G9AssemblyManagement 1.4.5.21

dotnet add package G9AssemblyManagement --version 1.4.5.21                
NuGet\Install-Package G9AssemblyManagement -Version 1.4.5.21                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="G9AssemblyManagement" Version="1.4.5.21" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add G9AssemblyManagement --version 1.4.5.21                
#r "nuget: G9AssemblyManagement, 1.4.5.21"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install G9AssemblyManagement as a Cake Addin
#addin nuget:?package=G9AssemblyManagement&version=1.4.5.21

// Install G9AssemblyManagement as a Cake Tool
#tool nuget:?package=G9AssemblyManagement&version=1.4.5.21                

G9TM G9AssemblyManagement

NuGet version (G9AssemblyManagement) Azure DevOps Pipeline Build Status Github Repository

G9AssemblyManagement

❇️Guide

Type Tools

This helper tool provides many various utilities for working by the types.

Tool for getting inherited types from a specified type:

var result = G9Assembly.TypeTools.GetInheritedTypesFromType(typeof(IPAddress));
Console.WriteLine(result.Count); //  1
Console.WriteLine(result[0].Name); // ReadOnlyIPAddress
  • Indeed, the type 'ReadOnlyIPAddress' is derived from the type 'IPAddress.'

This tool checks whether a specified type is a built-in .NET type or not:

// Some built-in .NET Types
var v1 = 1;
var v2 = DateTime.Now;
var v3 = IPAddress.Any;
// Custom type
var v4 = new CustomType();

Console.WriteLine(G9Assembly.TypeTools.IsTypeBuiltInDotNetType(v1.GetType())); // true
Console.WriteLine(G9Assembly.TypeTools.IsTypeBuiltInDotNetType(v1.GetType())); // true
Console.WriteLine(G9Assembly.TypeTools.IsTypeBuiltInDotNetType(v3.GetType())); // true
Console.WriteLine(G9Assembly.TypeTools.IsTypeBuiltInDotNetType(v4.GetType())); // false

A practical tool for changing the type of an object along with an intelligent value-changing process in possible conditions:

// Changes to string and number
var consoleColorString = G9Assembly.TypeTools.SmartChangeType<string>(ConsoleColor.DarkMagenta);
// "DarkMagenta"
var consoleColorNumber = G9Assembly.TypeTools.SmartChangeType<int>(ConsoleColor.DarkMagenta);
// 5

// Changes to primary type from string and number
var consoleColor = G9Assembly.TypeTools.SmartChangeType<ConsoleColor>(consoleColorString);
// ConsoleColor.DarkMagenta
consoleColor = G9Assembly.TypeTools.SmartChangeType<ConsoleColor>(consoleColorNumber);
// ConsoleColor.DarkMagenta

Instance Tools

This helper tool provides many practical utilities for working by the instances.

We sometimes need to access some instances of an object that aren't specified where they have been created, a process that is a little similar to dependency injection. In this case, this tool provides two ways of doing that.
Sample classes:

// In this scenario, we must inherit the abstract class 'G9AClassInitializer' in our desired classes.

// First sample
public class MyCustomClassA : G9AClassInitializer
{
    public string GetClassName()
    {
        return nameof(MyCustomClassA);
    }
}

// Second sample
public class MyCustomClassB : G9AClassInitializer
{
    public string GetClassName()
    {
        return nameof(MyCustomClassB);
    }
}

First way:

// In the following, each created instance of the above samples is accessible in the following way:

private static void Main()
{
    // MyCustomClassA
    var instance1 = new MyCustomClassA();
    var instance2 = new MyCustomClassA();
    var instance3 = new MyCustomClassA();

    // MyCustomClassB
    var instance4 = new MyCustomClassB();
    var instance5 = new MyCustomClassB();

    var instancesOfClassA = G9Assembly.InstanceTools.GetInstancesOfType<MyCustomClassA>();
    Console.WriteLine(instancesOfClassA.Count); // 3
    Console.WriteLine(instancesOfClassA[0].GetClassName()); // MyCustomClassA

    var instancesOfClassB = G9Assembly.InstanceTools.GetInstancesOfType<MyCustomClassB>();
    Console.WriteLine(instancesOfClassA.Count); // 2
    Console.WriteLine(instancesOfClassA[0].GetClassName()); // MyCustomClassB
}

Second way:

// Or, with a listener, we can control the new instance, removed instance, and exceptions:
private static void Main()
{
     var instanceListener =
        G9Assembly.InstanceTools.AssignInstanceListener<MyCustomClassA>
        (
            // On assign
            newInstance =>
            {
                // Do anything
            },
            // On Unassigning
            instance =>
            {
                // Do anything
            },
            // On receive exception
            ex =>
            {
                // Do anything
            }
        );
}

Sometimes, we need to create an instance of a type that there are many ways depending on the conditions:

// Method to create an instance from a type, first way:
G9Assembly.InstanceTools.CreateInstanceFromType<CustomType>();
// Method to create an instance from a type, second way:
G9Assembly.InstanceTools.CreateInstanceFromType(typeof(CustomType));
// Method to create an instance from a type with the constructor that has parameters
G9Assembly.InstanceTools.CreateInstanceFromTypeWithConstructorParameters(typeof(CustomType), "param1", "param2");
// Method to create an uninitialized instance from a type
G9Assembly.InstanceTools.CreateUninitializedInstanceFromType<IPAddress>();
// Method to create an instance from a generic type
G9Assembly.InstanceTools.CreateInstanceFromGenericType(
    typeof(GenericCustomType<>), typeof(IPAddress));
// Method to create an instance from a generic type with the constructor that has parameters
G9Assembly.InstanceTools.CreateInstanceFromGenericTypeWithConstructorParameters(
    typeof(GenericCustomType<,,>),
    // Custom generic types
    new[] { typeof(IPAddress), typeof(int), typeof(string) },
    // Specifies parameters
    "Param 1", "param 2" );

Reflection Tools

This tool provides many helpful methods for working with object members (reflection). All of the methods shown below have many functional parameters like the access modifier, custom filter, and so on that aren't shown:

// Note: The output of the whole reflection methods below is an array.

// Method to get fields of an object
var fields = G9Assembly.ReflectionTools.GetFieldsOfObject(myCustomObject);
// Method to get properties of an object
var properties = G9Assembly.ReflectionTools.GetPropertiesOfObject(myCustomObject);

// Common methods between fields and properties
Console.WriteLine(fields[0].GetValue()); // Method for getting the value of fields/properties.
properties[0].SetValue("Custom value"); // Method for setting a new value for fields/properties.

// Method to get Methods of an object
var methods = G9Assembly.ReflectionTools.GetMethodsOfObject(myCustomObject)
methods[0].CallMethod(); // method without result
var result1 = methods[1].CallMethodWithResult<int>(
    // If the desired method has parameters.
    6, 3); // method with result.

// Method to get generic methods of an object
var generigMethods = G9Assembly.ReflectionTools.GetGenericMethodsOfObject(object1);
generigMethods[0].CallMethod(); // method without result
var result2 = generigMethods[1].CallMethodWithResult<int>(
    // Specifies the generic types for the method.
    new[] { typeof(int), typeof(string), typeof(IPAddress) },
    // If the desired method has parameters.
    1, "G9TM", IPAddress.Broadcast); // method with result.


// There are also similar methods for working on type members.
// Method to get properties of a type
G9Assembly.ReflectionTools.GetPropertiesOfType(typeof(myCustomObject));
// Method to get fields of a type
G9Assembly.ReflectionTools.GetFieldsOfType(typeof(myCustomObject));
// Method to get properties of a type
G9Assembly.ReflectionTools.GetPropertiesOfType(typeof(myCustomObject));
// Method to get Methods of a type
G9Assembly.ReflectionTools.GetMethodsOfType(typeof(myCustomObject));
// Method to get generic methods of a type
G9Assembly.ReflectionTools.GetGenericMethodsOfType(typeof(myCustomObject));

Merging two objects

The merger tool provides an operational process for merging two objects. With that, you can make a custom process for integrating two things under many conditions. The method of merging is explained below.
Sample classes

// First sample
public class MyCustomClassA
{
    public int Age = 99;
    public string Name = "St1";
    public DateTime CurrentDateTime = DateTime.Now;
    public float Percent = 99.9f;
}

// Second sample
public class MyCustomClassB
{
    public string Age = "eight";
    public string Name = "St2";
    public DateTime CurrentDateTime = DateTime.Now;
    public string Percent = "39.9f";
}

Method of merging

private static void Main()
{
    var objectA = new MyCustomClassA();
    var objectB = new MyCustomClassB();

    G9Assembly.ObjectAndReflectionTools
    // In this case, the members' values of object B are set on Object A.
    .MergeObjectsValues(ref objectA, objectB,
        // Specifies the desired access modifier.
        G9EAccessModifier.Public,
        // Specifies that if two members' values don't have a shared type and can't transfer their values, the process must ignore them.
        // In this case, both objects have the same member with the name "Percent," But in the first one, it's Float, and in the second one, it's String. So, a mismatching occurs, but the core ignores it according to this setting (AllowMismatchValues).
        G9EValueMismatchChecking.AllowMismatchValues,
        // Specifies that if a mismatch occurs between two members' values, an automatic try to change type must happen or not.
        // If it is set to 'true,' the value of "Percent" will automatically convert from String to Float.
        false,
        // Specifies a custom filter for searching object's members if needed.
        // In this case, members with the name "CurrentDateTime" are ignored.
        member => member.Name != "CurrentDateTime",
        // Specifies a custom process for desired members if needed.
        // Notice: The function's result specifies whether the custom process handled merging or not.
        // If it's returned 'true.' Specifies that the custom process has done the merging process, and the core mustn't do anything.
        // If it's returned 'false.' Specifies that the custom process skipped the merging process, So the core must do it.
        // In the below case, the custom process just does the merging process on the member with the name "Age":
        (m1, m2) =>
        {
            // For the "Age" member
            if (m1.Name == "Age")
            {
                switch (m2.GetValue<string>())
                {
                    case "nine":
                        m1.SetValue(9);
                        break;
                    case "eight":
                        m1.SetValue(8);
                        break;
                    default:
                        m1.SetValue(0);
                        break;
                }

                // Returns true if the desired process performs the value-changing.
                // In simple words, it's done it.
                return true;
            }

            // Returns false if the value-changing process needs to pass to the core.
            return false;
        });

        // Result
        Console.WriteLine(objectA.Age); // 8
        Console.WriteLine(objectA.Name); // St2
        Console.WriteLine(objectA.Percent); // 99.9
}

Cryptography Tools

This small tool provides the essential methods for cryptography.

There are many hashing methods, and the most practical of them is provided here:

private static void Main()
{
    const string testText = "Programmers never die because they are tiny gods.";
    // message-digest algorithm
    var md5 = G9Assembly.CryptographyTools
        .StringToCustomHash(G9EHashAlgorithm.MD5, testText);
    // Secure Hash Algorithm 1
    var sha1 = G9Assembly.CryptographyTools
        .StringToCustomHash(G9EHashAlgorithm.SHA1, testText);
    // Secure Hash Algorithm 256
    var sha256 = G9Assembly.CryptographyTools
        .StringToCustomHash(G9EHashAlgorithm.SHA256, testText);
    // Secure Hash Algorithm 384
    var sha384 = G9Assembly.CryptographyTools
        .StringToCustomHash(G9EHashAlgorithm.SHA384, testText);
    // Secure Hash Algorithm 512
    var sha512 = G9Assembly.CryptographyTools
        .StringToCustomHash(G9EHashAlgorithm.SHA512, testText);
    // cyclic redundancy checksum
    var crc32 = G9Assembly.CryptographyTools
        .StringToCustomHash(G9EHashAlgorithm.CRC32, testText);
}

And also, there are many cryptography methods, and the most practical of them (AES type) is provided here:

private static void Main()
{
    const string testText = "Programmers never die because they are tiny gods.";
    const string standardKey = "eShVmYp3s6v9y$B&";
    const string standardIv = "gUkXp2s5v8x/A?D(";

    var aesInit = G9Assembly.CryptographyTools.InitAesCryptography(
        // Specifies custom private key.
        standardKey,
        // Specifies custom initialization vector.
        standardIv,
        // Specifies the custom config for encryption and decryption.
        // It's optional; by default, the values below are set for that.
        new G9DtAESConfig(
            paddingMode: PaddingMode.PKCS7,
            cipherMode: CipherMode.CBC,
            keySize: 128,
            blockSize: 128,
            // Specifies that if the key size isn't standard.
            // The process must fix it or not. (With an arbitrary process)
            enableAutoFixKeySize: false
        ));

    // AES encryption algorithm
    var aesEncryptionText =
        aesInit.EncryptString(
                // Specifies plain text.
                testText);

    // AES decryption algorithm
    var aesDecryptionText =
        aesInit.DecryptString(
                // Specifies cipher text.
                aesEncryptionText);

    Console.WriteLine(testText == aesDecryptionText);
    // true
}

Performance Tools

A helpful tool that is more used for testing performances.

The first one is used for testing multi-thread requests. It's like a simulated area that runs a custom code block many times:

private static void Main()
{
    var desiredNumberOfRepetitions = 999999;
    G9Assembly.PerformanceTools.MultiThreadShockTest(
        // Provides a random number.
        randomNumber =>
        {
            // Your custom code block for testing.
        },
        // Specifies desired a number of repetitions.
        desiredNumberOfRepetitions
    );
}

The second method compares two code blocks in terms of speed and memory usage:

private static void Main()
{
    // First
    void StringSum1()
    {
        var basisData = string.Empty;
        basisData += "AaA";
        basisData += basisData;
        basisData += basisData;
        basisData += basisData;
        _ = string.IsNullOrEmpty(basisData);
    }

    // Second
    void StringSum2()
    {
        var basisData = string.Empty;
        basisData = basisData + "AaA";
        basisData = basisData + "AaA";
        basisData = basisData + "AaA";
        basisData = basisData + "AaA";
        _ = string.IsNullOrEmpty(basisData);
    }

    // Single-core and multi-core test
    var desiredNumberOfRepetitions = 999999;
     var comparativeResult = G9Assembly.PerformanceTools
        .ComparativePerformanceTester(
            // Specifies that test must perform in both states of single-core and multi-core.
            G9EPerformanceTestMode.Both,
            // Specifies desired a number of repetitions.
            desiredNumberOfRepetitions,
            // Specifies the desired code blocks for testing.
            StringSum1, StringSum2);
}
  • Note: The output of this method has many details that are beyond the scope of this article.

Input Output Tools

In simple terms, it provides useful I/O tools.

Checking a path on the computer in terms of validation can consist of many things, like validation, path existence, and drive existence. Here with a method all of them are handled:

private static void Main()
{
    // Note: Assumes that the computer has the I drive but doesn't have the X drive.

    // Directory paths
    const string directory1 = @"I:\Project\!G9TM!\Page";
    const string directory2 = @"\Project\!G9TM!\Page";
    const string directory3 = @"I:\Project\!!!!!!!";
    const string directory4 = @"X:\Project\!G9TM!\Page";
    const string directory5 = @"\asd|asd|asd";

    // Notes about the following methods:
    // Note 1: The second parameter specifies whether the directory drive in terms of existence must be checked or not.
    // Note 2: The third parameter specifies whether the directory path in terms of existence must be checked or not.
    // Note 3: The fourth parameter specifies if the validation isn't correct, an exception must be thrown or not.
    // Note 4: The result of the below methods is an Enum type.

    Console.WriteLine(G9Assembly.InputOutputTools
        .CheckDirectoryPathValidation(directory1, true, false, false));
    // Result: G9EPatchCheckResult.Correct

    Console.WriteLine(G9Assembly.InputOutputTools
        .CheckDirectoryPathValidation(directory2, true, false, false));
    // Result: G9EPatchCheckResult.Correct

    Console.WriteLine(G9Assembly.InputOutputTools
        .CheckDirectoryPathValidation(directory3, true, true, false));
    // Result: G9EPatchCheckResult.PathExistenceIsIncorrect

    Console.WriteLine(G9Assembly.InputOutputTools
        .CheckDirectoryPathValidation(directory4, true, true, false));
    // Result: G9EPatchCheckResult.PathDriveIsIncorrect

    Console.WriteLine(G9Assembly.InputOutputTools
        .CheckDirectoryPathValidation(directory5, true, true, false));
    // Result: G9EPatchCheckResult.PathNameIsIncorrect

    // File paths
    const string file1 = @"I:\Project\!G9TM!\Page\First.png";
    const string file2 = @"\Project\!G9TM!\Page\First.png";
    const string file3 = @"I:\Project\!!!!!!!\First.png";
    const string file4 = @"X:\Project\!G9TM!\Page\First.png";
    const string file5 = @"\Fi|r|st.png";
    const string file6 = @"okay.png";
    const string file7 = @"okay.p-n|g";

    Console.WriteLine(G9Assembly.InputOutputTools
        .CheckFilePathValidation(file1, false, false, false));
    // G9EPatchCheckResult.Correct

    Console.WriteLine(G9Assembly.InputOutputTools
        .CheckFilePathValidation(file2, true, false, false));
    // G9EPatchCheckResult.Correct

    Console.WriteLine(G9Assembly.InputOutputTools
        .CheckFilePathValidation(file3, true, true, false));
    // G9EPatchCheckResult.PathExistenceIsIncorrect

    Console.WriteLine(G9Assembly.InputOutputTools
        .CheckFilePathValidation(file4, true, true, false));
    // G9EPatchCheckResult.PathDriveIsIncorrect

    Console.WriteLine(G9Assembly.InputOutputTools
        .CheckFilePathValidation(file5, true, true, false));
    // G9EPatchCheckResult.PathNameIsIncorrect

    Console.WriteLine(G9Assembly.InputOutputTools
        .CheckFilePathValidation(file6, true, false, false));
    // G9EPatchCheckResult.Correct

    Console.WriteLine(G9Assembly.InputOutputTools
        .CheckFilePathValidation(file7, true, true, false));
    // G9EPatchCheckResult.PathNameIsIncorrect

}

Method to make a wait system for access to the file with specified access and custom options.

G9Assembly.InputOutputTools.WaitForAccessToFile(
    // Specifies the full path of desired file.
    filePath,
    // Specifies a callback for invoking.
    // The specified callback invokes when the desired specified access would be available. In addition,
    // it has a parameter that provides a usable opened file stream on your specified file.
    fs =>
    {
        var data = Encoding.UTF8.GetBytes("Programmers never die because they are tiny gods!");
        fs.Write(data, 0, data.Length);
    },
    // Specifies how the operating system should open a file.
    FileMode.CreateNew,
    // Defines constants for read, write, or read/write access to a file.
    FileAccess.Write,
    // Contains constants for controlling the kind of access other objects can have to the same file.
    FileShare.Write,
    // Specifies how many times must be tried.
    9,
    // Specifies how much time must be considered between each try in milliseconds.
    99);

Embedded Resource

How to set a file as the Embedded Resource?
In Visual Studio:

G9TM

In Visual Studio for Mac:

G9TM

Or In 'project.csproj' file:
<ItemGroup>
  <EmbeddedResource Include="EmbeddedResources\Test\Test\a.txt" />
</ItemGroup>
Method to get a stream from a file that is an embedded resource.
// Embedded resouce file path
const string mbrPath1 = "EmbeddedResources.Test.Test.1.png";
// Access to stream of embedded resource file path
var stream = G9Assembly.InputOutputTools.EmbeddedResourceGetStreamFromFile(
    // Specifies the target assembly for catching the file.
    GetType().Assembly,
    // Specifies the address if embedded resource file.
    mbrPath1);
Method to copy multiple files from embedded resource addresses to a target directory.
// Embedded resouce file data type
 List<G9DtEmbeddedResourceFile> embStructure = new List<G9DtEmbeddedResourceFile>()
 {
     new G9DtEmbeddedResourceFile("EmbeddedResources.Test.Test.1.png", "ebr_copy_test/1/1.png"),
     new G9DtEmbeddedResourceFile("EmbeddedResources.Test.Test.2.png", "ebr_copy_test/1/2.png"),
     new G9DtEmbeddedResourceFile("EmbeddedResources.Test.Test.3.png", "ebr_copy_test/1/3.png"),
     new G9DtEmbeddedResourceFile("EmbeddedResources.Test.Test.a.txt", "ebr_copy_test/1/a.txt"),
 };
// Copy multiple files from embedded resource addresses to a target directory.
 G9Assembly.InputOutputTools.EmbeddedResourceCopyFilesToPath(
    // Specifies the target assembly for catching the file.
     GetType().Assembly,
     // Specifies the embedded resource path array.
     embStructure,
     // Specifies a custom process for copying.
     // By that, you can make the needed changes in the file before copying.
     (s, bytes) =>
     {
        // a.txt file
         if (s.EndsWith("a.txt"))
         {
             // Change specific target file
             var str = Encoding.UTF8.GetString(bytes);
             str = str.Replace("<ReplacePlace>", "G9Team");
             // rerun new data (with changes)
             return Encoding.UTF8.GetBytes(str);
         }

         // Without Change
         return bytes;
     },
     // Specifies if the target path (for copying) does not exist, It must be created or not.
     true,
     // Specifies the file mode for creating a copy
     FileMode.Create,
     // Specifies the file access for creating.
     FileAccess.Write,
     // Specifies the file share for creating.
     FileShare.Write);

General Tools

Some practical tools for everything.

Convert file volume units (bytes, kilobytes, etc.) to each other:

const long byteSize = 1000000000;
G9Assembly.GeneralTools.ConvertByteSizeToAnotherSize(
    // Specifies the byte size
    byteSize,
    // Specifies a unit for converting
    // Byte - KiloByte - MegaByte - GigaByte - TeraByte - PetaByte - ...
     G9ESizeUnits.Byte))

Get the assembly version

// Method to get the current version of the assembly.
var version = G9Assembly.GeneralTools.GetAssemblyVersion(
    // Specifies the target assembly for getting the version
    GetType().Assembly
);

END

Be the best you can be; the future depends on it. 🚀

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 is compatible. 
.NET Framework net35 is compatible.  net40 is compatible.  net403 was computed.  net45 is compatible.  net451 was computed.  net452 was computed.  net46 was computed.  net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on G9AssemblyManagement:

Package Downloads
G9JSONHandler

A pretty small .NET library has been developed for working with JSON. This library provides many helpful attributes for members like Comment, Encryption, CustomName, Ordering, Ignoring, CustomParser, etc. On the other hand, with the custom parser structure, you can define your desired parsing process for specific types, or with a preferred config, you can customize the parsing process, which leads to more flexibility.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.4.5.21 142 2/8/2024
1.4.5.1 118 2/8/2024
1.4.5 1,052 9/25/2022
1.4.4.2 1,920 9/20/2022
1.4.4.1 409 9/20/2022
1.4.4 410 9/19/2022
1.4.3.3 691 9/11/2022
1.4.3.2 396 9/11/2022
1.4.3.1 396 9/11/2022
1.4.2.7 674 9/7/2022
1.4.2.6 695 8/31/2022
1.4.2.5 390 8/31/2022
1.4.2.3 907 8/28/2022
1.4.2.2 945 8/25/2022
1.4.0.1 646 8/20/2022
1.3.3.5 396 8/18/2022
1.3.3.4 407 8/18/2022
1.3.3.2 434 8/17/2022
1.3.3.1 1,155 8/17/2022
1.2.0 713 8/10/2022
1.1.5 679 8/9/2022
1.1.4 420 8/8/2022
1.1.3 690 8/8/2022
1.1.2 431 8/7/2022
1.1.1 410 8/6/2022
1.1.0 417 8/5/2022
1.0.0.3 426 8/3/2022
1.0.0.1 380 8/19/2021
1.0.0 351 8/19/2021

-- Added I/O Part.
-- Redigned Structure.
-- Completed tests.