From 2ddcc21ef113a3175d64417ba7996b72ef860346 Mon Sep 17 00:00:00 2001 From: "Simon J. Williams" Date: Tue, 20 Jan 2026 22:32:33 +0000 Subject: [PATCH 1/4] GitHub Actions --- .github/dependabot.yml | 21 ++++ .github/workflows/codeql.yml | 101 ++++++++++++++++++++ .github/workflows/dependabot-auto-merge.yml | 22 +++++ .github/workflows/secrets-check.yml | 23 +++++ 4 files changed, 167 insertions(+) create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/codeql.yml create mode 100644 .github/workflows/dependabot-auto-merge.yml create mode 100644 .github/workflows/secrets-check.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..c192d27 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,21 @@ +# .github/dependabot.yml +version: 2 +updates: + # Keep GitHub Actions up to date + - package-ecosystem: "github-actions" + directory: "/" # Location of workflow files + schedule: + interval: "weekly" + labels: + - "dependencies" + - "github-actions" + + # Keep NuGet dependencies up to date + - package-ecosystem: "nuget" + directory: "/" # Location of solution file + schedule: + interval: "weekly" + open-pull-requests-limit: 5 + labels: + - "dependencies" + - "nuget" diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000..ba6114c --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,101 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL Advanced" + +on: + push: + branches: [ "**" ] # run on any branch push + pull_request: + branches: [ "**" ] # run on any branch PR + schedule: + - cron: '43 2 * * 3' + +jobs: + analyze: + if: github.event_name != 'workflow_dispatch' || github.actor != 'nektos/act' + name: Analyze (${{ matrix.language }}) + # Runner size impacts CodeQL analysis time. To learn more, please see: + # - https://gh.io/recommended-hardware-resources-for-running-codeql + # - https://gh.io/supported-runners-and-hardware-resources + # - https://gh.io/using-larger-runners (GitHub.com only) + # Consider using larger runners or machines with greater resources for possible analysis time improvements. + runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }} + permissions: + # required for all workflows + security-events: write + + # required to fetch internal or private CodeQL packs + packages: read + + # only required for workflows in private repositories + actions: read + contents: read + + strategy: + fail-fast: false + matrix: + include: + - language: actions + build-mode: none + - language: csharp + build-mode: none + # CodeQL supports the following values keywords for 'language': 'actions', 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift' + # Use `c-cpp` to analyze code written in C, C++ or both + # Use 'java-kotlin' to analyze code written in Java, Kotlin or both + # Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both + # To learn more about changing the languages that are analyzed or customizing the build mode for your analysis, + # see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning. + # If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how + # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages + steps: + - name: Checkout repository + uses: actions/checkout@v5 + + # Add any setup steps before running the `github/codeql-action/init` action. + # This includes steps like installing compilers or runtimes (`actions/setup-node` + # or others). This is typically only required for manual builds. + # - name: Setup runtime (example) + # uses: actions/setup-example@v1 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v4 + with: + languages: ${{ matrix.language }} + build-mode: ${{ matrix.build-mode }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + + # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs + # queries: security-extended,security-and-quality + + # If the analyze step fails for one of the languages you are analyzing with + # "We were unable to automatically build your code", modify the matrix above + # to set the build mode to "manual" for that language. Then modify this step + # to build your code. + # ℹ️ Command-line programs to run using the OS shell. + # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun + - if: matrix.build-mode == 'manual' + shell: bash + run: | + echo 'If you are using a "manual" build mode for one or more of the' \ + 'languages you are analyzing, replace this with the commands to build' \ + 'your code, for example:' + echo ' make bootstrap' + echo ' make release' + exit 1 + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v4 + with: + category: "/language:${{matrix.language}}" diff --git a/.github/workflows/dependabot-auto-merge.yml b/.github/workflows/dependabot-auto-merge.yml new file mode 100644 index 0000000..4ac8a21 --- /dev/null +++ b/.github/workflows/dependabot-auto-merge.yml @@ -0,0 +1,22 @@ +# .github/workflows/dependabot-auto-merge.yml +name: Dependabot auto-merge + +on: + pull_request: + branches: [ "main" ] + +permissions: + pull-requests: write + contents: write + +jobs: + dependabot: + runs-on: ubuntu-latest + if: github.actor == 'dependabot[bot]' + steps: + - uses: actions/checkout@v5 + + - name: Auto-merge Dependabot PRs + uses: fastify/github-action-merge-dependabot@v3 + with: + target: minor diff --git a/.github/workflows/secrets-check.yml b/.github/workflows/secrets-check.yml new file mode 100644 index 0000000..7dec275 --- /dev/null +++ b/.github/workflows/secrets-check.yml @@ -0,0 +1,23 @@ +name: gitleaks +on: + pull_request: + push: + workflow_dispatch: + schedule: + - cron: "0 4 * * *" # run once a day at 4 AM + +permissions: + contents: read + +jobs: + scan: + name: gitleaks + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + with: + fetch-depth: 0 + - uses: gitleaks/gitleaks-action@v2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} +# GITLEAKS_LICENSE: ${{ secrets.GITLEAKS_LICENSE }} # Only required for Organizations, not personal accounts. From 933857175f95b05deac74862931c4146f929eb5d Mon Sep 17 00:00:00 2001 From: "Simon J. Williams" Date: Wed, 21 Jan 2026 22:49:30 +0000 Subject: [PATCH 2/4] GitHub Actions - build and release. --- .github/workflows/ci.yml | 37 ++++++++++++++++ .github/workflows/release.yml | 43 +++++++++++++++++++ .../Kajabity.Tools.Java.csproj | 7 +-- README.md | 13 +++--- 4 files changed, 92 insertions(+), 8 deletions(-) create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..0afa8a9 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,37 @@ + # .github/workflows/ci.yml + name: CI + + on: + push: + branches: [ "**" ] # run on any branch push + tags: [ "v*" ] # also run when a version tag is pushed + pull_request: + branches: [ "**" ] # run on any branch PR + + permissions: + contents: read + + jobs: + build: + name: Build & Test + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v5 + + - name: Setup .NET + uses: actions/setup-dotnet@v5 + with: + dotnet-version: 9.0 + + - name: Restore dependencies + run: dotnet restore + + - name: Build + run: dotnet build --configuration Release --no-restore + + - name: Run tests + run: dotnet test --no-build --configuration Release --verbosity normal + + - name: Check vulnerable packages + run: dotnet list package --vulnerable --include-transitive diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..86fa56c --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,43 @@ +name: Release + +on: + push: + tags: + - '[0-9]+.[0-9]+.[0-9]+*' + +permissions: + contents: write + packages: write + +jobs: + publish: + name: Publish Release & NuGet + runs-on: windows-latest # required for .NET Framework builds + + steps: + - uses: actions/checkout@v5 + + - name: Setup .NET + uses: actions/setup-dotnet@v5 + with: + dotnet-version: 9.0 + + - name: Restore dependencies + run: dotnet restore + + - name: Build (Release) + run: dotnet build --configuration Release --no-restore + + - name: Pack NuGet package + run: dotnet pack src/Kajabity.Tools.Java/Kajabity.Tools.Java.csproj --configuration Release --no-build -o ./artifacts + + - name: Publish to GitHub Packages + run: dotnet nuget push **/artifacts/*.nupkg --api-key ${{ secrets.GITHUB_TOKEN }} --source https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json --skip-duplicate + + - name: Publish to NuGet.org + run: dotnet nuget push **/artifacts/*.nupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate + + - name: Create GitHub Release + uses: softprops/action-gh-release@v2 + with: + files: artifacts/**/*.nupkg diff --git a/Kajabity.Tools.Java/Kajabity.Tools.Java.csproj b/Kajabity.Tools.Java/Kajabity.Tools.Java.csproj index 37668cb..96cc6c9 100644 --- a/Kajabity.Tools.Java/Kajabity.Tools.Java.csproj +++ b/Kajabity.Tools.Java/Kajabity.Tools.Java.csproj @@ -2,13 +2,14 @@ netstandard2.0;net47;net471;net472;net48;net481;net10.0 + Kajabity.Tools.Java $(AssemblyName) $(AssemblyTitle) - Williams Technologies Limited - Copyright © 2009-21 $(AssemblyCompany). - $(AssemblyCompany) + Kajabity + Copyright © 2009-2026 $(AssemblyCompany). + Simon J. Williams Classes to read and write Java style “.properties” files in .NET applications. diff --git a/README.md b/README.md index 0b03229..8b09663 100644 --- a/README.md +++ b/README.md @@ -3,18 +3,21 @@ Kajabity.Tools.Java GitHub Repository [![Build status](https://ci.appveyor.com/api/projects/status/98ovyr22uy57gkp3/branch/main?svg=true)](https://ci.appveyor.com/project/Kajabity/kajabity-tools-java/branch/main) -Kajabity.Tools.Java is a collection of utility classes to read and write Java style “.properties” files in .NET applications. +Kajabity.Tools.Java is a collection of utility classes to read and write Java style “.properties” +files in .NET applications. Originally part of the Kajabity Tools collection, these classes are now refactored into their own -separate repository to reduce unnecessary code bloat. In particular, it removes the Windows Forms dependencies. +separate repository to reduce unnecessary code bloat. In particular, it removes the Windows Forms +dependencies. This repository contains several sub-projects: -- **Kajabity.Tools.Java** - a DLL project providing the JavaProperties classes for .NET projects. -- **Kajabity.Tools.Java.Test** - NUnit tests for the Kajabity.Tools.Java classes. +- **Kajabity.Tools.Java** - a DLL project providing the JavaProperties classes for .NET projects. +- **Kajabity.Tools.Java.Test** - NUnit tests for the Kajabity.Tools.Java classes. See the Releases section on GitHub to download copies of code, DLL exe's and NuGets. -Kajabity.Tools.Java DLL is a strongly named assembly and is available from nuget.org as Kajabity.Tools.Java. +Kajabity.Tools.Java DLL is a strongly named assembly and is available from nuget.org as +Kajabity.Tools.Java. Full documentation is available at [http://www.kajabity.com/kajabity-tools/](http://www.kajabity.com/kajabity-tools/). From 18493de3121ee9205531a290fa50b3b017a922ec Mon Sep 17 00:00:00 2001 From: "Simon J. Williams" Date: Fri, 23 Jan 2026 21:46:07 +0000 Subject: [PATCH 3/4] Updates to README.md and package build. --- .../Java/JavaPropertyWriterTest.cs | 2 +- .../Java/DuplicateKeyResolution.cs | 2 +- Kajabity.Tools.Java/Java/JavaProperties.cs | 2 +- .../Java/JavaPropertyReader.cs | 46 ++-- .../Kajabity.Tools.Java.csproj | 51 ++--- Kajabity.Tools.Java/README.md | 16 -- Kajabity.Tools.Java/license.rtf | 200 ----------------- LICENSE.txt | 201 ++++++++++++++++++ README.md | 46 +++- appveyor.yml | 113 ---------- kajabity.tools.java.logo.png | Bin 0 -> 10372 bytes 11 files changed, 278 insertions(+), 401 deletions(-) delete mode 100644 Kajabity.Tools.Java/README.md delete mode 100644 Kajabity.Tools.Java/license.rtf create mode 100644 LICENSE.txt delete mode 100644 appveyor.yml create mode 100644 kajabity.tools.java.logo.png diff --git a/Kajabity.Tools.Java.Test/Java/JavaPropertyWriterTest.cs b/Kajabity.Tools.Java.Test/Java/JavaPropertyWriterTest.cs index f82c455..d28fc02 100644 --- a/Kajabity.Tools.Java.Test/Java/JavaPropertyWriterTest.cs +++ b/Kajabity.Tools.Java.Test/Java/JavaPropertyWriterTest.cs @@ -27,7 +27,7 @@ namespace Kajabity.Tools.Java { /// /// The following tests are validated by converting to equivalent JUnit tests - for example: - /// + /// ///
     ///    @Test
     ///    public void test() throws IOException
diff --git a/Kajabity.Tools.Java/Java/DuplicateKeyResolution.cs b/Kajabity.Tools.Java/Java/DuplicateKeyResolution.cs
index 4098d57..cec6cd4 100644
--- a/Kajabity.Tools.Java/Java/DuplicateKeyResolution.cs
+++ b/Kajabity.Tools.Java/Java/DuplicateKeyResolution.cs
@@ -27,7 +27,7 @@ public enum DuplicateKeyResolution
     {
         /// 
         /// Overwrite the key with a new value.
-        /// 
+        ///
         /// Last one wins.
         /// 
         Overwrite = 1,
diff --git a/Kajabity.Tools.Java/Java/JavaProperties.cs b/Kajabity.Tools.Java/Java/JavaProperties.cs
index 8511a62..65b3a61 100644
--- a/Kajabity.Tools.Java/Java/JavaProperties.cs
+++ b/Kajabity.Tools.Java/Java/JavaProperties.cs
@@ -67,7 +67,7 @@ public JavaProperties(Dictionary defaults)
         }
 
         /// 
-        /// Load Java Properties from a stream with the specified encoding and 
+        /// Load Java Properties from a stream with the specified encoding and
         /// expecting the format as described in .
         /// 
         /// An input stream to read properties from.
diff --git a/Kajabity.Tools.Java/Java/JavaPropertyReader.cs b/Kajabity.Tools.Java/Java/JavaPropertyReader.cs
index 239f417..c0e3d90 100644
--- a/Kajabity.Tools.Java/Java/JavaPropertyReader.cs
+++ b/Kajabity.Tools.Java/Java/JavaPropertyReader.cs
@@ -25,7 +25,7 @@
 namespace Kajabity.Tools.Java
 {
     /// 
-    /// This class reads Java style properties from an input stream.  
+    /// This class reads Java style properties from an input stream.
     /// 
     public class JavaPropertyReader
     {
@@ -152,29 +152,29 @@ public JavaPropertyReader(Dictionary hashtable)
         {
             this.hashtable = hashtable;
         }
-        
+
         /// 
-        /// Load key value pairs (properties) from an input Stream.  
-        /// The input stream (usually reading from a ".properties" file) consists of a series of lines (terminated 
+        /// Load key value pairs (properties) from an input Stream.
+        /// The input stream (usually reading from a ".properties" file) consists of a series of lines (terminated
         /// by \r, \n or \r\n) each a key value pair, a comment or a blank line.
-        /// 
-        /// Leading whitespace (spaces, tabs, formfeeds) are ignored at the start of any line - and a line that is empty or 
+        ///
+        /// Leading whitespace (spaces, tabs, formfeeds) are ignored at the start of any line - and a line that is empty or
         /// contains only whitespace is blank and ignored.
-        /// 
-        /// A line with the first non-whitespace character is a '#' or '!' is a comment line and the rest of the line is 
+        ///
+        /// A line with the first non-whitespace character is a '#' or '!' is a comment line and the rest of the line is
         /// ignored.
-        /// 
+        ///
         /// If the first non-whitespace character is not '#' or '!' then it is the start of a key.  A key is all the
         /// characters up to the first whitespace or a key/value separator - '=' or ':'.
-        /// 
+        ///
         /// The separator is optional.  Any whitespace after the key or after the separator (if present) is ignored.
-        /// 
-        /// The first non-whitespace character after the separator (or after the key if no separator) begins the value.  
+        ///
+        /// The first non-whitespace character after the separator (or after the key if no separator) begins the value.
         /// The value may include whitespace, separators, or comment characters.
-        /// 
-        /// Any unicode character may be included in either key or value by using escapes preceded by the escape 
+        ///
+        /// Any unicode character may be included in either key or value by using escapes preceded by the escape
         /// character '\'.
-        /// 
+        ///
         /// The following special cases are defined:
         /// 
         /// 	'\t' - horizontal tab.
@@ -182,20 +182,20 @@ public JavaPropertyReader(Dictionary hashtable)
         /// 	'\r' - return
         /// 	'\n' - new line
         /// 	'\\' - add escape character.
-        /// 
+        ///
         /// 	'\ ' - add space in a key or at the start of a value.
         /// 	'\!', '\#' - add comment markers at the start of a key.
         /// 	'\=', '\:' - add a separator in a key.
         /// 
-        /// 
+        ///
         /// Any unicode character using the following escape:
         /// 
         /// 	'\uXXXX' - where XXXX represents the unicode character code as 4 hexadecimal digits.
         /// 
-        /// 
+        ///
         /// Finally, longer lines can be broken by putting an escape at the very end of the line.  Any leading space
         /// (unless escaped) is skipped at the beginning of the following line.
-        /// 
+        ///
         /// Examples
         /// 
         /// 	a-key = a-value
@@ -203,24 +203,24 @@ public JavaPropertyReader(Dictionary hashtable)
         /// 	a-key=a-value
         /// 	a-key a-value
         /// 
-        /// 
+        ///
         /// All the above will result in the same key/value pair - key "a-key" and value "a-value".
         /// 
         /// 	! comment...
         /// 	# another comment...
         /// 
-        /// 
+        ///
         /// The above are two examples of comments.
         /// 
         /// 	Honk\ Kong = Near China
         /// 
-        /// 
+        ///
         /// The above shows how to embed a space in a key - key is "Hong Kong", value is "Near China".
         /// 
         /// 	a-longer-key-example = a really long value that is \
         /// 			split over two lines.
         /// 
-        /// 
+        ///
         /// An example of a long line split into two.
         /// 
         /// The input stream that the properties are read from.
diff --git a/Kajabity.Tools.Java/Kajabity.Tools.Java.csproj b/Kajabity.Tools.Java/Kajabity.Tools.Java.csproj
index 96cc6c9..eb832af 100644
--- a/Kajabity.Tools.Java/Kajabity.Tools.Java.csproj
+++ b/Kajabity.Tools.Java/Kajabity.Tools.Java.csproj
@@ -4,57 +4,32 @@
     netstandard2.0;net47;net471;net472;net48;net481;net10.0
 
     
-    Kajabity.Tools.Java
-    $(AssemblyName)
-    $(AssemblyTitle)
-    Kajabity
+    Kajabity
     Copyright © 2009-2026 $(AssemblyCompany).
     Simon J. Williams
     Classes to read and write Java style “.properties” files in .NET applications.
 
-    
-    $([System.DateTime]::op_Subtraction($([System.DateTime]::get_Now().get_Date()),$([System.DateTime]::new(2000,1,1))).get_TotalDays())
-    $([MSBuild]::Divide($([System.DateTime]::get_Now().get_TimeOfDay().get_TotalSeconds()), 2).ToString('F0'))
-    0.3.$(Build).$(Revision)
-    $(Version)
-    $(Version)
-    $(Version)
-
     
-    http://www.apache.org/licenses/LICENSE-2.0
+    LICENSE.txt
     http://kajabity.com/kajabity-tools/java-properties-classes/
-    http://kajabity.com/images/logo-57x57.png
-    $(PackageIconUri)
+    kajabity.tools.java.logo.png
     Java Properties
-    $(Version)
     https://github.com/Kajabity/Kajabity.Tools.Java
+    git
+    true
+    README.md
   
 
   
-    Debug
-    AnyCPU
-    
-    false
-    {4CF13660-95BA-482C-BA3E-BF97B9624F19}
-    Library
-    Properties
-    Kajabity.Tools
-    en-US
-    
-  
-
-  
-    true
-    full
-    false
-    DEBUG;TRACE;$(FrameworkSymbols)
+    true
+    snupkg
   
 
-  
-    pdbonly
-    true
-    TRACE;$(FrameworkSymbols)
-  
+  
+    
+    
+    
+  
 
   
     true
diff --git a/Kajabity.Tools.Java/README.md b/Kajabity.Tools.Java/README.md
deleted file mode 100644
index 9d3aa1d..0000000
--- a/Kajabity.Tools.Java/README.md
+++ /dev/null
@@ -1,16 +0,0 @@
-Kajabity.Tools.Java
-===================
-
-This directory contains the Kajabity.Tools.Java DLL project and it produces 
-a Strongly Named DLL which is packaged as a NuGet.
-
-Kajabity.Tools.Java is available in several forms:
-
--	As a project which you can clone or fork from GitHub and include into your own Visual Studio solutions.
--	Copy some or all the source files/code into your own projects.
--	Download the sources or NuGet packages from [GitHub Releases](https://github.com/Kajabity/Kajabity.Tools.Java/releases).
--	Add the NuGet component to your project from [nuget.org](https://www.nuget.org/packages/Kajabity.Tools.Java/).
-
-Developed using Microsoft Visual Studio 2019.
-
-Full documentation is available at [http://www.kajabity.com/kajabity-tools/](http://www.kajabity.com/kajabity-tools/).
diff --git a/Kajabity.Tools.Java/license.rtf b/Kajabity.Tools.Java/license.rtf
deleted file mode 100644
index 52a2f86..0000000
--- a/Kajabity.Tools.Java/license.rtf
+++ /dev/null
@@ -1,200 +0,0 @@
-{\rtf1\adeflang1025\ansi\ansicpg1252\uc1\adeff0\deff0\stshfdbch0\stshfloch0\stshfhich0\stshfbi0\deflang2057\deflangfe2057{\fonttbl{\f0\froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f1\fswiss\fcharset0\fprq2{\*\panose 020b0604020202020204}Arial;}{\f37\froman\fcharset238\fprq2 Times New Roman CE;}
-{\f38\froman\fcharset204\fprq2 Times New Roman Cyr;}{\f40\froman\fcharset161\fprq2 Times New Roman Greek;}{\f41\froman\fcharset162\fprq2 Times New Roman Tur;}{\f42\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}
-{\f43\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\f44\froman\fcharset186\fprq2 Times New Roman Baltic;}{\f45\froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\f47\fswiss\fcharset238\fprq2 Arial CE;}
-{\f48\fswiss\fcharset204\fprq2 Arial Cyr;}{\f50\fswiss\fcharset161\fprq2 Arial Greek;}{\f51\fswiss\fcharset162\fprq2 Arial Tur;}{\f52\fbidi \fswiss\fcharset177\fprq2 Arial (Hebrew);}{\f53\fbidi \fswiss\fcharset178\fprq2 Arial (Arabic);}
-{\f54\fswiss\fcharset186\fprq2 Arial Baltic;}{\f55\fswiss\fcharset163\fprq2 Arial (Vietnamese);}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0;
-\red255\green255\blue0;\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;\red192\green192\blue192;}{\stylesheet{
-\ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 \fs24\lang2057\langfe2057\cgrid\langnp2057\langfenp2057 \snext0 Normal;}{\*\cs10 \additive \ssemihidden 
-Default Paragraph Font;}{\*\ts11\tsrowd\trftsWidthB3\trpaddl108\trpaddr108\trpaddfl3\trpaddft3\trpaddfb3\trpaddfr3\trcbpat1\trcfpat1\tblind0\tblindtype3\tscellwidthfts0\tsvertalt\tsbrdrt\tsbrdrl\tsbrdrb\tsbrdrr\tsbrdrdgl\tsbrdrdgr\tsbrdrh\tsbrdrv 
-\ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20 \ltrch\fcs0 \fs20\lang1024\langfe1024\cgrid\langnp1024\langfenp1024 \snext11 \ssemihidden Normal Table;}}
-{\*\latentstyles\lsdstimax156\lsdlockeddef0}{\*\rsidtbl \rsid6122943}{\*\generator Microsoft Word 11.0.0000;}{\info{\operator Simon J. Williams}{\creatim\yr2009\mo12\dy1\hr23\min9}{\revtim\yr2009\mo12\dy1\hr23\min10}{\version2}{\edmins1}{\nofpages4}
-{\nofwords1540}{\nofchars8780}{\nofcharsws10300}{\vern24615}{\*\password 00000000}}{\*\xmlnstbl {\xmlns1 http://schemas.microsoft.com/office/word/2003/wordml}}\paperw12240\paperh15840\margl1800\margr1800\margt1440\margb1440\gutter0\ltrsect 
-\widowctrl\ftnbj\aenddoc\donotembedsysfont0\donotembedlingdata1\grfdocevents0\validatexml0\showplaceholdtext0\ignoremixedcontent0\saveinvalidxml0\showxmlerrors0\horzdoc\dghspace120\dgvspace120\dghorigin1701\dgvorigin1984\dghshow0\dgvshow3
-\jcompress\viewkind4\viewscale100\rsidroot6122943 \fet0{\*\wgrffmtfilter 013f}\ilfomacatclnup0\ltrpar \sectd \ltrsect\linex0\sectdefaultcl\sftnbj {\*\pnseclvl1\pnucrm\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl2
-\pnucltr\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl3\pndec\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl4\pnlcltr\pnstart1\pnindent720\pnhang {\pntxta )}}{\*\pnseclvl5\pndec\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl6
-\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl7\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl8\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl9\pnlcrm\pnstart1\pnindent720\pnhang 
-{\pntxtb (}{\pntxta )}}\pard\plain \ltrpar\ql \li0\ri0\nowidctlpar\wrapdefault\faauto\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs24\alang1025 \ltrch\fcs0 \fs24\lang2057\langfe2057\cgrid\langnp2057\langfenp2057 {\rtlch\fcs1 \af1\afs20 \ltrch\fcs0 
-\f1\fs20\cf1\insrsid6122943 Copyright (c) 2009, Williams Technologies Limited.
-\par 
-\par Kajabity }{\rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f1\fs20\cf1\insrsid6122943 Tools}{\rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f1\fs20\cf1\insrsid6122943  is released under the Apache License Version 2.0 
-\par which is reproduced below.
-\par 
-\par 
-\par                                  Apache License
-\par                            Version 2.0, January 2004
-\par                         }{\rtlch\fcs1 \ab\af1\afs20 \ltrch\fcs0 \b\f1\fs20\cf1\insrsid6122943 http://www.apache.org/licenses/
-\par }{\rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f1\fs20\cf1\insrsid6122943 
-\par    TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-\par 
-\par    }{\rtlch\fcs1 \ab\af1\afs20 \ltrch\fcs0 \b\f1\fs20\cf1\insrsid6122943 1. Definitions}{\rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f1\fs20\cf1\insrsid6122943 .}{\rtlch\fcs1 \ab\af1\afs20 \ltrch\fcs0 \b\f1\fs20\cf1\insrsid6122943 
-\par }{\rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f1\fs20\cf1\insrsid6122943 
-\par       "License" shall mean the terms and conditions for use, reproduction,
-\par       and distribution as defined by Sections 1 through 9 of this document.
-\par 
-\par       "Licensor" shall mean the copyright owner or entity authorized by
-\par       the copyright owner that is granting the License.
-\par 
-\par       "Legal Entity" shall mean the union of the acting entity and all
-\par       other entities that control, are controlled by, or are under common
-\par       control with that entity. For the purposes of this definition,
-\par       "control" means (i) the power, direct or indirect, to cause the
-\par       direction or management of such entity, whether by contract or
-\par       otherwise, or (ii) ownership of fifty percent (50%) or more of the
-\par       outstanding shares, or (iii) beneficial ownership of such entity.
-\par 
-\par       "You" (or "Your") shall mean an individual or Legal Entity
-\par       exercising permissions granted by this License.
-\par 
-\par       "Source" form shall mean the preferred form for making modifications,
-\par       including but not limited to software source code, documentation
-\par       source, and configuration files.
-\par 
-\par       "Object" form shall mean any form resulting from mechanical
-\par       transformation or translation of a Source form, including but
-\par       not limited to compiled object code, generated documentation,
-\par       and conversions to other media types.
-\par 
-\par       "Work" shall mean the work of authorship, whether in Source or
-\par       Object form, made available under the License, as indicated by a
-\par       copyright notice that is included in or attached to the work
-\par       (an example is provided in the Appendix below).
-\par 
-\par       "Derivative Works" shall mean any work, whether in Source or Object
-\par       form, that is based on (or derived from) the Work and for which the
-\par       editorial revisions, annotations, elaborations, or other modifications
-\par       represent, as a whole, an original work of authorship. For the purposes
-\par       of this License, Derivative Works shall not include works that remain
-\par       separable from, or merely link (or bind by name) to the interfaces of,
-\par       the Work and Derivative Works thereof.
-\par 
-\par       "Contribution" shall mean any work of authorship, including
-\par       the original version of the Work and any modifications or additions
-\par       to that Work or Derivative Works thereof, that is intentionally
-\par       submitted to Licensor for inclusion in the Work by the copyright owner
-\par       or by an individual or Legal Entity authorized to submit on behalf of
-\par       the copyright owner. For the purposes of this definition, "submitted"
-\par       means any form of electronic, verbal, or written communication sent
-\par       to the Licensor or its representatives, including but not limited to
-\par       communication on electronic mailing lists, source code control systems,
-\par       and issue tracking systems that are managed by, or on behalf of, the
-\par       Licensor for the purpose of discussing and improving the Work, but
-\par       excluding communication that is conspicuously marked or otherwise
-\par       designated in writing by the copyright owner as "Not a Contribution."
-\par 
-\par       "Contributor" shall mean Licensor and any individual or Legal Entity
-\par       on behalf of whom a Contribution has been received by Licensor and
-\par       subsequently incorporated within the Work.
-\par 
-\par    }{\rtlch\fcs1 \ab\af1\afs20 \ltrch\fcs0 \b\f1\fs20\cf1\insrsid6122943 2. Grant of Copyright License}{\rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f1\fs20\cf1\insrsid6122943 . Subject to the terms and conditions of
-\par       this License, each Contributor hereby grants to You a perpetual,
-\par       worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-\par       copyright license to reproduce, prepare Derivative Works of,
-\par       publicly display, publicly perform, sublicense, and distribute the
-\par       Work and such Derivative Works in Source or Object form.
-\par 
-\par    }{\rtlch\fcs1 \ab\af1\afs20 \ltrch\fcs0 \b\f1\fs20\cf1\insrsid6122943 3. Grant of Patent License}{\rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f1\fs20\cf1\insrsid6122943 . Subject to the terms and conditions of
-\par       this License, each Contributor hereby grants to You a perpetual,
-\par       worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-\par       (except as stated in this section) patent license to make, have made,
-\par       use, offer to sell, sell, import, and otherwise transfer the Work,
-\par       where such license applies only to those patent claims licensable
-\par       by such Contributor that are necessarily infringed by their
-\par       Contribution(s) alone or by combination of their Contribution(s)
-\par       with the Work to which such Contribution(s) was submitted. If You
-\par       institute patent litigation against any entity (including a
-\par       cross-claim or counterclaim in a lawsuit) alleging that the Work
-\par       or a Contribution incorporated within the Work constitutes direct
-\par       or contributory patent infringement, then any patent licenses
-\par       granted to You under this License for that Work shall terminate
-\par       as of the date such litigation is filed.
-\par 
-\par    }{\rtlch\fcs1 \ab\af1\afs20 \ltrch\fcs0 \b\f1\fs20\cf1\insrsid6122943 4. Redistribution}{\rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f1\fs20\cf1\insrsid6122943 . You may reproduce and distribute copies of the
-\par       Work or Derivative Works thereof in any medium, with or without
-\par       modifications, and in Source or Object form, provided that You
-\par       meet the following conditions:
-\par 
-\par       (a) You must give any other recipients of the Work or
-\par           Derivative Works a copy of this License; and
-\par 
-\par       (b) You must cause any modified files to carry prominent notices
-\par           stating that You changed the files; and
-\par 
-\par       (c) You must retain, in the Source form of any Derivative Works
-\par           that You distribute, all copyright, patent, trademark, and
-\par           attribution notices from the Source form of the Work,
-\par           excluding those notices that do not pertain to any part of
-\par           the Derivative Works; and
-\par 
-\par       (d) If the Work includes a "NOTICE" text file as part of its
-\par           distribution, then any Derivative Works that You distribute must
-\par           include a readable copy of the attribution notices contained
-\par           within such NOTICE file, excluding those notices that do not
-\par           pertain to any part of the Derivative Works, in at least one
-\par           of the following places: within a NOTICE text file distributed
-\par           as part of the Derivative Works; within the Source form or
-\par           documentation, if provided along with the Derivative Works; or,
-\par           within a display generated by the Derivative Works, if and
-\par           wherever such third-party notices normally appear. The contents
-\par           of the NOTICE file are for informational purposes only and
-\par           do not modify the License. You may add Your own attribution
-\par           notices within Derivative Works that You distribute, alongside
-\par           or as an addendum to the NOTICE text from the Work, provided
-\par           that such additional attribution notices cannot be construed
-\par           as modifying the License.
-\par 
-\par       You may add Your own copyright statement to Your modifications and
-\par       may provide additional or different license terms and conditions
-\par       for use, reproduction, or distribution of Your modifications, or
-\par       for any such Derivative Works as a whole, provided Your use,
-\par       reproduction, and distribution of the Work otherwise complies with
-\par       the conditions stated in this License.
-\par 
-\par    }{\rtlch\fcs1 \ab\af1\afs20 \ltrch\fcs0 \b\f1\fs20\cf1\insrsid6122943 5. Submission of Contributions}{\rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f1\fs20\cf1\insrsid6122943 . Unless You explicitly state otherwise,
-\par       any Contribution intentionally submitted for inclusion in the Work
-\par       by You to the Licensor shall be under the terms and conditions of
-\par       this License, without any additional terms or conditions.
-\par       Notwithstanding the above, nothing herein shall supersede or modify
-\par       the terms of any separate license agreement you may have executed
-\par       with Licensor regarding such Contributions.
-\par 
-\par    }{\rtlch\fcs1 \ab\af1\afs20 \ltrch\fcs0 \b\f1\fs20\cf1\insrsid6122943 6. Trademarks}{\rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f1\fs20\cf1\insrsid6122943 . This License does not grant permission to use the trade
-\par       names, trademarks, service marks, or product names of the Licensor,
-\par       except as required for reasonable and customary use in describing the
-\par       origin of the Work and reproducing the content of the NOTICE file.
-\par 
-\par    }{\rtlch\fcs1 \ab\af1\afs20 \ltrch\fcs0 \b\f1\fs20\cf1\insrsid6122943 7. Disclaimer of Warranty}{\rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f1\fs20\cf1\insrsid6122943 . Unless required by applicable law or
-\par       agreed to in writing, Licensor provides the Work (and each
-\par       Contributor provides its Contributions) on an "AS IS" BASIS,
-\par       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-\par       implied, including, without limitation, any warranties or conditions
-\par       of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-\par       PARTICULAR PURPOSE. You are solely responsible for determining the
-\par       appropriateness of using or redistributing the Work and assume any
-\par       risks associated with Your exercise of permissions under this License.
-\par 
-\par    }{\rtlch\fcs1 \ab\af1\afs20 \ltrch\fcs0 \b\f1\fs20\cf1\insrsid6122943 8. Limitation of Liability}{\rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f1\fs20\cf1\insrsid6122943 . In no event and under no legal theory,
-\par       whether in tort (including negligence), contract, or otherwise,
-\par       unless required by applicable law (such as deliberate and grossly
-\par       negligent acts) or agreed to in writing, shall any Contributor be
-\par       liable to You for damages, including any direct, indirect, special,
-\par       incidental, or consequential damages of any character arising as a
-\par       result of this License or out of the use or inability to use the
-\par       Work (including but not limited to damages for loss of goodwill,
-\par       work stoppage, computer failure or malfunction, or any and all
-\par       other commercial damages or losses), even if such Contributor
-\par       has been advised of the possibility of such damages.
-\par 
-\par    }{\rtlch\fcs1 \ab\af1\afs20 \ltrch\fcs0 \b\f1\fs20\cf1\insrsid6122943 9. Accepting Warranty or Additional Liability}{\rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f1\fs20\cf1\insrsid6122943 . While redistributing
-\par       the Work or Derivative Works thereof, You may choose to offer,
-\par       and charge a fee for, acceptance of support, warranty, indemnity,
-\par       or other liability obligations and/or rights consistent with this
-\par       License. However, in accepting such obligations, You may act only
-\par       on Your own behalf and on Your sole responsibility, not on behalf
-\par       of any other Contributor, and only if You agree to indemnify,
-\par       defend, and hold each Contributor harmless for any liability
-\par       incurred by, or claims asserted against, such Contributor by reason
-\par       of your accepting any such warranty or additional liability.
-\par 
-\par    END OF TERMS AND CONDITIONS
-\par 
-\par }}
\ No newline at end of file
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 0000000..261eeb9
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/README.md b/README.md
index 8b09663..899d820 100644
--- a/README.md
+++ b/README.md
@@ -1,15 +1,19 @@
-Kajabity.Tools.Java GitHub Repository
-====================================
+Kajabity.Tools.Java - Java Properties Utilities
+===============================================
 
-[![Build status](https://ci.appveyor.com/api/projects/status/98ovyr22uy57gkp3/branch/main?svg=true)](https://ci.appveyor.com/project/Kajabity/kajabity-tools-java/branch/main)
+[![CI](https://github.com/kajabity/Kajabity.Tools.Java/actions/workflows/ci.yml/badge.svg)](https://github.com/kajabity/Kajabity.Tools.Java/actions/workflows/ci.yml)
+[![CodeQL](https://github.com/kajabity/Kajabity.Tools.Java/actions/workflows/codeql.yml/badge.svg)](https://github.com/kajabity/Kajabity.Tools.Java/actions/workflows/codeql.yml)
+[![NuGet](https://img.shields.io/nuget/v/Kajabity.Tools.Java.svg)](https://www.nuget.org/packages/Kajabity.Tools.Java/)
+[![NuGet Downloads](https://img.shields.io/nuget/dt/Kajabity.Tools.Java.svg)](https://www.nuget.org/packages/Kajabity.Tools.Java/)
+[![GitHub Release](https://img.shields.io/github/v/release/kajabity/Kajabity.Tools.Java.svg)](https://github.com/kajabity/Kajabity.Tools.Java/releases)
+[![License: Apache 2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE.txt)
+
+Overview
+--------
 
 Kajabity.Tools.Java is a collection of utility classes to read and write Java style “.properties”
 files in .NET applications.
 
-Originally part of the Kajabity Tools collection, these classes are now refactored into their own
-separate repository to reduce unnecessary code bloat.  In particular, it removes the Windows Forms
-dependencies.
-
 This repository contains several sub-projects:
 
 - **Kajabity.Tools.Java** - a DLL project providing the JavaProperties classes for .NET projects.
@@ -20,4 +24,30 @@ See the Releases section on GitHub to download copies of code, DLL exe's and NuG
 Kajabity.Tools.Java DLL is a strongly named assembly and is available from nuget.org as
 Kajabity.Tools.Java.
 
-Full documentation is available at [http://www.kajabity.com/kajabity-tools/](http://www.kajabity.com/kajabity-tools/).
+Features
+--------
+
+The JavaProperties class wraps a Dictionary class to provide the following additional features:
+
+- Load Java properties from a Stream into the Dictionary
+- Load Java properties from a Stream with an alternate (e.g. Unicode) encoding – easier to support languages in alternate character sets.
+- Store Java properties to a Stream from the Dictionary.
+- Support default properties (as with Java Properties class) using the 2nd constructor which provides a Dictionary of defaults.
+- Coerce the property keys and values to strings (as they are for Java properties).
+
+Usage
+-----
+
+Full documentation is available at [https://www.kajabity.com/kajabity-tools/java-properties-classes/](https://www.kajabity.com/kajabity-tools/java-properties-classes/).
+
+Releases
+--------
+
+- **Latest GitHub Release:** [View on GitHub](https://github.com/kajabity/Kajabity.Tools.Java/releases/latest)
+- **Latest NuGet Package:** [View on NuGet.org](https://www.nuget.org/packages/Kajabity.Tools.Java/)
+
+Feedback & Contributions
+-------------------------
+
+Contributions and feedback are welcome if you notice anything that could be improved.
+
diff --git a/appveyor.yml b/appveyor.yml
deleted file mode 100644
index b595091..0000000
--- a/appveyor.yml
+++ /dev/null
@@ -1,113 +0,0 @@
-##
-## Copyright 2009-20 Williams Technologies Limited.
-##
-## Licensed under the Apache License, Version 2.0 (the "License");
-## you may not use this file except in compliance with the License.
-## You may obtain a copy of the License at
-##
-##     http://www.apache.org/licenses/LICENSE-2.0
-##
-## Unless required by applicable law or agreed to in writing, software
-## distributed under the License is distributed on an "AS IS" BASIS,
-## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-## See the License for the specific language governing permissions and
-## limitations under the License.
-##
-## Kajabity is a trademark of Williams Technologies Limited.
-##
-## http://www.kajabity.com
-##
-
-#---------------------------------# 
-#      general configuration      # 
-#---------------------------------# 
-
-# tell appveyor to use MSBuild 15.0 or higher
-# eventually move to Visual Studio 2026 when available
-image: Visual Studio 2022
- 
-# version format 
-version: 0.3-{build}
-
-# branches to build
-#branches
-
- 
-# Do not build on tags (GitHub only)
-# This avoids the infinite build loop as Deploy to GitHub is set to create a tag each time.
-skip_tags: true 
-
-#---------------------------------# 
-#    environment configuration    # 
-#---------------------------------# 
- 
-# scripts that are called at very beginning, before repo cloning 
-init:
-- git config --global core.autocrlf true
-
-# Automatically register private account and/or project AppVeyor NuGet feeds.
-nuget:
-    account_feed: false
-    project_feed: true
-    disable_publish_on_pr: true     # disable publishing of .nupkg artifacts to
-                                    # account/project feeds for pull request builds
-
-#---------------------------------# 
-#       build configuration       # 
-#---------------------------------# 
- 
-# build platform, i.e. x86, x64, Any CPU. This setting is optional. 
-# platform:
-
-# build Configuration, i.e. Debug, Release, etc.
-before_build:
-    - cmd: dotnet restore "Kajabity.Tools.Java.sln"
-
-# build Configuration, i.e. Debug, Release, etc.
-configuration: Release
-
-build:
-    publish_nuget: true             # package projects with .nuspec files and push to artifacts 
-    publish_nuget_symbols: true     # generate and publish NuGet symbol packages 
-    include_nuget_references: true  # add -IncludeReferencedProjects option while packaging NuGet artifacts 
- 
-# MSBuild verbosity level - one of quiet|minimal|normal|detailed
-    verbosity: normal
-
-#---------------------------------# 
-#      artifacts configuration    # 
-#---------------------------------# 
-
-# Artifacts picked up by nuget deployment and includes all DLL variants for each .NET version.
-#artifacts:
-#    - path: Kajabity.Tools.Java\bin\$(configuration)\Kajabity.Tools.Java.dll
-
-#---------------------------------# 
-#     deployment configuration    # 
-#---------------------------------# 
-
-# providers: Local, FTP, WebDeploy, AzureCS, AzureBlob, S3, NuGet, Environment 
-# provider names are case-sensitive! 
-
-deploy:
-    # Secure tokens created using https://ci.appveyor.com/tools/encrypt
-
-    # Deploying to NuGet feed - using API Key from NuGet.org.
-  - provider: NuGet
-    api_key:
-        secure: ZoR+8IeDz9PXvLWhZoEtPdLjyv7zXoyejU3XTmGZeFrOsJ3QgfVrisQeEdfC2mYF
-    skip_symbols: true
-    artifact: /.*\.nupkg/
-    on:
-        #appveyor_repo_tag: true        # deploy on tag push only - removed or won't deploy at all.
-        branch: main                    # release from main branch only
-
-    # Deploy to GitHub Releases 
-  - provider: GitHub 
-    release: kajabity.tools.java-v$(appveyor_build_version)
-    description: 'Kajabity.Tools.Java Release v$(appveyor_build_version)'
-    auth_token:
-        secure: VRw5uPJq7zs0KwEF2hR8c9aSn5ZzA/SzJq4wNCR7fdYwMRrbwg+9sZDkAD30fsOY
-    draft: false
-    prerelease: false
-    #appveyor_repo_tag: true        # deploy on tag push only
diff --git a/kajabity.tools.java.logo.png b/kajabity.tools.java.logo.png
new file mode 100644
index 0000000000000000000000000000000000000000..72493db30da4b306a74f5b93a24507a3ad96de62
GIT binary patch
literal 10372
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
Date: Fri, 23 Jan 2026 23:22:00 +0000
Subject: [PATCH 4/4] Updates to README.md and package build.

---
 Kajabity.Tools.Java.sln                       |   9 ++--
 README.md                                     |  45 ++++++++++--------
 .../Java/DuplicateKeyResolution.cs            |   0
 .../Java/JavaProperties.cs                    |   0
 .../Java/JavaPropertyReader.cs                |   0
 .../Java/JavaPropertyWriter.cs                |   0
 .../Java/ParseException.cs                    |   0
 .../Kajabity.Tools.Java.csproj                |  26 +++++++---
 .../Kajabity.Tools.Java.snk                   | Bin
 .../Kajabity.Tools.Java}/NOTICE.txt           |   0
 .../Java/JavaPropertyReaderTest.cs            |   0
 .../Java/JavaPropertyWriterTest.cs            |   0
 .../Kajabity.Tools.Java.Test.csproj           |   2 +-
 .../Test Data/Java/blank.properties           |   0
 .../Test Data/Java/comments.properties        |   0
 .../Test Data/Java/duplicate.properties       |   0
 .../Test Data/Java/empty.properties           |   0
 .../Java/line-break-unicode.properties        |   0
 .../Test Data/Java/line-breaks.properties     |   0
 .../non-ascii-symbols-native2ascii.properties |   0
 .../Java/non-ascii-symbols-utf8.properties    |   0
 .../Test Data/Java/separators.properties      |   0
 .../Java/special-characters.properties        |   0
 .../Test Data/Java/urls.properties            |   0
 .../Test Data/Java/utf8-with-BOM.properties   |   0
 25 files changed, 50 insertions(+), 32 deletions(-)
 rename {Kajabity.Tools.Java => src/Kajabity.Tools.Java}/Java/DuplicateKeyResolution.cs (100%)
 rename {Kajabity.Tools.Java => src/Kajabity.Tools.Java}/Java/JavaProperties.cs (100%)
 rename {Kajabity.Tools.Java => src/Kajabity.Tools.Java}/Java/JavaPropertyReader.cs (100%)
 rename {Kajabity.Tools.Java => src/Kajabity.Tools.Java}/Java/JavaPropertyWriter.cs (100%)
 rename {Kajabity.Tools.Java => src/Kajabity.Tools.Java}/Java/ParseException.cs (100%)
 rename {Kajabity.Tools.Java => src/Kajabity.Tools.Java}/Kajabity.Tools.Java.csproj (57%)
 rename {Kajabity.Tools.Java => src/Kajabity.Tools.Java}/Kajabity.Tools.Java.snk (100%)
 rename {Kajabity.Tools.Java => src/Kajabity.Tools.Java}/NOTICE.txt (100%)
 rename {Kajabity.Tools.Java.Test => tests/Kajabity.Tools.Java.Test}/Java/JavaPropertyReaderTest.cs (100%)
 rename {Kajabity.Tools.Java.Test => tests/Kajabity.Tools.Java.Test}/Java/JavaPropertyWriterTest.cs (100%)
 rename {Kajabity.Tools.Java.Test => tests/Kajabity.Tools.Java.Test}/Kajabity.Tools.Java.Test.csproj (97%)
 rename {Kajabity.Tools.Java.Test => tests/Kajabity.Tools.Java.Test}/Test Data/Java/blank.properties (100%)
 rename {Kajabity.Tools.Java.Test => tests/Kajabity.Tools.Java.Test}/Test Data/Java/comments.properties (100%)
 rename {Kajabity.Tools.Java.Test => tests/Kajabity.Tools.Java.Test}/Test Data/Java/duplicate.properties (100%)
 rename {Kajabity.Tools.Java.Test => tests/Kajabity.Tools.Java.Test}/Test Data/Java/empty.properties (100%)
 rename {Kajabity.Tools.Java.Test => tests/Kajabity.Tools.Java.Test}/Test Data/Java/line-break-unicode.properties (100%)
 rename {Kajabity.Tools.Java.Test => tests/Kajabity.Tools.Java.Test}/Test Data/Java/line-breaks.properties (100%)
 rename {Kajabity.Tools.Java.Test => tests/Kajabity.Tools.Java.Test}/Test Data/Java/non-ascii-symbols-native2ascii.properties (100%)
 rename {Kajabity.Tools.Java.Test => tests/Kajabity.Tools.Java.Test}/Test Data/Java/non-ascii-symbols-utf8.properties (100%)
 rename {Kajabity.Tools.Java.Test => tests/Kajabity.Tools.Java.Test}/Test Data/Java/separators.properties (100%)
 rename {Kajabity.Tools.Java.Test => tests/Kajabity.Tools.Java.Test}/Test Data/Java/special-characters.properties (100%)
 rename {Kajabity.Tools.Java.Test => tests/Kajabity.Tools.Java.Test}/Test Data/Java/urls.properties (100%)
 rename {Kajabity.Tools.Java.Test => tests/Kajabity.Tools.Java.Test}/Test Data/Java/utf8-with-BOM.properties (100%)

diff --git a/Kajabity.Tools.Java.sln b/Kajabity.Tools.Java.sln
index 950742c..01ce09b 100644
--- a/Kajabity.Tools.Java.sln
+++ b/Kajabity.Tools.Java.sln
@@ -1,18 +1,17 @@
 
 Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 16
-VisualStudioVersion = 16.0.31515.178
+# Visual Studio Version 18
+VisualStudioVersion = 18.2.11408.102 d18.0
 MinimumVisualStudioVersion = 10.0.40219.1
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{C4DC639F-FAF7-451B-856A-7133B434F10C}"
 	ProjectSection(SolutionItems) = preProject
 		.gitignore = .gitignore
-		appveyor.yml = appveyor.yml
 		README.md = README.md
 	EndProjectSection
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kajabity.Tools.Java", "Kajabity.Tools.Java\Kajabity.Tools.Java.csproj", "{4CF13660-95BA-482C-BA3E-BF97B9624F19}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kajabity.Tools.Java", "src\Kajabity.Tools.Java\Kajabity.Tools.Java.csproj", "{4CF13660-95BA-482C-BA3E-BF97B9624F19}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kajabity.Tools.Java.Test", "Kajabity.Tools.Java.Test\Kajabity.Tools.Java.Test.csproj", "{F182CD46-5B4C-4EDF-A3EE-AEE11FB2A1BE}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kajabity.Tools.Java.Test", "tests\Kajabity.Tools.Java.Test\Kajabity.Tools.Java.Test.csproj", "{F182CD46-5B4C-4EDF-A3EE-AEE11FB2A1BE}"
 EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
diff --git a/README.md b/README.md
index 899d820..2320015 100644
--- a/README.md
+++ b/README.md
@@ -11,43 +11,50 @@ Kajabity.Tools.Java - Java Properties Utilities
 Overview
 --------
 
-Kajabity.Tools.Java is a collection of utility classes to read and write Java style “.properties”
-files in .NET applications.
+Kajabity.Tools.Java is a collection of utility classes for reading and writing Java-style 
+`.properties` files in .NET applications.
 
 This repository contains several sub-projects:
 
-- **Kajabity.Tools.Java** - a DLL project providing the JavaProperties classes for .NET projects.
-- **Kajabity.Tools.Java.Test** - NUnit tests for the Kajabity.Tools.Java classes.
+- Kajabity.Tools.Java – a DLL project providing the JavaProperties classes for .NET projects.
 
-See the Releases section on GitHub to download copies of code, DLL exe's and NuGets.
+- Kajabity.Tools.Java.Test – NUnit tests for the Kajabity.Tools.Java classes.
 
-Kajabity.Tools.Java DLL is a strongly named assembly and is available from nuget.org as
-Kajabity.Tools.Java.
+See the Releases section on GitHub to download source code, DLLs, executables, and NuGet packages.
+
+The Kajabity.Tools.Java DLL is a strongly named assembly and is available from nuget.org as Kajabity.Tools.Java.
 
 Features
 --------
 
-The JavaProperties class wraps a Dictionary class to provide the following additional features:
+The JavaProperties class wraps a `Dictionary` to provide the following additional features:
+
+- Load Java properties from a Stream into a `Dictionary`.
+
+- Load Java properties from a Stream using an alternate encoding (e.g. Unicode), making it easier to 
+  support languages with non-ASCII character sets.
+
+- Store Java properties from a `Dictionary` to a Stream.
 
-- Load Java properties from a Stream into the Dictionary
-- Load Java properties from a Stream with an alternate (e.g. Unicode) encoding – easier to support languages in alternate character sets.
-- Store Java properties to a Stream from the Dictionary.
-- Support default properties (as with Java Properties class) using the 2nd constructor which provides a Dictionary of defaults.
-- Coerce the property keys and values to strings (as they are for Java properties).
+- Support default properties (as with the Java Properties class) using the second constructor, which 
+accepts a `Dictionary` of defaults.
+
+- Coerce property keys and values to strings, matching Java properties behaviour.
 
 Usage
 -----
 
-Full documentation is available at [https://www.kajabity.com/kajabity-tools/java-properties-classes/](https://www.kajabity.com/kajabity-tools/java-properties-classes/).
+Full documentation is available at:
+https://www.kajabity.com/kajabity-tools/java-properties-classes/
 
 Releases
 --------
 
-- **Latest GitHub Release:** [View on GitHub](https://github.com/kajabity/Kajabity.Tools.Java/releases/latest)
-- **Latest NuGet Package:** [View on NuGet.org](https://www.nuget.org/packages/Kajabity.Tools.Java/)
+Latest GitHub Release: View on GitHub
 
-Feedback & Contributions
--------------------------
+Latest NuGet Package: View on NuGet.org
 
-Contributions and feedback are welcome if you notice anything that could be improved.
+Feedback & Contributions
+------------------------
 
+Contributions and feedback are welcome if you notice anything that could be improved.
\ No newline at end of file
diff --git a/Kajabity.Tools.Java/Java/DuplicateKeyResolution.cs b/src/Kajabity.Tools.Java/Java/DuplicateKeyResolution.cs
similarity index 100%
rename from Kajabity.Tools.Java/Java/DuplicateKeyResolution.cs
rename to src/Kajabity.Tools.Java/Java/DuplicateKeyResolution.cs
diff --git a/Kajabity.Tools.Java/Java/JavaProperties.cs b/src/Kajabity.Tools.Java/Java/JavaProperties.cs
similarity index 100%
rename from Kajabity.Tools.Java/Java/JavaProperties.cs
rename to src/Kajabity.Tools.Java/Java/JavaProperties.cs
diff --git a/Kajabity.Tools.Java/Java/JavaPropertyReader.cs b/src/Kajabity.Tools.Java/Java/JavaPropertyReader.cs
similarity index 100%
rename from Kajabity.Tools.Java/Java/JavaPropertyReader.cs
rename to src/Kajabity.Tools.Java/Java/JavaPropertyReader.cs
diff --git a/Kajabity.Tools.Java/Java/JavaPropertyWriter.cs b/src/Kajabity.Tools.Java/Java/JavaPropertyWriter.cs
similarity index 100%
rename from Kajabity.Tools.Java/Java/JavaPropertyWriter.cs
rename to src/Kajabity.Tools.Java/Java/JavaPropertyWriter.cs
diff --git a/Kajabity.Tools.Java/Java/ParseException.cs b/src/Kajabity.Tools.Java/Java/ParseException.cs
similarity index 100%
rename from Kajabity.Tools.Java/Java/ParseException.cs
rename to src/Kajabity.Tools.Java/Java/ParseException.cs
diff --git a/Kajabity.Tools.Java/Kajabity.Tools.Java.csproj b/src/Kajabity.Tools.Java/Kajabity.Tools.Java.csproj
similarity index 57%
rename from Kajabity.Tools.Java/Kajabity.Tools.Java.csproj
rename to src/Kajabity.Tools.Java/Kajabity.Tools.Java.csproj
index eb832af..57d7026 100644
--- a/Kajabity.Tools.Java/Kajabity.Tools.Java.csproj
+++ b/src/Kajabity.Tools.Java/Kajabity.Tools.Java.csproj
@@ -1,7 +1,7 @@
 
 
   
-    netstandard2.0;net47;net471;net472;net48;net481;net10.0
+    netstandard2.0;net48;net10.0
 
     
     Kajabity
@@ -16,24 +16,36 @@
     Java Properties
     https://github.com/Kajabity/Kajabity.Tools.Java
     git
-    true
     README.md
   
 
-  
+	
+		true
+		true
+		true
+	
+
+	
     true
     snupkg
   
 
   
-    
-    
-    
+    
+    
+      all
+      runtime; build; native; contentfiles; analyzers; buildtransitive
+    
+  
+
+  
+    
+    
+    
   
 
   
     true
     Kajabity.Tools.Java.snk
-    True
   
 
diff --git a/Kajabity.Tools.Java/Kajabity.Tools.Java.snk b/src/Kajabity.Tools.Java/Kajabity.Tools.Java.snk
similarity index 100%
rename from Kajabity.Tools.Java/Kajabity.Tools.Java.snk
rename to src/Kajabity.Tools.Java/Kajabity.Tools.Java.snk
diff --git a/Kajabity.Tools.Java/NOTICE.txt b/src/Kajabity.Tools.Java/NOTICE.txt
similarity index 100%
rename from Kajabity.Tools.Java/NOTICE.txt
rename to src/Kajabity.Tools.Java/NOTICE.txt
diff --git a/Kajabity.Tools.Java.Test/Java/JavaPropertyReaderTest.cs b/tests/Kajabity.Tools.Java.Test/Java/JavaPropertyReaderTest.cs
similarity index 100%
rename from Kajabity.Tools.Java.Test/Java/JavaPropertyReaderTest.cs
rename to tests/Kajabity.Tools.Java.Test/Java/JavaPropertyReaderTest.cs
diff --git a/Kajabity.Tools.Java.Test/Java/JavaPropertyWriterTest.cs b/tests/Kajabity.Tools.Java.Test/Java/JavaPropertyWriterTest.cs
similarity index 100%
rename from Kajabity.Tools.Java.Test/Java/JavaPropertyWriterTest.cs
rename to tests/Kajabity.Tools.Java.Test/Java/JavaPropertyWriterTest.cs
diff --git a/Kajabity.Tools.Java.Test/Kajabity.Tools.Java.Test.csproj b/tests/Kajabity.Tools.Java.Test/Kajabity.Tools.Java.Test.csproj
similarity index 97%
rename from Kajabity.Tools.Java.Test/Kajabity.Tools.Java.Test.csproj
rename to tests/Kajabity.Tools.Java.Test/Kajabity.Tools.Java.Test.csproj
index 94272ad..b80a50d 100644
--- a/Kajabity.Tools.Java.Test/Kajabity.Tools.Java.Test.csproj
+++ b/tests/Kajabity.Tools.Java.Test/Kajabity.Tools.Java.Test.csproj
@@ -32,7 +32,7 @@
   
 
   
-    
+    
   
 
   
diff --git a/Kajabity.Tools.Java.Test/Test Data/Java/blank.properties b/tests/Kajabity.Tools.Java.Test/Test Data/Java/blank.properties
similarity index 100%
rename from Kajabity.Tools.Java.Test/Test Data/Java/blank.properties
rename to tests/Kajabity.Tools.Java.Test/Test Data/Java/blank.properties
diff --git a/Kajabity.Tools.Java.Test/Test Data/Java/comments.properties b/tests/Kajabity.Tools.Java.Test/Test Data/Java/comments.properties
similarity index 100%
rename from Kajabity.Tools.Java.Test/Test Data/Java/comments.properties
rename to tests/Kajabity.Tools.Java.Test/Test Data/Java/comments.properties
diff --git a/Kajabity.Tools.Java.Test/Test Data/Java/duplicate.properties b/tests/Kajabity.Tools.Java.Test/Test Data/Java/duplicate.properties
similarity index 100%
rename from Kajabity.Tools.Java.Test/Test Data/Java/duplicate.properties
rename to tests/Kajabity.Tools.Java.Test/Test Data/Java/duplicate.properties
diff --git a/Kajabity.Tools.Java.Test/Test Data/Java/empty.properties b/tests/Kajabity.Tools.Java.Test/Test Data/Java/empty.properties
similarity index 100%
rename from Kajabity.Tools.Java.Test/Test Data/Java/empty.properties
rename to tests/Kajabity.Tools.Java.Test/Test Data/Java/empty.properties
diff --git a/Kajabity.Tools.Java.Test/Test Data/Java/line-break-unicode.properties b/tests/Kajabity.Tools.Java.Test/Test Data/Java/line-break-unicode.properties
similarity index 100%
rename from Kajabity.Tools.Java.Test/Test Data/Java/line-break-unicode.properties
rename to tests/Kajabity.Tools.Java.Test/Test Data/Java/line-break-unicode.properties
diff --git a/Kajabity.Tools.Java.Test/Test Data/Java/line-breaks.properties b/tests/Kajabity.Tools.Java.Test/Test Data/Java/line-breaks.properties
similarity index 100%
rename from Kajabity.Tools.Java.Test/Test Data/Java/line-breaks.properties
rename to tests/Kajabity.Tools.Java.Test/Test Data/Java/line-breaks.properties
diff --git a/Kajabity.Tools.Java.Test/Test Data/Java/non-ascii-symbols-native2ascii.properties b/tests/Kajabity.Tools.Java.Test/Test Data/Java/non-ascii-symbols-native2ascii.properties
similarity index 100%
rename from Kajabity.Tools.Java.Test/Test Data/Java/non-ascii-symbols-native2ascii.properties
rename to tests/Kajabity.Tools.Java.Test/Test Data/Java/non-ascii-symbols-native2ascii.properties
diff --git a/Kajabity.Tools.Java.Test/Test Data/Java/non-ascii-symbols-utf8.properties b/tests/Kajabity.Tools.Java.Test/Test Data/Java/non-ascii-symbols-utf8.properties
similarity index 100%
rename from Kajabity.Tools.Java.Test/Test Data/Java/non-ascii-symbols-utf8.properties
rename to tests/Kajabity.Tools.Java.Test/Test Data/Java/non-ascii-symbols-utf8.properties
diff --git a/Kajabity.Tools.Java.Test/Test Data/Java/separators.properties b/tests/Kajabity.Tools.Java.Test/Test Data/Java/separators.properties
similarity index 100%
rename from Kajabity.Tools.Java.Test/Test Data/Java/separators.properties
rename to tests/Kajabity.Tools.Java.Test/Test Data/Java/separators.properties
diff --git a/Kajabity.Tools.Java.Test/Test Data/Java/special-characters.properties b/tests/Kajabity.Tools.Java.Test/Test Data/Java/special-characters.properties
similarity index 100%
rename from Kajabity.Tools.Java.Test/Test Data/Java/special-characters.properties
rename to tests/Kajabity.Tools.Java.Test/Test Data/Java/special-characters.properties
diff --git a/Kajabity.Tools.Java.Test/Test Data/Java/urls.properties b/tests/Kajabity.Tools.Java.Test/Test Data/Java/urls.properties
similarity index 100%
rename from Kajabity.Tools.Java.Test/Test Data/Java/urls.properties
rename to tests/Kajabity.Tools.Java.Test/Test Data/Java/urls.properties
diff --git a/Kajabity.Tools.Java.Test/Test Data/Java/utf8-with-BOM.properties b/tests/Kajabity.Tools.Java.Test/Test Data/Java/utf8-with-BOM.properties
similarity index 100%
rename from Kajabity.Tools.Java.Test/Test Data/Java/utf8-with-BOM.properties
rename to tests/Kajabity.Tools.Java.Test/Test Data/Java/utf8-with-BOM.properties