3 Commits
Author SHA1 Message Date
BlubbFish 7f3f3a7b89 Helper also know type string; move to .net 10 2026-08-04 12:19:10 +02:00
BlubbFish cc579102cb [1.6.2] ProgrammLogger improved 2022-01-30 22:40:25 +01:00
BlubbFish e3d37988c9 [1.6.1] ProgrammLogger Fixed 2022-01-20 19:42:14 +01:00
6 changed files with 410 additions and 370 deletions
+15
View File
@@ -1,5 +1,20 @@
# Changelog
## 1.6.2 - 2022-01-30 - ProgrammLogger improved
### New Features
* ProgrammLogger can now have a path while init, so not need to move the file
* Make it possible that two instances can use the same logfile
* IniReader GetValue can now have a default that returns if no setting is found
### Bugfixes
### Changes
* Codingstyles
## 1.6.1 - 2022-01-20 - ProgrammLogger Fixed
### New Features
### Bugfixes
* Unhandled exception. System.IO.IOException: The file '/var/log/zwaybot/debug.log' already exists.
### Changes
## 1.6.0 - 2022-01-09 - HttpEndpoint added
### New Features
* Add HttpEndpoint
+191 -191
View File
@@ -1,199 +1,199 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace BlubbFish.Utils
{
public class CmdArgs
{
public enum ArgLength
{
Single,
Touple
}
#region Classes
public struct VaildArguments
{
public VaildArguments(ArgLength length, Boolean required, String @default = "", String description = "")
{
this.Required = required;
this.Length = length;
this.Description = description;
this.@Default = @default;
}
public VaildArguments(ArgLength length, String @default = "", String description = "")
{
this.Required = false;
this.Length = length;
this.Description = description;
this.@Default = @default;
}
public ArgLength Length { get; private set; }
public Boolean Required { get; private set; }
public String Description { get; private set; }
public String Default { get; private set; }
}
private struct ArgTouple
{
public ArgTouple(String type, String data)
{
this.Type = type;
this.Data = data;
}
public ArgTouple(String type)
{
this.Type = type;
this.Data = null;
}
public String Type { get; private set; }
public String Data { get; private set; }
internal void SetData(String data)
{
if (data != "") {
this.Data = data;
}
}
}
#endregion
private String[] args;
private List<ArgTouple> argList;
private Dictionary<String, VaildArguments> argsPosible = new Dictionary<String, VaildArguments>();
private static CmdArgs instances = null;
private Boolean isSetArguments = false;
private CmdArgs()
{
}
/// <summary>
/// Gibt eine Instanz der Klasse zurück
/// </summary>
/// <returns>Klasse</returns>
public static CmdArgs Instance
{
get {
if (instances == null) {
instances = new CmdArgs();
}
return instances;
}
}
/// <summary>
/// Übernimmt die Argumente für die Klasse
/// </summary>
/// <param name="arguments">Mögliche Komandozeilenargumente</param>
/// <param name="args">Tatsächliche Komandozeilenargumente</param>
public void SetArguments(Dictionary<String, VaildArguments> arguments, String[] args)
{
this.args = args;
if (!this.isSetArguments) {
this.isSetArguments = true;
this.argsPosible = arguments;
this.Init();
}
}
private void Init()
{
this.argList = new List<ArgTouple>();
for (Int32 i = 0; i < this.args.Length; i++) {
if (this.argsPosible.Keys.Contains(this.args[i])) {
ArgTouple arg = new ArgTouple(this.args[i]);
if (this.argsPosible[this.args[i]].Length == ArgLength.Touple) {
if (this.args.Length > i + 1) {
arg.SetData(this.args[++i]);
} else {
Console.WriteLine(this.GetUsageList(""));
throw new ArgumentException("Argument: "+this.args[i]+" missing second argument.");
}
}
this.argList.Add(arg);
}
}
using System;
using System.Collections.Generic;
using System.Linq;
namespace BlubbFish.Utils
{
public class CmdArgs
{
public enum ArgLength
{
Single,
Touple
}
#region Classes
public struct VaildArguments
{
public VaildArguments(ArgLength length, Boolean required, String @default = "", String description = "")
{
this.Required = required;
this.Length = length;
this.Description = description;
this.@Default = @default;
}
public VaildArguments(ArgLength length, String @default = "", String description = "")
{
this.Required = false;
this.Length = length;
this.Description = description;
this.@Default = @default;
}
public ArgLength Length { get; private set; }
public Boolean Required { get; private set; }
public String Description { get; private set; }
public String Default { get; private set; }
}
private struct ArgTouple
{
public ArgTouple(String type, String data)
{
this.Type = type;
this.Data = data;
}
public ArgTouple(String type)
{
this.Type = type;
this.Data = null;
}
public String Type { get; private set; }
public String Data { get; private set; }
internal void SetData(String data)
{
if (data != "") {
this.Data = data;
}
}
}
#endregion
private String[] args;
private List<ArgTouple> argList;
private Dictionary<String, VaildArguments> argsPosible = new Dictionary<String, VaildArguments>();
private static CmdArgs instances = null;
private Boolean isSetArguments = false;
private CmdArgs()
{
}
/// <summary>
/// Gibt eine Instanz der Klasse zurück
/// </summary>
/// <returns>Klasse</returns>
public static CmdArgs Instance
{
get {
if (instances == null) {
instances = new CmdArgs();
}
return instances;
}
}
/// <summary>
/// Übernimmt die Argumente für die Klasse
/// </summary>
/// <param name="arguments">Mögliche Komandozeilenargumente</param>
/// <param name="args">Tatsächliche Komandozeilenargumente</param>
public void SetArguments(Dictionary<String, VaildArguments> arguments, String[] args)
{
this.args = args;
if (!this.isSetArguments) {
this.isSetArguments = true;
this.argsPosible = arguments;
this.Init();
}
}
private void Init()
{
this.argList = new List<ArgTouple>();
for (Int32 i = 0; i < this.args.Length; i++) {
if (this.argsPosible.Keys.Contains(this.args[i])) {
ArgTouple arg = new ArgTouple(this.args[i]);
if (this.argsPosible[this.args[i]].Length == ArgLength.Touple) {
if (this.args.Length > i + 1) {
arg.SetData(this.args[++i]);
} else {
Console.WriteLine(this.GetUsageList(""));
throw new ArgumentException("Argument: "+this.args[i]+" missing second argument.");
}
}
this.argList.Add(arg);
}
}
foreach(KeyValuePair<String, VaildArguments> item in this.argsPosible) {
if(!this.HasArgumentType(item.Key) && item.Value.Length == ArgLength.Touple && item.Value.Default != "") {
this.argList.Add(new ArgTouple(item.Key, item.Value.Default));
}
}
}
/// <summary>
/// Menge der angegebenen Komandozeilen-Argumente
/// </summary>
/// <returns>Menge</returns>
public Int32 GetArgsLength() => this.argList.Count;
/// <summary>
/// Gibt zurück ob ein Argument angegeben wurde
/// </summary>
/// <param name="name">Name des Arguments</param>
/// <returns>true wenn angegeben</returns>
public Boolean HasArgumentType(String name)
{
foreach (ArgTouple t in this.argList) {
if (t.Type == name) {
return true;
}
}
return false;
}
/// <summary>
/// Gibt den Inhalt des angegeben Arguments zurück, nur bei zweiteiligen Argumenten möglich
/// </summary>
/// <param name="name">Name des Arguments</param>
/// <returns>Inhalt des Arguments oder ArgumentNullException</returns>
public String GetArgumentData(String name)
{
foreach (ArgTouple t in this.argList) {
if (t.Type == name && t.Data != null) {
return t.Data;
}
}
throw new ArgumentNullException();
}
public Boolean HasAllRequiredArguments()
{
foreach (KeyValuePair<String, VaildArguments> item in this.argsPosible) {
if (item.Value.Required && !this.HasArgumentType(item.Key)) {
return false;
}
}
return true;
}
public String GetUsageList(String name)
{
String ret = "Usage: " + name + " Parameter\nParameter:\n";
String req = "";
String opt = "";
foreach (KeyValuePair<String, VaildArguments> item in this.argsPosible) {
if (item.Value.Required) {
req += item.Key + " " + ((item.Value.Length == ArgLength.Touple) ? (item.Value.Default != "" ? " " + item.Value.Default + "\n" : " [data]\n") : "\n");
}
}
/// <summary>
/// Menge der angegebenen Komandozeilen-Argumente
/// </summary>
/// <returns>Menge</returns>
public Int32 GetArgsLength() => this.argList.Count;
/// <summary>
/// Gibt zurück ob ein Argument angegeben wurde
/// </summary>
/// <param name="name">Name des Arguments</param>
/// <returns>true wenn angegeben</returns>
public Boolean HasArgumentType(String name)
{
foreach (ArgTouple t in this.argList) {
if (t.Type == name) {
return true;
}
}
return false;
}
/// <summary>
/// Gibt den Inhalt des angegeben Arguments zurück, nur bei zweiteiligen Argumenten möglich
/// </summary>
/// <param name="name">Name des Arguments</param>
/// <returns>Inhalt des Arguments oder ArgumentNullException</returns>
public String GetArgumentData(String name)
{
foreach (ArgTouple t in this.argList) {
if (t.Type == name && t.Data != null) {
return t.Data;
}
}
throw new ArgumentNullException();
}
public Boolean HasAllRequiredArguments()
{
foreach (KeyValuePair<String, VaildArguments> item in this.argsPosible) {
if (item.Value.Required && !this.HasArgumentType(item.Key)) {
return false;
}
}
return true;
}
public String GetUsageList(String name)
{
String ret = "Usage: " + name + " Parameter\nParameter:\n";
String req = "";
String opt = "";
foreach (KeyValuePair<String, VaildArguments> item in this.argsPosible) {
if (item.Value.Required) {
req += item.Key + " " + ((item.Value.Length == ArgLength.Touple) ? (item.Value.Default != "" ? " " + item.Value.Default + "\n" : " [data]\n") : "\n");
if(item.Value.Description != "") {
req += "\t" + item.Value.Description + "\n";
}
}
}
if (req != "") {
ret += "Benötigte Parameter:\n" + req;
}
foreach (KeyValuePair<String, VaildArguments> item in this.argsPosible) {
if (!item.Value.Required) {
opt += item.Key + " " + ((item.Value.Length == ArgLength.Touple) ? (item.Value.Default != "" ? " " + item.Value.Default + "\n" : " [data]\n") : "\n");
}
}
}
if (req != "") {
ret += "Benötigte Parameter:\n" + req;
}
foreach (KeyValuePair<String, VaildArguments> item in this.argsPosible) {
if (!item.Value.Required) {
opt += item.Key + " " + ((item.Value.Length == ArgLength.Touple) ? (item.Value.Default != "" ? " " + item.Value.Default + "\n" : " [data]\n") : "\n");
if (item.Value.Description != "") {
opt += "\t" + item.Value.Description + "\n";
}
}
}
if (opt != "") {
ret += "Optionale Parameter:\n" + opt;
}
return ret;
}
}
}
}
}
}
if (opt != "") {
ret += "Optionale Parameter:\n" + opt;
}
return ret;
}
}
}
+3 -1
View File
@@ -23,7 +23,9 @@ namespace BlubbFish.Utils {
public static void SetProperty(this Object o, String name, String value) {
PropertyInfo prop = o.GetType().GetProperty(name);
if (prop.CanWrite) {
if (prop.PropertyType == typeof(Boolean) && Boolean.TryParse(value, out Boolean vb)) {
if(prop.PropertyType == typeof(String)) {
prop.SetValue(o, value);
} else if (prop.PropertyType == typeof(Boolean) && Boolean.TryParse(value, out Boolean vb)) {
prop.SetValue(o, vb);
} else if (prop.PropertyType == typeof(Byte) && Byte.TryParse(value, out Byte v8)) {
prop.SetValue(o, v8);
+5 -9
View File
@@ -31,8 +31,7 @@ namespace BlubbFish.Utils {
return false;
}
private InIReader(String filename)
{
private InIReader(String filename) {
foreach (String path in search_path) {
if (File.Exists(path + Path.DirectorySeparatorChar + filename)) {
this.filename = path + Path.DirectorySeparatorChar + filename;
@@ -60,8 +59,7 @@ namespace BlubbFish.Utils {
/// </summary>
/// <param name="filename">Dateiname</param>
/// <returns></returns>
public static InIReader GetInstance(String filename)
{
public static InIReader GetInstance(String filename) {
if (!instances.Keys.Contains(filename)) {
instances.Add(filename, new InIReader(filename));
}
@@ -70,8 +68,7 @@ namespace BlubbFish.Utils {
private void ReadAgain(Object sender, EventArgs e) => this.LoadFile();
private void LoadFile()
{
private void LoadFile() {
this.inifile = new Dictionary<String, Dictionary<String, String>>();
StreamReader file = new StreamReader(this.filename);
List<String> buf = new List<String>();
@@ -152,12 +149,11 @@ namespace BlubbFish.Utils {
/// <param name="section">Name der Sektion</param>
/// <param name="key">Name des Wertes</param>
/// <returns></returns>
public String GetValue(String section, String key)
{
public String GetValue(String section, String key, String @default = null) {
if (!section.StartsWith("[")) {
section = "[" + section + "]";
}
return this.inifile.Keys.Contains(section) && this.inifile[section].Keys.Contains(key) ? this.inifile[section][key] : null;
return this.inifile.Keys.Contains(section) && this.inifile[section].Keys.Contains(key) ? this.inifile[section][key] : @default;
}
/// <summary>
+168 -143
View File
@@ -1,150 +1,175 @@
using System;
using System.IO;
using System.Text;
namespace BlubbFish.Utils {
public class ProgramLogger {
private FileWriter fw;
private ConsoleWriter stdout;
private ConsoleWriter errout;
private String loggerfile;
public ProgramLogger() {
this.loggerfile = Directory.GetCurrentDirectory() + Path.DirectorySeparatorChar + "output.log";
this.Init(this.loggerfile);
this.AttachToFw();
this.SetOutputs();
}
private void SetOutputs() {
Console.SetOut(this.stdout);
Console.SetError(this.errout);
}
private void Init(String file) {
if(!this.IsWritable(file)) {
Console.Error.WriteLine("Cannot write to " + file);
throw new ArgumentException("Cannot write to " + file);
}
this.fw = new FileWriter(file);
this.stdout = new ConsoleWriter(Console.Out, ConsoleWriterEventArgs.ConsoleType.Info);
this.errout = new ConsoleWriter(Console.Error, ConsoleWriterEventArgs.ConsoleType.Error);
}
private Boolean IsWritable(String filename) {
try {
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
namespace BlubbFish.Utils {
public class ProgramLogger {
private FileWriter fw;
private ConsoleWriter stdout;
private ConsoleWriter errout;
private String loggerfile;
public ProgramLogger(String path = null) {
this.loggerfile = path ?? Directory.GetCurrentDirectory() + Path.DirectorySeparatorChar + "output.log";
this.Init(this.loggerfile);
this.AttachToFw();
this.SetOutputs();
}
private void SetOutputs() {
Console.SetOut(this.stdout);
Console.SetError(this.errout);
}
private void Init(String file) {
if(!this.IsWritable(file)) {
Console.Error.WriteLine("Cannot write to " + file);
throw new ArgumentException("Cannot write to " + file);
}
this.fw = new FileWriter(FileWriter.GetFileSteam(file, false));
this.stdout = new ConsoleWriter(Console.Out, ConsoleWriterEventArgs.ConsoleType.Info);
this.errout = new ConsoleWriter(Console.Error, ConsoleWriterEventArgs.ConsoleType.Error);
}
private Boolean IsWritable(String filename) {
try {
using FileStream fstream = new FileStream(filename, FileMode.Append);
using TextWriter writer = new StreamWriter(fstream);
writer.Write("");
} catch (UnauthorizedAccessException) {
return false;
}
return true;
}
public void SetPath(String file) {
if(file == null) {
return;
}
if (!this.IsWritable(file)) {
Console.Error.WriteLine("Cannot write to " + file);
throw new ArgumentException("Cannot write to " + file);
}
this.DisattachToFw();
this.fw.Close();
if(new FileInfo(this.loggerfile).Length > 0) {
File.Move(this.loggerfile, file);
} else {
File.Delete(this.loggerfile);
}
this.loggerfile = file;
this.fw = new FileWriter(this.loggerfile);
this.AttachToFw();
}
private void DisattachToFw() {
this.stdout.WriteEvent -= this.fw.Write;
this.stdout.WriteLineEvent -= this.fw.WriteLine;
this.errout.WriteEvent -= this.fw.Write;
this.errout.WriteLineEvent -= this.fw.WriteLine;
}
private void AttachToFw() {
this.stdout.WriteEvent += this.fw.Write;
this.stdout.WriteLineEvent += this.fw.WriteLine;
this.errout.WriteEvent += this.fw.Write;
this.errout.WriteLineEvent += this.fw.WriteLine;
}
}
internal class FileWriter : StreamWriter {
private Boolean newline = true;
public FileWriter(String path) : base(path) {
}
writer.Write("");
} catch (UnauthorizedAccessException) {
return false;
}
return true;
}
public void SetPath(String file) {
if(file == null) {
return;
}
if (!this.IsWritable(file)) {
Console.Error.WriteLine("Cannot write to " + file);
throw new ArgumentException("Cannot write to " + file);
}
this.DisattachToFw();
this.fw.Close();
if(new FileInfo(this.loggerfile).Length > 0) {
if(File.Exists(file)) {
this.FileCopy(this.loggerfile, file);
File.Delete(this.loggerfile);
} else {
File.Move(this.loggerfile, file);
}
} else {
File.Delete(this.loggerfile);
}
this.loggerfile = file;
this.fw = new FileWriter(FileWriter.GetFileSteam(this.loggerfile, true));
this.AttachToFw();
}
public void Dispose() {
this.DisattachToFw();
this.fw.Dispose();
}
private void FileCopy(String source, String target) {
using FileStream fread = new FileStream(source, FileMode.Open);
using FileStream fwrite = new FileStream(target, FileMode.Create);
using TextReader reader = new StreamReader(fread);
using TextWriter writer = new StreamWriter(fwrite);
writer.Write(reader.ReadToEnd());
writer.Flush();
writer.Close();
reader.Close();
}
private void DisattachToFw() {
this.stdout.WriteEvent -= this.fw.Write;
this.stdout.WriteLineEvent -= this.fw.WriteLine;
this.errout.WriteEvent -= this.fw.Write;
this.errout.WriteLineEvent -= this.fw.WriteLine;
}
private void AttachToFw() {
this.stdout.WriteEvent += this.fw.Write;
this.stdout.WriteLineEvent += this.fw.WriteLine;
this.errout.WriteEvent += this.fw.Write;
this.errout.WriteLineEvent += this.fw.WriteLine;
}
}
internal class FileWriter : StreamWriter {
private Boolean newline = true;
public FileWriter(FileStream fs) : base(fs) {
}
public static FileStream GetFileSteam(String path, Boolean append) => File.Open(path, append ? FileMode.Append : FileMode.Create, FileAccess.Write, RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ? FileShare.Write : FileShare.ReadWrite);
public override Encoding Encoding => Encoding.UTF8;
public override Boolean AutoFlush { get => true; set => base.AutoFlush = value; }
private void Write(String value, TextWriter origstream, ConsoleWriterEventArgs.ConsoleType type) {
public override Boolean AutoFlush { get => true; set => base.AutoFlush = value; }
private void Write(String value, TextWriter origstream, ConsoleWriterEventArgs.ConsoleType type) {
String text;
if (this.newline) {
text = "[" + DateTime.Now.ToString("o") + "]-" + type.ToString() + ": " + value;
this.newline = false;
} else {
text = value;
}
origstream.Write(text);
base.Write(text);
base.Flush();
}
private void WriteLine(String value, TextWriter origstream, ConsoleWriterEventArgs.ConsoleType type) {
if (this.newline) {
text = "[" + DateTime.Now.ToString("o") + "]-" + type.ToString() + ": " + value;
this.newline = false;
} else {
text = value;
}
origstream.Write(text);
base.Write(text);
base.Flush();
}
private void WriteLine(String value, TextWriter origstream, ConsoleWriterEventArgs.ConsoleType type) {
String text = this.newline ? "[" + DateTime.Now.ToString("o") + "]-" + type.ToString() + ": " + value : value;
this.newline = true;
origstream.WriteLine(text);
base.WriteLine(text);
base.Flush();
}
internal void Write(Object sender, ConsoleWriterEventArgs e) => this.Write(e.Value, e.Writer, e.StreamType);
internal void WriteLine(Object sender, ConsoleWriterEventArgs e) => this.WriteLine(e.Value, e.Writer, e.StreamType);
}
internal class ConsoleWriterEventArgs : EventArgs {
public String Value { get; private set; }
public TextWriter Writer { get; private set; }
public ConsoleType StreamType { get; private set; }
public enum ConsoleType {
Info,
Error
}
public ConsoleWriterEventArgs(String value, TextWriter writer, ConsoleType type) {
this.Value = value;
this.Writer = writer;
this.StreamType = type;
}
}
internal class ConsoleWriter : TextWriter {
private readonly TextWriter stream;
private readonly ConsoleWriterEventArgs.ConsoleType streamtype;
public ConsoleWriter(TextWriter writer, ConsoleWriterEventArgs.ConsoleType type) {
this.stream = writer;
this.streamtype = type;
}
this.newline = true;
origstream.WriteLine(text);
base.WriteLine(text);
base.Flush();
}
internal void Write(Object sender, ConsoleWriterEventArgs e) => this.Write(e.Value, e.Writer, e.StreamType);
internal void WriteLine(Object sender, ConsoleWriterEventArgs e) => this.WriteLine(e.Value, e.Writer, e.StreamType);
}
internal class ConsoleWriterEventArgs : EventArgs {
public String Value { get; private set; }
public TextWriter Writer { get; private set; }
public ConsoleType StreamType { get; private set; }
public enum ConsoleType {
Info,
Error
}
public ConsoleWriterEventArgs(String value, TextWriter writer, ConsoleType type) {
this.Value = value;
this.Writer = writer;
this.StreamType = type;
}
}
internal class ConsoleWriter : TextWriter {
private readonly TextWriter stream;
private readonly ConsoleWriterEventArgs.ConsoleType streamtype;
public ConsoleWriter(TextWriter writer, ConsoleWriterEventArgs.ConsoleType type) {
this.stream = writer;
this.streamtype = type;
}
public override Encoding Encoding => Encoding.UTF8;
public override void Write(String value) => this.WriteEvent?.Invoke(this, new ConsoleWriterEventArgs(value, this.stream, this.streamtype));
//base.Write(value);
public override void WriteLine(String value) => this.WriteLineEvent?.Invoke(this, new ConsoleWriterEventArgs(value, this.stream, this.streamtype));
//base.WriteLine(value);
public event EventHandler<ConsoleWriterEventArgs> WriteEvent;
public event EventHandler<ConsoleWriterEventArgs> WriteLineEvent;
}
}
public override void Write(String value) => this.WriteEvent?.Invoke(this, new ConsoleWriterEventArgs(value, this.stream, this.streamtype));
//base.Write(value);
public override void WriteLine(String value) => this.WriteLineEvent?.Invoke(this, new ConsoleWriterEventArgs(value, this.stream, this.streamtype));
//base.WriteLine(value);
public event EventHandler<ConsoleWriterEventArgs> WriteEvent;
public event EventHandler<ConsoleWriterEventArgs> WriteLineEvent;
}
}
+28 -26
View File
@@ -1,44 +1,46 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<AssemblyName>Utils</AssemblyName>
<RootNamespace>BlubbFish.Utils</RootNamespace>
<Description>Provides useful classes for other projects</Description>
<Company>BlubbFish</Company>
<Authors>BlubbFish</Authors>
<PackageId>Utils.BlubbFish</PackageId>
<Copyright>Copyright © BlubbFish 2014 - 09.01.2022</Copyright>
<Version>1.6.0</Version>
<Copyright>Copyright © BlubbFish 2014 - 30.01.2022</Copyright>
<Version>1.6.2</Version>
<NeutralLanguage>de-DE</NeutralLanguage>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<PackageProjectUrl>http://git.blubbfish.net/vs_utils/Utils</PackageProjectUrl>
<RepositoryUrl>http://git.blubbfish.net/vs_utils/Utils.git</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageReleaseNotes>
1.6.0 HttpEndpoint added
1.5.0 Add GetEvent so you can call events by string; Add OwnSingeton class
1.4.0 Add Helper to Utils
1.1.3 Improve CmdArgs
1.1.2 Tiny Codingstyles
1.1.1 ProgrammLogger neets to cleanup
1.1.0 ProgrammLogger
1.0.7.0 Yet another IniReader improvemnt round again
1.0.6.0 Yet another IniReader improvemnt round
1.0.5.2 And Improve IniReader again
1.0.5.1 Improve IniReader again
1.0.5.0 Improve IniReader
1.0.4.1 Cleanup OwnView
1.0.4.0 More Updater
1.0.3.2 Next Updater
1.0.3.1 EventArgsHelper
1.0.2.6 Better Updater
1.0.2.5 Logging in OwnObject
1.0.2.3 OwnModel better
1.0.2.2 Make it nice
1.0.2.1 Filemutex
1.0.0.1 Filelogger improvements
1.0.0.0 Init
1.6.2 - 2022-01-30 - ProgrammLogger improved
1.6.1 - 2022-01-20 - ProgrammLogger Fixed
1.6.0 - 2022-01-09 - HttpEndpoint added
1.5.0 - 2021-04-10 - Add GetEvent so you can call events by string; Add OwnSingeton class
1.4.0 - 2018-11-27 - Add Helper to Utils
1.1.3 - 2018-10-02 - Improve CmdArgs
1.1.2 - 2018-09-11 - Tiny Codingstyles
1.1.1 - 2018-05-29 - ProgrammLogger neets to cleanup
1.1.0 - 2018-05-15 - ProgrammLogger
1.0.7.0 - 2018-05-08 - Yet another IniReader improvemnt round again
1.0.6.0 - 2017-12-22 - Yet another IniReader improvemnt round
1.0.5.2 - 2017-09-26 - And Improve IniReader again
1.0.5.1 - 2017-09-24 - Improve IniReader again
1.0.5.0 - 2017-08-09 - Improve IniReader
1.0.4.1 - 2017-08-08 - Cleanup OwnView
1.0.4.0 - 2017-04-30 - More Updater
1.0.3.2 - 2017-04-26 - Next Updater
1.0.3.1 - 2017-04-25 - EventArgsHelper
1.0.2.6 - 2017-04-24 - Better Updater
1.0.2.5 - 2017-04-19 - Logging in OwnObject
1.0.2.3 - 2017-04-16 - OwnModel better
1.0.2.2 - 2017-03-09 - Make it nice
1.0.2.1 - 2017-03-09 - Filemutex
1.0.0.1 - 2016-12-03 - Filelogger improvements
1.0.0.0 - 2015-11-16 - Init
</PackageReleaseNotes>
</PropertyGroup>