Browse Source

Merge pull request #113 from vldgeorgiev/master

Yaml fixes
Exilon 2 years ago
parent
commit
6f729e61f1
2 changed files with 1394 additions and 1386 deletions
  1. 302 298
      Quick.Config.YAML.pas
  2. 1092 1088
      Quick.YAML.pas

+ 302 - 298
Quick.Config.YAML.pas

@@ -1,298 +1,302 @@
-{ ***************************************************************************
-
-  Copyright (c) 2015-2019 Kike Pérez
-
-  Unit        : Quick.Config.YAML
-  Description : Save config to YAML file
-  Author      : Kike Pérez
-  Version     : 1.0
-  Created     : 12/04/2019
-  Modified    : 27/04/2019
-
-  This file is part of QuickLib: https://github.com/exilon/QuickLib
-
- ***************************************************************************
-
-  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.
-
- *************************************************************************** }
-
-unit Quick.Config.YAML;
-
-{$i QuickLib.inc}
-
-interface
-
-uses
-  Classes,
-  SysUtils,
-  {$IFDEF DELPHIXE_UP}
-  IOUtils,
-  {$ELSE}
-  Quick.Files,
-  {$ENDIF}
-  Rtti,
-  Quick.YAML.Serializer,
-  Quick.FileMonitor,
-  Quick.Config.Base;
-
-type
-
-  TFileModifiedEvent = procedure of object;
-  TLoadConfigEvent = procedure of object;
-
-  {$IFNDEF FPC}
-  TNotSerializableProperty = Quick.YAML.Serializer.TNotSerializableProperty;
-  TCommentProperty = Quick.YAML.Serializer.TCommentProperty;
-  TCustomNameProperty = Quick.YAML.Serializer.TCustomNameProperty;
-  {$ENDIF}
-
-  TAppConfigYMALProvider = class(TAppConfigProvider)
-  private
-    fFilename : string;
-    fFileMonitor : TFileMonitor;
-    fOnFileModified : TFileModifiedEvent;
-    fLoaded : Boolean;
-    fReloadIfFileChanged : Boolean;
-    fOnConfigLoaded : TLoadConfigEvent;
-    fOnConfigReloaded : TLoadConfigEvent;
-    fNotifyReload : TLoadConfigEvent;
-    procedure CreateFileMonitor;
-    procedure FileModifiedNotify(MonitorNotify : TMonitorNotify);
-    procedure SetFileName(const Value: string);
-    procedure SetReloadIfFileChanged(const Value: Boolean);
-    procedure SetReloadNotify(aNotifyReload : TLoadConfigEvent);
-    procedure DoNofifyReload;
-  protected
-    procedure Load(cConfig : TAppConfig); override;
-    procedure Save(cConfig : TAppConfig); override;
-  public
-    constructor Create(const aFilename : string; aReloadIfFileChanged : Boolean = False); overload;
-    destructor Destroy; override;
-    property Filename : string read fFilename write SetFileName;
-    property ReloadIfFileChanged : Boolean read fReloadIfFileChanged write SetReloadIfFileChanged;
-    property IsLoaded : Boolean read fLoaded;
-    property OnFileModified : TFileModifiedEvent read fOnFileModified write fOnFileModified;
-    property OnConfigLoaded : TLoadConfigEvent read fOnConfigLoaded write fOnConfigLoaded;
-    property OnConfigReloaded : TLoadConfigEvent read fOnConfigReloaded write fOnConfigReloaded;
-  end;
-
-  TAppConfigYAML = class(TAppConfig)
-  private
-    function GetProvider : TAppConfigYMALProvider;
-    procedure ReloadNotify;
-  public
-    constructor Create(const aFilename : string; aReloadIfFileChanged : Boolean = False);
-    destructor Destroy; override;
-    property Provider : TAppConfigYMALProvider read GetProvider;
-    function ToYAML : string;
-    procedure FromYAML(const yaml : string);
-  end;
-
-  {Usage: create a descend class from TAppConfigYAML and add published properties to be loaded/saved
-
-  TMyConfig = class(TAppConfigYAML)
-  private
-    fName : string;
-    fSurname : string;
-    fStatus : Integer;
-  published
-    property Name : string read fName write fName;
-    property SurName : string read fSurname write fSurname;
-    property Status : Integer read fStatus write fStatus;
-  end;
-
-  MyConfig := TMyConfig.Create;
-  MyConfig.Provider.FileName := '.\MyAppName.yml';
-  MyConfig.Name := 'John';
-  MyConfig.Save;
-  }
-
-
-implementation
-
-constructor TAppConfigYMALProvider.Create(const aFilename : string; aReloadIfFileChanged : Boolean = False);
-begin
-  inherited Create;
-  if aFilename = '' then fFilename := TPath.ChangeExtension(ParamStr(0),'yml')
-    else fFilename := aFilename;
-  fLoaded := False;
-  fReloadIfFileChanged := aReloadIfFileChanged;
-  if aReloadIfFileChanged then CreateFileMonitor;
-end;
-
-procedure TAppConfigYMALProvider.CreateFileMonitor;
-begin
-  fFileMonitor := TQuickFileMonitor.Create;
-  fFileMonitor.FileName := fFilename;
-  fFileMonitor.Interval := 2000;
-  fFileMonitor.Notifies := [TMonitorNotify.mnFileModified];
-  fFileMonitor.OnFileChange := FileModifiedNotify;
-  fFileMonitor.Enabled := True;
-end;
-
-destructor TAppConfigYMALProvider.Destroy;
-begin
-  if Assigned(fFileMonitor) then fFileMonitor.Free;
-  inherited;
-end;
-
-procedure TAppConfigYMALProvider.DoNofifyReload;
-begin
-  if Assigned(fNotifyReload) then fNotifyReload
-    else raise EAppConfig.Create('Not config assigned to reload!');
-end;
-
-procedure TAppConfigYMALProvider.FileModifiedNotify(MonitorNotify : TMonitorNotify);
-begin
-  if MonitorNotify = TMonitorNotify.mnFileModified then
-  begin
-    if Assigned(fOnFileModified) then fOnFileModified;
-    if fReloadIfFileChanged then DoNofifyReload;
-  end;
-end;
-
-procedure TAppConfigYMALProvider.Load(cConfig : TAppConfig);
-var
-  yaml : TStrings;
-  serializer : TYamlSerializer;
-begin
-  if (not FileExists(fFilename)) and (CreateIfNotExists) then
-  begin
-    TAppConfig(cConfig).DefaultValues;
-    Self.Save(cConfig);
-  end;
-
-  try
-    yaml := TStringList.Create;
-    try
-      yaml.LoadFromFile(fFilename);
-      serializer := TYamlSerializer.Create(slPublishedProperty,UseEnumNames);
-      try
-        //Streamer.Options := Streamer.Options + [jsoDateTimeAsString ,jsoUseFormatString];
-        //Streamer.DateTimeFormat := 'yyyy-mm-dd"T"hh:mm:ss.zz';
-        serializer.YamlToObject(cConfig,yaml.Text);
-      finally
-        serializer.Free;
-      end;
-    finally
-      yaml.Free;
-    end;
-    if not fLoaded then
-    begin
-      fLoaded := True;
-      if Assigned(fOnConfigLoaded) then fOnConfigLoaded;
-    end
-    else if Assigned(fOnConfigReloaded) then fOnConfigReloaded;
-  except
-    on e : Exception do raise EAppConfig.Create(e.Message);
-  end;
-end;
-
-procedure TAppConfigYMALProvider.Save(cConfig : TAppConfig);
-var
-  yaml : TStrings;
-  Serializer : TYamlSerializer;
-begin
-  if not Assigned(cConfig) then cConfig := TAppConfigYAML.Create(fFilename,fReloadIfFileChanged);
-
-  try
-    yaml := TStringList.Create;
-    try
-      serializer := TYamlSerializer.Create(TSerializeLevel.slPublishedProperty,UseEnumNames);
-      try
-        //Streamer.Options := Streamer.Options + [jsoDateTimeAsString ,jsoUseFormatString];
-        //Streamer.DateTimeFormat := 'yyyy-mm-dd"T"hh:mm:ss.zz';
-        yaml.Text := serializer.ObjectToYaml(cConfig);
-      finally
-        serializer.Free;
-      end;
-      yaml.SaveToFile(fFilename);
-    finally
-      yaml.Free;
-    end;
-  except
-    on e : Exception do raise EAppConfig.Create(e.Message);
-  end;
-end;
-
-
-procedure TAppConfigYMALProvider.SetFileName(const Value: string);
-begin
-  fFilename := Value;
-  if Assigned(fFileMonitor) then fFileMonitor.Free;
-  if fReloadIfFileChanged then CreateFileMonitor;
-end;
-
-procedure TAppConfigYMALProvider.SetReloadIfFileChanged(const Value: Boolean);
-begin
-  if Value = fReloadIfFileChanged then Exit;
-  fReloadIfFileChanged := Value;
-  if Assigned(fFileMonitor) then fFileMonitor.Free;
-  if fReloadIfFileChanged then CreateFileMonitor;
-end;
-
-procedure TAppConfigYMALProvider.SetReloadNotify(aNotifyReload: TLoadConfigEvent);
-begin
-  fNotifyReload := aNotifyReload;
-end;
-
-{ TAppConfigYAML }
-
-constructor TAppConfigYAML.Create(const aFilename : string; aReloadIfFileChanged : Boolean = False);
-begin
-  inherited Create(TAppConfigYMALProvider.Create(aFileName,aReloadIfFileChanged));
-  TAppConfigYMALProvider(fProvider).SetReloadNotify(ReloadNotify);
-end;
-
-destructor TAppConfigYAML.Destroy;
-begin
-  inherited;
-end;
-
-function TAppConfigYAML.GetProvider: TAppConfigYMALProvider;
-begin
-  if not Assigned(fProvider) then raise EAppConfig.Create('No provider assigned!');
-  Result := TAppConfigYMALProvider(fProvider);
-end;
-
-procedure TAppConfigYAML.ReloadNotify;
-begin
-  Self.Load;
-end;
-
-function TAppConfigYAML.ToYAML: string;
-var
-  serializer : TYamlSerializer;
-begin
-  serializer := TYamlSerializer.Create(slPublishedProperty,fProvider.UseEnumNames);
-  try
-    Result := serializer.ObjectToYaml(Self);
-  finally
-    serializer.Free;
-  end;
-end;
-
-procedure TAppConfigYAML.FromYAML(const yaml: string);
-var
-  serializer : TYamlSerializer;
-begin
-  serializer := TYamlSerializer.Create(slPublishedProperty,fProvider.UseEnumNames);
-  try
-    serializer.YamlToObject(Self,yaml);
-  finally
-    serializer.Free;
-  end;
-end;
-
-end.
+{ ***************************************************************************
+
+  Copyright (c) 2015-2019 Kike Pérez
+
+  Unit        : Quick.Config.YAML
+  Description : Save config to YAML file
+  Author      : Kike Pérez
+  Version     : 1.0
+  Created     : 12/04/2019
+  Modified    : 27/04/2019
+
+  This file is part of QuickLib: https://github.com/exilon/QuickLib
+
+ ***************************************************************************
+
+  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.
+
+ *************************************************************************** }
+
+unit Quick.Config.YAML;
+
+{$i QuickLib.inc}
+
+interface
+
+uses
+  Classes,
+  SysUtils,
+  {$IFDEF DELPHIXE_UP}
+  IOUtils,
+  {$ELSE}
+  Quick.Files,
+  {$ENDIF}
+  Rtti,
+  Quick.YAML.Serializer,
+  Quick.FileMonitor,
+  Quick.Config.Base;
+
+type
+
+  TFileModifiedEvent = procedure of object;
+  TLoadConfigEvent = procedure of object;
+
+  {$IFNDEF FPC}
+  TNotSerializableProperty = Quick.YAML.Serializer.TNotSerializableProperty;
+  TCommentProperty = Quick.YAML.Serializer.TCommentProperty;
+  TCustomNameProperty = Quick.YAML.Serializer.TCustomNameProperty;
+  {$ENDIF}
+
+  TAppConfigYMALProvider = class(TAppConfigProvider)
+  private
+    fFilename : string;
+    fFileMonitor : TFileMonitor;
+    fOnFileModified : TFileModifiedEvent;
+    fLoaded : Boolean;
+    fReloadIfFileChanged : Boolean;
+    fOnConfigLoaded : TLoadConfigEvent;
+    fOnConfigReloaded : TLoadConfigEvent;
+    fNotifyReload : TLoadConfigEvent;
+    procedure CreateFileMonitor;
+    procedure FileModifiedNotify(MonitorNotify : TMonitorNotify);
+    procedure SetFileName(const Value: string);
+    procedure SetReloadIfFileChanged(const Value: Boolean);
+    procedure SetReloadNotify(aNotifyReload : TLoadConfigEvent);
+    procedure DoNofifyReload;
+  protected
+    procedure Load(cConfig : TAppConfig); override;
+    procedure Save(cConfig : TAppConfig); override;
+  public
+    constructor Create(const aFilename : string; aReloadIfFileChanged : Boolean = False); overload;
+    destructor Destroy; override;
+    property Filename : string read fFilename write SetFileName;
+    property ReloadIfFileChanged : Boolean read fReloadIfFileChanged write SetReloadIfFileChanged;
+    property IsLoaded : Boolean read fLoaded;
+    property OnFileModified : TFileModifiedEvent read fOnFileModified write fOnFileModified;
+    property OnConfigLoaded : TLoadConfigEvent read fOnConfigLoaded write fOnConfigLoaded;
+    property OnConfigReloaded : TLoadConfigEvent read fOnConfigReloaded write fOnConfigReloaded;
+  end;
+
+  TAppConfigYAML = class(TAppConfig)
+  private
+    function GetProvider : TAppConfigYMALProvider;
+    procedure ReloadNotify;
+  public
+    constructor Create(const aFilename : string; aReloadIfFileChanged : Boolean = False);
+    destructor Destroy; override;
+    property Provider : TAppConfigYMALProvider read GetProvider;
+    function ToYAML : string;
+    procedure FromYAML(const yaml : string);
+  end;
+
+  {Usage: create a descend class from TAppConfigYAML and add published properties to be loaded/saved
+
+  TMyConfig = class(TAppConfigYAML)
+  private
+    fName : string;
+    fSurname : string;
+    fStatus : Integer;
+  published
+    property Name : string read fName write fName;
+    property SurName : string read fSurname write fSurname;
+    property Status : Integer read fStatus write fStatus;
+  end;
+
+  MyConfig := TMyConfig.Create;
+  MyConfig.Provider.FileName := '.\MyAppName.yml';
+  MyConfig.Name := 'John';
+  MyConfig.Save;
+  }
+
+
+implementation
+
+constructor TAppConfigYMALProvider.Create(const aFilename : string; aReloadIfFileChanged : Boolean = False);
+begin
+  inherited Create;
+  if aFilename = '' then fFilename := TPath.ChangeExtension(ParamStr(0),'yml')
+    else fFilename := aFilename;
+  fLoaded := False;
+  fReloadIfFileChanged := aReloadIfFileChanged;
+  if aReloadIfFileChanged then CreateFileMonitor;
+end;
+
+procedure TAppConfigYMALProvider.CreateFileMonitor;
+begin
+  fFileMonitor := TQuickFileMonitor.Create;
+  fFileMonitor.FileName := fFilename;
+  fFileMonitor.Interval := 2000;
+  fFileMonitor.Notifies := [TMonitorNotify.mnFileModified];
+  fFileMonitor.OnFileChange := FileModifiedNotify;
+  fFileMonitor.Enabled := True;
+end;
+
+destructor TAppConfigYMALProvider.Destroy;
+begin
+  if Assigned(fFileMonitor) then fFileMonitor.Free;
+  inherited;
+end;
+
+procedure TAppConfigYMALProvider.DoNofifyReload;
+begin
+  if Assigned(fNotifyReload) then fNotifyReload
+    else raise EAppConfig.Create('Not config assigned to reload!');
+end;
+
+procedure TAppConfigYMALProvider.FileModifiedNotify(MonitorNotify : TMonitorNotify);
+begin
+  if MonitorNotify = TMonitorNotify.mnFileModified then
+  begin
+    if Assigned(fOnFileModified) then fOnFileModified;
+    if fReloadIfFileChanged then DoNofifyReload;
+  end;
+end;
+
+procedure TAppConfigYMALProvider.Load(cConfig : TAppConfig);
+var
+  yaml : TStrings;
+  serializer : TYamlSerializer;
+begin
+  if (not FileExists(fFilename)) and (CreateIfNotExists) then
+  begin
+    TAppConfig(cConfig).DefaultValues;
+    Self.Save(cConfig);
+  end;
+
+  try
+    yaml := TStringList.Create;
+    try
+      yaml.LoadFromFile(fFilename);
+      if yaml.Count > 0 then
+      begin
+        serializer := TYamlSerializer.Create(slPublishedProperty,UseEnumNames);
+        try
+          //Streamer.Options := Streamer.Options + [jsoDateTimeAsString ,jsoUseFormatString];
+          //Streamer.DateTimeFormat := 'yyyy-mm-dd"T"hh:mm:ss.zz';
+          serializer.YamlToObject(cConfig,yaml.Text);
+        finally
+          serializer.Free;
+        end;
+      end else
+        TAppConfig(cConfig).DefaultValues;
+    finally
+      yaml.Free;
+    end;
+    if not fLoaded then
+    begin
+      fLoaded := True;
+      if Assigned(fOnConfigLoaded) then fOnConfigLoaded;
+    end
+    else if Assigned(fOnConfigReloaded) then fOnConfigReloaded;
+  except
+    on e : Exception do raise EAppConfig.Create(e.Message);
+  end;
+end;
+
+procedure TAppConfigYMALProvider.Save(cConfig : TAppConfig);
+var
+  yaml : TStrings;
+  Serializer : TYamlSerializer;
+begin
+  if not Assigned(cConfig) then cConfig := TAppConfigYAML.Create(fFilename,fReloadIfFileChanged);
+
+  try
+    yaml := TStringList.Create;
+    try
+      serializer := TYamlSerializer.Create(TSerializeLevel.slPublishedProperty,UseEnumNames);
+      try
+        //Streamer.Options := Streamer.Options + [jsoDateTimeAsString ,jsoUseFormatString];
+        //Streamer.DateTimeFormat := 'yyyy-mm-dd"T"hh:mm:ss.zz';
+        yaml.Text := serializer.ObjectToYaml(cConfig);
+      finally
+        serializer.Free;
+      end;
+      yaml.SaveToFile(fFilename);
+    finally
+      yaml.Free;
+    end;
+  except
+    on e : Exception do raise EAppConfig.Create(e.Message);
+  end;
+end;
+
+
+procedure TAppConfigYMALProvider.SetFileName(const Value: string);
+begin
+  fFilename := Value;
+  if Assigned(fFileMonitor) then fFileMonitor.Free;
+  if fReloadIfFileChanged then CreateFileMonitor;
+end;
+
+procedure TAppConfigYMALProvider.SetReloadIfFileChanged(const Value: Boolean);
+begin
+  if Value = fReloadIfFileChanged then Exit;
+  fReloadIfFileChanged := Value;
+  if Assigned(fFileMonitor) then fFileMonitor.Free;
+  if fReloadIfFileChanged then CreateFileMonitor;
+end;
+
+procedure TAppConfigYMALProvider.SetReloadNotify(aNotifyReload: TLoadConfigEvent);
+begin
+  fNotifyReload := aNotifyReload;
+end;
+
+{ TAppConfigYAML }
+
+constructor TAppConfigYAML.Create(const aFilename : string; aReloadIfFileChanged : Boolean = False);
+begin
+  inherited Create(TAppConfigYMALProvider.Create(aFileName,aReloadIfFileChanged));
+  TAppConfigYMALProvider(fProvider).SetReloadNotify(ReloadNotify);
+end;
+
+destructor TAppConfigYAML.Destroy;
+begin
+  inherited;
+end;
+
+function TAppConfigYAML.GetProvider: TAppConfigYMALProvider;
+begin
+  if not Assigned(fProvider) then raise EAppConfig.Create('No provider assigned!');
+  Result := TAppConfigYMALProvider(fProvider);
+end;
+
+procedure TAppConfigYAML.ReloadNotify;
+begin
+  Self.Load;
+end;
+
+function TAppConfigYAML.ToYAML: string;
+var
+  serializer : TYamlSerializer;
+begin
+  serializer := TYamlSerializer.Create(slPublishedProperty,fProvider.UseEnumNames);
+  try
+    Result := serializer.ObjectToYaml(Self);
+  finally
+    serializer.Free;
+  end;
+end;
+
+procedure TAppConfigYAML.FromYAML(const yaml: string);
+var
+  serializer : TYamlSerializer;
+begin
+  serializer := TYamlSerializer.Create(slPublishedProperty,fProvider.UseEnumNames);
+  try
+    serializer.YamlToObject(Self,yaml);
+  finally
+    serializer.Free;
+  end;
+end;
+
+end.

+ 1092 - 1088
Quick.YAML.pas

@@ -1,1088 +1,1092 @@
-{ ***************************************************************************
-
-  Copyright (c) 2015-2022 Kike Pérez
-
-  Unit        : Quick.YAML
-  Description : YAML Object parser
-  Author      : Kike Pérez
-  Version     : 1.1
-  Created     : 17/04/2019
-  Modified    : 07/03/2022
-
-  This file is part of QuickLib: https://github.com/exilon/QuickLib
-
- ***************************************************************************
-
-  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.
-
- *************************************************************************** }
-
-unit Quick.YAML;
-
-{$i QuickLib.inc}
-
-interface
-
-uses
-  Classes,
-  SysUtils,
-  Quick.Commons,
-  Generics.Collections,
-  Quick.Value;
-
-type
-  TYamlScalar = TFlexValue;
-
-  TYamlAncestor = class abstract
-  protected
-    fOwned : Boolean;
-    function IsNull : Boolean; virtual;
-    procedure AddDescendant(const aDescendent: TYamlAncestor); virtual;
-  public
-    constructor Create;
-    property Owned : Boolean read fOwned write fOwned;
-    property Null : Boolean read IsNull;
-    function IsScalar : Boolean; virtual;
-  end;
-
-  TYamlValue = class abstract(TYamlAncestor)
-  public
-    function Value : TFlexValue; virtual;
-    function AsString : string; virtual; abstract;
-  end;
-
-  TYamlString = class(TYamlValue)
-  private
-    fValue : string;
-    fIsNull : Boolean;
-  protected
-    function IsNull : Boolean; override;
-  public
-    constructor Create; overload;
-    constructor Create(const aValue : string); overload;
-    function Value : TFlexValue; override;
-    function IsScalar : Boolean; override;
-    function AsString : string; override;
-  end;
-
-  TYamlInteger = class(TYamlValue)
-  private
-    fValue : Integer;
-    fIsNull : Boolean;
-  protected
-    function IsNull : Boolean; override;
-  public
-    constructor Create; overload;
-    constructor Create(const aValue : Integer); overload;
-    function Value : TFlexValue; override;
-    function IsScalar : Boolean; override;
-    function AsString : string; override;
-  end;
-
-  TYamlFloat = class(TYamlValue)
-  private
-    fValue : Double;
-    fIsNull : Boolean;
-  protected
-    function IsNull : Boolean; override;
-  public
-    constructor Create; overload;
-    constructor Create(const aValue : Double); overload;
-    function Value : TFlexValue; override;
-    function IsScalar : Boolean; override;
-    function AsString : string; override;
-  end;
-
-  TYamlBoolean = class(TYamlValue)
-  private
-    fValue : Boolean;
-    fIsNull : Boolean;
-  protected
-    function IsNull : Boolean; override;
-  public
-    constructor Create; overload;
-    constructor Create(const aValue : Boolean); overload;
-    function Value : TFlexValue; override;
-    function IsScalar : Boolean; override;
-    function AsString : string; override;
-  end;
-
-  TYamlNull = class(TYamlValue)
-  protected
-    function IsNull: Boolean; override;
-  public
-    function Value : TFlexValue; override;
-    function AsString : string; override;
-  end;
-
-  TYamlComment = class(TYamlValue)
-  private
-    fValue : string;
-    fIsNull : Boolean;
-  protected
-    function IsNull : Boolean; override;
-  public
-    constructor Create; overload;
-    constructor Create(const aComment : string); overload;
-    function Value : TFlexValue; override;
-    function IsScalar : Boolean; override;
-    function AsString : string; override;
-  end;
-
-  TYamlPair = class(TYamlAncestor)
-  private
-    fName : string;
-    fValue : TYamlValue;
-  protected
-    procedure AddDescendant(const aDescendent: TYamlAncestor); override;
-  public
-    constructor Create(const aName : string; const aValue : TYamlValue); overload;
-    constructor Create(const aName : string; const aValue : string); overload;
-    constructor Create(const aName : string; const aValue : Integer); overload;
-    constructor Create(const aName : string; const aValue : Double); overload;
-    destructor Destroy; override;
-    property Name : string read fName write fName;
-    property Value : TYamlValue read fValue write fValue;
-    function ToYaml : string;
-  end;
-
-  TYamlWriter = class
-  private
-    fData : string;
-  public
-    constructor Create;
-    property Text : string read fData;
-    procedure Write(const aValue : string);
-    procedure Writeln(const aValue : string);
-  end;
-
-  TYamlObject = class(TYamlValue)
-  public type
-    TEnumerator = class
-    private
-      fIndex: Integer;
-      fObject: TYamlObject;
-    public
-      constructor Create(const aObject: TYamlObject);
-      function GetCurrent: TYamlPair; inline;
-      function MoveNext: Boolean; inline;
-      property Current: TYamlPair read GetCurrent;
-    end;
-  private
-    fMembers : TList<TYamlPair>;
-    function GetCount : Integer;
-    class function ParseValue(yaml : TList<string>; var vIndex : Integer): TYamlAncestor;
-    class function ParsePairName(const aPair : string) : string;
-    class function ParsePairValue(const aPair : string) : string;
-    class function ParseArrayValue(const aValue : string) : TYamlValue;
-    class function GetItemLevel(const aValue : string) : Integer;
-    function ParseToYaml(aIndent : Integer) : string;
-  protected
-    procedure AddDescendant(const aDescendent: TYamlAncestor); override;
-  public
-    constructor Create; overload;
-    constructor Create(const aData : string); overload;
-    destructor Destroy; override;
-    function GetValue(const aName: string): TYamlValue;
-    property Values[const aName: string] : TYamlValue read GetValue;
-    procedure ParseYaml(const aData : string);
-    property Count : Integer read GetCount;
-    class function ParseYamlValue(const aData : string) : TYamlAncestor;
-    function GetPair(const aIndex : Integer) : TYamlPair;
-    function GetPairByName(const aPairName : string) : TYamlPair;
-    function AddPair(const aPair : TYamlPair): TYamlObject; overload;
-    function AddPair(const aName : string; const aValue : TYamlValue): TYamlObject; overload;
-    function AddPair(const aName : string; const aValue : string): TYamlObject; overload;
-    function RemovePair(const aPairName: string): TYamlPair;
-    function GetEnumerator: TEnumerator; inline;
-    property Pairs[const aIndex: Integer]: TYamlPair read GetPair;
-    function ToYaml : string;
-    function AsString : string; override;
-  end;
-
-  { TYamlArray }
-
-  TYamlArray = class(TYamlValue)
-  public type
-    TEnumerator = class
-    private
-      fIndex : Integer;
-      fArray : TYamlArray;
-    public
-      constructor Create(const aArray: TYamlArray);
-      function GetCurrent: TYamlValue; inline;
-      function MoveNext: Boolean; inline;
-      property Current: TYamlValue read GetCurrent;
-    end;
-  private
-    fElements: TList<TYamlValue>;
-    function ParseToYaml(aIndent : Integer; var vIsScalar : Boolean) : string;
-  protected
-    procedure AddDescendant(const aDescendant: TYamlAncestor); override;
-    function GetCount: Integer; inline;
-    function GetValue(const aIndex: Integer): TYamlValue; overload; inline;
-  public
-    constructor Create; overload;
-    constructor Create(const aFirstElem: TYamlValue); overload;
-    destructor Destroy; override;
-    property Count: Integer read GetCount;
-    property Items[const aIndex: Integer]: TYamlValue read GetValue;
-    procedure AddElement(const aElement: TYamlValue);
-    function GetEnumerator: TEnumerator; inline;
-    function AsString : string; override;
-  end;
-
-  EYAMLException = class(Exception);
-
-implementation
-
-const
-  NUM_INDENT = 2;
-
-{ TYamlAncestor }
-
-procedure TYamlAncestor.AddDescendant(const aDescendent: TYamlAncestor);
-begin
-  raise EYAMLException.CreateFmt('Cannot add value %s to %s',[aDescendent.ClassName,ClassName]);
-end;
-
-constructor TYamlAncestor.Create;
-begin
-  inherited Create;
-  fOwned := True;
-end;
-
-function TYamlAncestor.IsNull: Boolean;
-begin
-  Result := False;
-end;
-
-function TYamlAncestor.IsScalar: Boolean;
-begin
-  Result := False;
-end;
-
-{ TYamlObject }
-
-function TYamlObject.AddPair(const aPair: TYamlPair): TYamlObject;
-begin
-  if aPair <> nil then AddDescendant(aPair);
-  Result := Self;
-end;
-
-function TYamlObject.AddPair(const aName: string; const aValue: TYamlValue): TYamlObject;
-begin
-  if (not aName.IsEmpty) and (aValue <> nil) then AddPair(TYamlPair.Create(aName,aValue));
-  Result := Self;
-end;
-
-procedure TYamlObject.AddDescendant(const aDescendent: TYamlAncestor);
-begin
-  if aDescendent <> nil then fMembers.Add(TYamlPair(aDescendent));
-end;
-
-function TYamlObject.AddPair(const aName, aValue: string): TYamlObject;
-begin
-  if not aName.IsEmpty and (not aValue.IsEmpty) then AddPair(TYamlPair.Create(aName,aValue));
-  Result := Self;
-end;
-
-function TYamlObject.AsString: string;
-begin
-  Result := ToYaml;
-end;
-
-constructor TYamlObject.Create(const aData: string);
-begin
-  inherited Create;
-  ParseYaml(aData);
-end;
-
-constructor TYamlObject.Create;
-begin
-  inherited Create;
-  fMembers := TList<TYamlPair>.Create;
-end;
-
-destructor TYamlObject.Destroy;
-var
-  member: TYamlAncestor;
-  i: Integer;
-begin
-  if Assigned(fMembers) then
-  for i := 0 to fMembers.Count - 1 do
-  begin
-    {$IFNDEF FPC}
-    member := fMembers.List[i];
-    {$ELSE}
-    member := fMembers.Items[i];
-    {$ENDIF}
-    if Assigned(member) and member.Owned then member.Free;
-  end;
-  FreeAndNil(fMembers);
-  inherited;
-end;
-
-function TYamlObject.GetCount: Integer;
-begin
-  Result := fMembers.Count;
-end;
-
-function TYamlObject.GetEnumerator: TEnumerator;
-begin
-  Result := TEnumerator.Create(Self);
-end;
-
-class function TYamlObject.GetItemLevel(const aValue: string): Integer;
-var
-  i : Integer;
-  trimed : string;
-begin
-  trimed := aValue.Trim;
-  if trimed.IsEmpty or trimed.StartsWith('#') then Exit(99999);
-
-  for i := Low(aValue) to aValue.Length do
-  begin
-    if aValue[i] <> ' ' then Exit(i);
-  end;
-  Result := Low(aValue);
-end;
-
-function TYamlObject.GetPair(const aIndex: Integer): TYamlPair;
-begin
-  Result := fMembers[aIndex];
-end;
-
-function TYamlObject.GetPairByName(const aPairName: string): TYamlPair;
-var
-  yamlpair : TYamlPair;
-  I: Integer;
-begin
-  for i := 0 to Count - 1 do
-  begin
-    {$IFNDEF FPC}
-    yamlpair := fMembers.List[i];
-    {$ELSE}
-    yamlpair := fMembers.Items[i];
-    {$ENDIF}
-    if CompareText(yamlpair.Name,aPairName) = 0 then Exit(yamlpair);
-  end;
-  Result := nil;
-end;
-
-function TYamlObject.GetValue(const aName: string): TYamlValue;
-var
-  ymlpair: TYamlPair;
-  i: Integer;
-begin
-  for i := 0 to Count - 1 do
-  begin
-    {$IFNDEF FPC}
-    ymlpair := fMembers.List[i];
-    {$ELSE}
-    ymlpair := fMembers.Items[i];
-    {$ENDIF}
-    if CompareText(ymlpair.Name,aName) = 0 then Exit(ymlpair.Value);
-  end;
-  Result := nil;
-end;
-
-class function TYamlObject.ParseArrayValue(const aValue: string): TYamlValue;
-var
-  nint : Int64;
-  nfloat : Double;
-begin
-  if TryStrToInt64(aValue,nint) then Result := TYamlInteger.Create(nint)
-  else if TryStrToFloat(aValue,nfloat) then Result := TYamlFloat.Create(nfloat)
-  else Result := TYamlString.Create(aValue);
-end;
-
-class function TYamlObject.ParsePairName(const aPair: string): string;
-begin
-  Result := Copy(aPair,0,aPair.IndexOf(':'));
-end;
-
-class function TYamlObject.ParsePairValue(const aPair: string): string;
-begin
-  Result := Copy(aPair,aPair.IndexOf(':')+2,aPair.Length).Trim;
-end;
-
-class function TYamlObject.ParseValue(yaml : TList<string>; var vIndex : Integer): TYamlAncestor;
-type
-  TYamlType = (ytObject, ytArray, ytScalarArray, ytScalar);
-var
-  name : string;
-  value : string;
-  yvalue : TYamlAncestor;
-  level : Integer;
-  nextlevel : Integer;
-  aitem : string;
-  yamlType : TYamlType;
-begin
-  Result := nil;
-  level := 0;
-  while yaml.Count > vIndex do
-  begin
-    value := yaml[vIndex].Trim;
-
-    name := ParsePairName(value);
-    if (name.IsEmpty) or (value.IsEmpty) or (value.StartsWith('#')) or (value.StartsWith(#9)) then Exit(nil)
-    //else if value.StartsWith('#') then Exit(TYamlComment.Create(value))
-    else if value.StartsWith('-') then
-    begin
-      yaml[vIndex] := StringReplace(yaml[vIndex],'-','',[]).TrimLeft;
-      yamlType := ytObject;
-      Dec(vIndex);
-    end
-    else if value.EndsWith(':') then
-    begin
-      if yaml[vIndex + 1].TrimLeft.StartsWith('-') then yamlType := ytArray
-        else yamlType := ytObject;
-    end
-    else if value.IndexOf(':') < value.Length then
-    begin
-      value := ParsePairValue(value);
-      if (value.StartsWith('[')) and (value.EndsWith(']')) then yamlType := ytScalarArray
-        else yamlType := ytScalar;
-    end
-    else yamlType := TYamlType.ytScalar;
-
-    case yamlType of
-      ytArray : //is array
-        begin
-          yvalue := TYamlArray.Create;
-          level := GetItemLevel(yaml[vIndex + 1]);
-          repeat
-            Inc(vIndex);
-            yvalue.AddDescendant(ParseValue(yaml,vIndex));
-          until (yvalue = nil) or (vIndex >= yaml.Count - 1) or (GetItemLevel(yaml[vIndex + 1]) < level);
-          Exit(TYamlPair.Create(name,TYamlValue(yvalue)));
-        end;
-      ytObject : //is object
-        begin
-          yvalue := TYamlObject.Create;
-          repeat
-            Inc(vIndex);
-            nextlevel := GetItemLevel(yaml[vIndex]);
-            if nextlevel <> 99999 then level := nextlevel;
-
-            yvalue.AddDescendant(ParseValue(yaml,vIndex));
-            //level := GetItemLevel(yaml[vIndex]);
-            //var level2 := GetItemLevel(yaml[offset + 1]);
-          until (yvalue = nil) or (vIndex >= yaml.Count - 1) or (GetItemLevel(yaml[vIndex + 1]) < level);
-          Exit(TYamlPair.Create(name,TYamlValue(yvalue)));
-        end;
-      ytScalarArray : //is scalar array
-        begin
-          yvalue := TYamlArray.Create;
-          value := StringReplace(Copy(value,2,Value.Length-2),', ',#9,[rfReplaceAll]);
-          for aitem in value.Split([#9]) do
-          begin
-            yvalue.AddDescendant(ParseArrayValue(aitem));
-          end;
-          Exit(TYamlPair.Create(name,TYamlValue(yvalue)));
-        end;
-    else Exit(TYamlPair.Create(name,value)); //is scalar
-    end;
-    Inc(vIndex);
-  end;
-end;
-
-procedure TYamlObject.ParseYaml(const aData: string);
-var
-  yaml : TList<string>;
-  line : string;
-  data : string;
-  yamlvalue : TYamlAncestor;
-  vIndex : Integer;
-begin
-  yaml := TList<string>.Create;
-  try
-    vIndex := 0;
-    //normalize tabs
-    data := StringReplace(aData,#9,Spaces(NUM_INDENT),[rfReplaceAll]);
-    {$IFNDEF LINUX}
-    for line in data.Split([#13]) do yaml.Add(StringReplace(line,#10,'',[rfReplaceAll]));
-    {$ELSE}
-    for line in data.Split([#10]) do yaml.Add(StringReplace(line,#13,'',[rfReplaceAll]));
-    {$ENDIF}
-    while yaml.Count > vIndex do
-    begin
-      yamlvalue := ParseValue(yaml,vIndex);
-      if yamlvalue <> nil then AddDescendant(yamlvalue);
-      Inc(vIndex);
-    end;
-  finally
-    yaml.Free;
-  end;
-end;
-
-class function TYamlObject.ParseYamlValue(const aData : string) : TYamlAncestor;
-var
-  yaml : TList<string>;
-  line : string;
-  data : string;
-  yamlvalue : TYamlAncestor;
-  vIndex : Integer;
-begin
-  yaml := TList<string>.Create;
-  try
-    vIndex := 0;
-    //normalize tabs
-    data := StringReplace(aData,#9,Spaces(NUM_INDENT),[rfReplaceAll]);
-    {$IFNDEF LINUX}
-    for line in data.Split([#13]) do yaml.Add(StringReplace(line,#10,'',[rfReplaceAll]));
-    {$ELSE}
-    for line in data.Split([#10]) do yaml.Add(StringReplace(line,#13,'',[rfReplaceAll]));
-    {$ENDIF}
-    if yaml[0].TrimLeft.StartsWith('- ') then Result := TYamlArray.Create
-      else Result := TYamlObject.Create;
-    while yaml.Count > vIndex do
-    begin
-      yamlvalue := ParseValue(yaml,vIndex);
-      if yamlvalue <> nil then Result.AddDescendant(yamlvalue);
-      Inc(vIndex);
-    end;
-  finally
-    yaml.Free;
-  end;
-end;
-
-function TYamlObject.RemovePair(const aPairName: string): TYamlPair;
-var
-  yamlpair: TYamlPair;
-  i: Integer;
-begin
-  for i := 0 to Count - 1 do
-  begin
-    {$IFNDEF FPC}
-    yamlpair := TYamlPair(FMembers.List[i]);
-    {$ELSE}
-    yamlpair := TYamlPair(fMembers.Items[i]);
-    {$ENDIF}
-    if CompareText(yamlpair.Name,aPairName) = 0 then
-    begin
-      fMembers.Remove(yamlpair);
-      Exit(yamlpair);
-    end;
-  end;
-  Result := nil;
-end;
-
-function TYamlObject.ToYaml: string;
-begin
-  Result := ParseToYaml(0);
-end;
-
-function TYamlObject.ParseToYaml(aIndent : Integer) : string;
-var
-  i : Integer;
-  member : TYamlPair;
-  yaml : TYamlWriter;
-  yvalue : TYamlAncestor;
-  indent : string;
-  isscalar : Boolean;
-  scalar : string;
-  rarray : string;
-begin
-  yaml := TYamlWriter.Create;
-  try
-    indent := StringOfChar(' ',aIndent);
-    for i := 0 to fMembers.Count - 1 do
-    begin
-      member := fMembers[i];
-      if member = nil then continue;
-
-      yvalue := member.Value;
-      if (yvalue.IsScalar) or (yvalue is TYamlNull) then
-      begin
-        if yvalue is TYamlComment then yaml.Writeln(Format('#%s%s',[indent,TYamlComment(member.Value).AsString]))
-        else
-        begin
-          if yvalue is TYamlNull then scalar := 'null'
-          else if (yvalue is TYamlFloat) or (yvalue is TYamlBoolean) then scalar := member.Value.AsString
-            else scalar := member.Value.Value.AsString;
-          if scalar.IsEmpty then scalar := '""';
-          yaml.Writeln(Format('%s%s: %s',[indent,member.Name,scalar]));
-          if (i < fMembers.Count - 1) and (fMembers[i+1].Value is TYamlComment) then yaml.Writeln('');
-        end;
-      end
-      else if (yvalue is TYamlObject) then
-      begin
-        yaml.Writeln(Format('%s%s:',[indent,member.Name]));
-        yaml.Write((yvalue as TYamlObject).ParseToYaml(aIndent + NUM_INDENT));
-        if aIndent = 0 then yaml.Writeln('');
-      end
-      else if (yvalue is TYamlArray) then
-      begin
-        isscalar := False;
-        rarray := (yvalue as TYamlArray).ParseToYaml(aIndent + NUM_INDENT,isscalar);
-        if isscalar then yaml.Writeln(Format('%s%s: %s',[indent,member.Name,rarray]))
-        else
-        begin
-          yaml.Writeln(Format('%s%s:',[indent,member.Name]));
-          yaml.Write(rarray);
-        end;
-      end;
-    end;
-    Result := yaml.Text;
-  finally
-    yaml.Free;
-  end;
-end;
-
-{ TYamlString }
-
-constructor TYamlString.Create(const aValue: string);
-begin
-  inherited Create;
-  fValue := aValue;
-  fIsNull := False;
-end;
-
-constructor TYamlString.Create;
-begin
-  inherited Create;
-  fIsNull := True;
-end;
-
-function TYamlString.IsNull: Boolean;
-begin
-  Result := fIsNull;
-end;
-
-function TYamlString.IsScalar: Boolean;
-begin
-  Result := True;
-end;
-
-function TYamlString.AsString: string;
-begin
-  Result := fValue;
-end;
-
-function TYamlString.Value: TFlexValue;
-begin
-  Result := fValue;
-end;
-
-{ TYamlInteger }
-
-constructor TYamlInteger.Create(const aValue: Integer);
-begin
-  inherited Create;
-  fValue := aValue;
-  fIsNull := False;
-end;
-
-constructor TYamlInteger.Create;
-begin
-  inherited Create;
-  fIsNull := True;
-end;
-
-function TYamlInteger.IsNull: Boolean;
-begin
-  Result := fIsNull;
-end;
-
-function TYamlInteger.IsScalar: Boolean;
-begin
-  Result := True;
-end;
-
-function TYamlInteger.AsString: string;
-begin
-  Result := IntToStr(fValue);
-end;
-
-function TYamlInteger.Value: TFlexValue;
-begin
-  Result := fValue;
-end;
-
-{ TYamlFloat }
-
-constructor TYamlFloat.Create(const aValue: Double);
-begin
-  inherited Create;
-  fValue := aValue;
-  fIsNull := False;
-end;
-
-constructor TYamlFloat.Create;
-begin
-  inherited Create;
-  fIsNull := True;
-end;
-
-function TYamlFloat.IsNull: Boolean;
-begin
-  Result := fIsNull;
-end;
-
-function TYamlFloat.IsScalar: Boolean;
-begin
-  Result := True;
-end;
-
-function TYamlFloat.AsString: string;
-begin
-  Result := FloatToStr(fValue);
-end;
-
-function TYamlFloat.Value: TFlexValue;
-begin
-  Result := fValue;
-end;
-
-{ TYamlPair }
-
-constructor TYamlPair.Create(const aName: string; const aValue: TYamlValue);
-begin
-  inherited Create;
-  fName := aName;
-  fValue := aValue;
-end;
-
-constructor TYamlPair.Create(const aName, aValue: string);
-begin
-  inherited Create;
-  fName := aName;
-  fValue := TYamlString.Create(aValue);
-end;
-
-constructor TYamlPair.Create(const aName: string; const aValue: Double);
-begin
-  inherited Create;
-  fName := aName;
-  fValue := TYamlFloat.Create(aValue);
-end;
-
-constructor TYamlPair.Create(const aName: string; const aValue: Integer);
-begin
-  inherited Create;
-  fName := aName;
-  fValue := TYamlInteger.Create(aValue);
-end;
-
-destructor TYamlPair.Destroy;
-begin
-  if (fValue <> nil) and fValue.Owned then FreeAndNil(fValue);
-  inherited Destroy;
-end;
-
-function TYamlPair.ToYaml: string;
-var
-  isscalar : Boolean;
-begin
-  if fValue = nil then Exit('null');
-
-  if fValue is TYamlObject then Result := TYamlObject(fValue).ToYaml
-    else if fValue is TYamlArray then Result := TYamlArray(fValue).ParseToYaml(0,isscalar)
-      else Result := Format('%s: %s',[fName,fValue.Value.AsString]);
-
-end;
-
-procedure TYamlPair.AddDescendant(const aDescendent: TYamlAncestor);
-begin
-  if fName = '' then
-    fName := TYamlString(aDescendent).Value
-  else if fValue = nil then
-    fValue:= TYamlValue(aDescendent)
-  else inherited AddDescendant(aDescendent);
-end;
-
-{ TYamlObject.TEnumerator }
-
-constructor TYamlObject.TEnumerator.Create(const aObject: TYamlObject);
-begin
-  inherited Create;
-  fIndex := -1;
-  fObject := aObject;
-end;
-
-function TYamlObject.TEnumerator.GetCurrent: TYamlPair;
-begin
-  {$IFNDEF FPC}
-  Result := fObject.fMembers.List[fIndex];
-  {$ELSE}
-  Result := fObject.fMembers.Items[fIndex];
-  {$ENDIF}
-end;
-
-function TYamlObject.TEnumerator.MoveNext: Boolean;
-begin
-  Inc(fIndex);
-  Result := fIndex < fObject.Count;
-end;
-
-
-{ TYamlValue }
-
-function TYamlValue.Value: TFlexValue;
-begin
-  Result := '';
-end;
-
-{ TYamlArray.TEnumerator }
-
-constructor TYamlArray.TEnumerator.Create(const aArray: TYamlArray);
-begin
-  inherited Create;
-  fIndex := -1;
-  fArray := aArray;
-end;
-
-function TYamlArray.TEnumerator.GetCurrent: TYamlValue;
-begin
-  {$IFNDEF FPC}
-  Result := fArray.fElements.List[fIndex];
-  {$ELSE}
-  Result := fArray.fElements.Items[fIndex];
-  {$ENDIF}
-end;
-
-function TYamlArray.TEnumerator.MoveNext: Boolean;
-begin
-  Inc(fIndex);
-  Result := fIndex < fArray.Count;
-end;
-
-{ TYamlArray }
-
-procedure TYamlArray.AddDescendant(const aDescendant: TYamlAncestor);
-begin
-  fElements.Add(TYamlValue(aDescendant));
-end;
-
-constructor TYamlArray.Create;
-begin
-  inherited Create;
-  fElements := TList<TYamlValue>.Create;
-end;
-
-constructor TYamlArray.Create(const aFirstElem: TYamlValue);
-begin
-  inherited Create;
-  AddElement(aFirstElem);
-end;
-
-procedure TYamlArray.AddElement(const aElement: TYamlValue);
-begin
-  if aElement <> nil then AddDescendant(aElement);
-end;
-
-function TYamlArray.AsString: string;
-var
-  first : Boolean;
-  element : TYamlValue;
-begin
-  first := True;
-  for element in fElements do
-  begin
-    if first then Result := Result + element.AsString
-      else  Result := Result + ',' + element.AsString;
-  end;
-  Result := Format('[%s]',[Result]);
-end;
-
-destructor TYamlArray.Destroy;
-var
-  element: TYamlAncestor;
-  i: Integer;
-begin
-  if Assigned(fElements) then
-  for i := 0 to fElements.Count - 1 do
-  begin
-    element := fElements[i];
-    if Assigned(element) and (element.Owned) then element.Free;
-  end;
-  if Assigned(fElements) then FreeAndNil(fElements);
-  inherited Destroy;
-end;
-
-function TYamlArray.GetCount: Integer;
-begin
-  Result := fElements.Count;
-end;
-
-function TYamlArray.GetEnumerator: TEnumerator;
-begin
-  Result := TEnumerator.Create(Self);
-end;
-
-function TYamlArray.GetValue(const aIndex: Integer): TYamlValue;
-begin
-  Result := fElements[aIndex];
-end;
-
-function TYamlArray.ParseToYaml(aIndent : Integer; var vIsScalar : Boolean) : string;
-var
-  element : TYamlValue;
-  yaml : TYamlWriter;
-  yvalue : TYamlAncestor;
-  indent : string;
-  isscalar : Boolean;
-begin
-  Result := '';
-  yvalue := nil;
-  yaml := TYamlWriter.Create;
-  try
-    indent := StringOfChar(' ',aIndent);
-    if fElements.Count = 0 then
-    begin
-      vIsScalar := True;
-      Exit('[]');
-    end;
-    for element in fElements do
-    begin
-      yvalue := element;
-      if yvalue is TYamlPair then yvalue := TYamlPair(yvalue).value;
-
-      if yvalue.IsScalar then
-      begin
-        {$IFNDEF FPC}
-        if Result = '' then Result := element.AsString
-          else Result := Result + ', ' + element.AsString;
-        {$ELSE}
-        if Result = '' then Result := TYamlPair(element).Value.AsString
-          else Result := Result + ', ' + TYamlPair(element).Value.AsString;
-        {$ENDIF}
-      end
-      else if (yvalue is TYamlObject) then
-      begin
-        yaml.Write(indent + '- ' + (yvalue as TYamlObject).ParseToYaml(aIndent + NUM_INDENT).TrimLeft);
-      end
-      else if (yvalue is TYamlArray) then
-      begin
-        yaml.Write(Format('%s%s',[indent,(yvalue as TYamlArray).ParseToYaml(aIndent + NUM_INDENT,isscalar)]))
-      end;
-      yaml.Writeln('');
-    end;
-    if (yvalue <> nil) and (yvalue.IsScalar) then
-    begin
-      Result := '[' + Result + ']';
-      vIsScalar := True;
-    end
-    else Result := yaml.Text;
-  finally
-    yaml.Free;
-  end;
-end;
-
-{ TYamlWriter }
-
-procedure TYamlWriter.Write(const aValue: string);
-begin
-  fData := fData + aValue;
-end;
-
-procedure TYamlWriter.Writeln(const aValue: string);
-begin
-  fData := fData + aValue + CRLF;
-end;
-
-constructor TYamlWriter.Create;
-begin
-  fData := '';
-end;
-
-{ TYamlNull }
-
-function TYamlNull.IsNull: Boolean;
-begin
-  Result := True;
-end;
-
-function TYamlNull.AsString: string;
-begin
-  Result := 'null';
-end;
-
-function TYamlNull.Value: TFlexValue;
-begin
-  Result := nil;
-end;
-
-{ TYamlBoolean }
-
-constructor TYamlBoolean.Create;
-begin
-  inherited Create;
-  fIsNull := True;
-end;
-
-constructor TYamlBoolean.Create(const aValue: Boolean);
-begin
-  inherited Create;
-  fIsNull := False;
-  fValue := aValue;
-end;
-
-function TYamlBoolean.IsNull: Boolean;
-begin
-  Result := fIsNull;
-end;
-
-function TYamlBoolean.IsScalar: Boolean;
-begin
-  Result := True;
-end;
-
-function TYamlBoolean.AsString: string;
-begin
-  Result := BoolToStr(fValue,True).ToLower;
-end;
-
-function TYamlBoolean.Value: TFlexValue;
-begin
-  Result := fValue;
-end;
-
-{ TYamlComment }
-
-function TYamlComment.AsString: string;
-begin
-  Result := fValue;
-end;
-
-constructor TYamlComment.Create;
-begin
-  inherited Create;
-  fIsNull := True;
-end;
-
-constructor TYamlComment.Create(const aComment: string);
-begin
-  inherited Create;
-  fIsNull := False;
-  fValue := aComment;
-end;
-
-function TYamlComment.IsNull: Boolean;
-begin
-  Result := fIsNull;
-end;
-
-function TYamlComment.IsScalar: Boolean;
-begin
-  Result := True;
-end;
-
-function TYamlComment.Value: TFlexValue;
-begin
-
-end;
-
-end.
+{ ***************************************************************************
+
+  Copyright (c) 2015-2022 Kike P�rez
+
+  Unit        : Quick.YAML
+  Description : YAML Object parser
+  Author      : Kike P�rez
+  Version     : 1.1
+  Created     : 17/04/2019
+  Modified    : 07/03/2022
+
+  This file is part of QuickLib: https://github.com/exilon/QuickLib
+
+ ***************************************************************************
+
+  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.
+
+ *************************************************************************** }
+
+unit Quick.YAML;
+
+{$i QuickLib.inc}
+
+interface
+
+uses
+  Classes,
+  SysUtils,
+  Quick.Commons,
+  Generics.Collections,
+  Quick.Value;
+
+type
+  TYamlScalar = TFlexValue;
+
+  TYamlAncestor = class abstract
+  protected
+    fOwned : Boolean;
+    function IsNull : Boolean; virtual;
+    procedure AddDescendant(const aDescendent: TYamlAncestor); virtual;
+  public
+    constructor Create;
+    property Owned : Boolean read fOwned write fOwned;
+    property Null : Boolean read IsNull;
+    function IsScalar : Boolean; virtual;
+  end;
+
+  TYamlValue = class abstract(TYamlAncestor)
+  public
+    function Value : TFlexValue; virtual;
+    function AsString : string; virtual; abstract;
+  end;
+
+  TYamlString = class(TYamlValue)
+  private
+    fValue : string;
+    fIsNull : Boolean;
+  protected
+    function IsNull : Boolean; override;
+  public
+    constructor Create; overload;
+    constructor Create(const aValue : string); overload;
+    function Value : TFlexValue; override;
+    function IsScalar : Boolean; override;
+    function AsString : string; override;
+  end;
+
+  TYamlInteger = class(TYamlValue)
+  private
+    fValue : Integer;
+    fIsNull : Boolean;
+  protected
+    function IsNull : Boolean; override;
+  public
+    constructor Create; overload;
+    constructor Create(const aValue : Integer); overload;
+    function Value : TFlexValue; override;
+    function IsScalar : Boolean; override;
+    function AsString : string; override;
+  end;
+
+  TYamlFloat = class(TYamlValue)
+  private
+    fValue : Double;
+    fIsNull : Boolean;
+  protected
+    function IsNull : Boolean; override;
+  public
+    constructor Create; overload;
+    constructor Create(const aValue : Double); overload;
+    function Value : TFlexValue; override;
+    function IsScalar : Boolean; override;
+    function AsString : string; override;
+  end;
+
+  TYamlBoolean = class(TYamlValue)
+  private
+    fValue : Boolean;
+    fIsNull : Boolean;
+  protected
+    function IsNull : Boolean; override;
+  public
+    constructor Create; overload;
+    constructor Create(const aValue : Boolean); overload;
+    function Value : TFlexValue; override;
+    function IsScalar : Boolean; override;
+    function AsString : string; override;
+  end;
+
+  TYamlNull = class(TYamlValue)
+  protected
+    function IsNull: Boolean; override;
+  public
+    function Value : TFlexValue; override;
+    function AsString : string; override;
+  end;
+
+  TYamlComment = class(TYamlValue)
+  private
+    fValue : string;
+    fIsNull : Boolean;
+  protected
+    function IsNull : Boolean; override;
+  public
+    constructor Create; overload;
+    constructor Create(const aComment : string); overload;
+    function Value : TFlexValue; override;
+    function IsScalar : Boolean; override;
+    function AsString : string; override;
+  end;
+
+  TYamlPair = class(TYamlAncestor)
+  private
+    fName : string;
+    fValue : TYamlValue;
+  protected
+    procedure AddDescendant(const aDescendent: TYamlAncestor); override;
+  public
+    constructor Create(const aName : string; const aValue : TYamlValue); overload;
+    constructor Create(const aName : string; const aValue : string); overload;
+    constructor Create(const aName : string; const aValue : Integer); overload;
+    constructor Create(const aName : string; const aValue : Double); overload;
+    destructor Destroy; override;
+    property Name : string read fName write fName;
+    property Value : TYamlValue read fValue write fValue;
+    function ToYaml : string;
+  end;
+
+  TYamlWriter = class
+  private
+    fData : string;
+  public
+    constructor Create;
+    property Text : string read fData;
+    procedure Write(const aValue : string);
+    procedure Writeln(const aValue : string);
+  end;
+
+  TYamlObject = class(TYamlValue)
+  public type
+    TEnumerator = class
+    private
+      fIndex: Integer;
+      fObject: TYamlObject;
+    public
+      constructor Create(const aObject: TYamlObject);
+      function GetCurrent: TYamlPair; inline;
+      function MoveNext: Boolean; inline;
+      property Current: TYamlPair read GetCurrent;
+    end;
+  private
+    fMembers : TList<TYamlPair>;
+    function GetCount : Integer;
+    class function ParseValue(yaml : TList<string>; var vIndex : Integer): TYamlAncestor;
+    class function ParsePairName(const aPair : string) : string;
+    class function ParsePairValue(const aPair : string) : string;
+    class function ParseArrayValue(const aValue : string) : TYamlValue;
+    class function GetItemLevel(const aValue : string) : Integer;
+    function ParseToYaml(aIndent : Integer) : string;
+  protected
+    procedure AddDescendant(const aDescendent: TYamlAncestor); override;
+  public
+    constructor Create; overload;
+    constructor Create(const aData : string); overload;
+    destructor Destroy; override;
+    function GetValue(const aName: string): TYamlValue;
+    property Values[const aName: string] : TYamlValue read GetValue;
+    procedure ParseYaml(const aData : string);
+    property Count : Integer read GetCount;
+    class function ParseYamlValue(const aData : string) : TYamlAncestor;
+    function GetPair(const aIndex : Integer) : TYamlPair;
+    function GetPairByName(const aPairName : string) : TYamlPair;
+    function AddPair(const aPair : TYamlPair): TYamlObject; overload;
+    function AddPair(const aName : string; const aValue : TYamlValue): TYamlObject; overload;
+    function AddPair(const aName : string; const aValue : string): TYamlObject; overload;
+    function RemovePair(const aPairName: string): TYamlPair;
+    function GetEnumerator: TEnumerator; inline;
+    property Pairs[const aIndex: Integer]: TYamlPair read GetPair;
+    function ToYaml : string;
+    function AsString : string; override;
+  end;
+
+  { TYamlArray }
+
+  TYamlArray = class(TYamlValue)
+  public type
+    TEnumerator = class
+    private
+      fIndex : Integer;
+      fArray : TYamlArray;
+    public
+      constructor Create(const aArray: TYamlArray);
+      function GetCurrent: TYamlValue; inline;
+      function MoveNext: Boolean; inline;
+      property Current: TYamlValue read GetCurrent;
+    end;
+  private
+    fElements: TList<TYamlValue>;
+    function ParseToYaml(aIndent : Integer; var vIsScalar : Boolean) : string;
+  protected
+    procedure AddDescendant(const aDescendant: TYamlAncestor); override;
+    function GetCount: Integer; inline;
+    function GetValue(const aIndex: Integer): TYamlValue; overload; inline;
+  public
+    constructor Create; overload;
+    constructor Create(const aFirstElem: TYamlValue); overload;
+    destructor Destroy; override;
+    property Count: Integer read GetCount;
+    property Items[const aIndex: Integer]: TYamlValue read GetValue;
+    procedure AddElement(const aElement: TYamlValue);
+    function GetEnumerator: TEnumerator; inline;
+    function AsString : string; override;
+  end;
+
+  EYAMLException = class(Exception);
+
+implementation
+
+const
+  NUM_INDENT = 2;
+
+{ TYamlAncestor }
+
+procedure TYamlAncestor.AddDescendant(const aDescendent: TYamlAncestor);
+begin
+  raise EYAMLException.CreateFmt('Cannot add value %s to %s',[aDescendent.ClassName,ClassName]);
+end;
+
+constructor TYamlAncestor.Create;
+begin
+  inherited Create;
+  fOwned := True;
+end;
+
+function TYamlAncestor.IsNull: Boolean;
+begin
+  Result := False;
+end;
+
+function TYamlAncestor.IsScalar: Boolean;
+begin
+  Result := False;
+end;
+
+{ TYamlObject }
+
+function TYamlObject.AddPair(const aPair: TYamlPair): TYamlObject;
+begin
+  if aPair <> nil then AddDescendant(aPair);
+  Result := Self;
+end;
+
+function TYamlObject.AddPair(const aName: string; const aValue: TYamlValue): TYamlObject;
+begin
+  if (not aName.IsEmpty) and (aValue <> nil) then AddPair(TYamlPair.Create(aName,aValue));
+  Result := Self;
+end;
+
+procedure TYamlObject.AddDescendant(const aDescendent: TYamlAncestor);
+begin
+  if aDescendent <> nil then fMembers.Add(TYamlPair(aDescendent));
+end;
+
+function TYamlObject.AddPair(const aName, aValue: string): TYamlObject;
+begin
+  if not aName.IsEmpty and (not aValue.IsEmpty) then AddPair(TYamlPair.Create(aName,aValue));
+  Result := Self;
+end;
+
+function TYamlObject.AsString: string;
+begin
+  Result := ToYaml;
+end;
+
+constructor TYamlObject.Create(const aData: string);
+begin
+  inherited Create;
+  ParseYaml(aData);
+end;
+
+constructor TYamlObject.Create;
+begin
+  inherited Create;
+  fMembers := TList<TYamlPair>.Create;
+end;
+
+destructor TYamlObject.Destroy;
+var
+  member: TYamlAncestor;
+  i: Integer;
+begin
+  if Assigned(fMembers) then
+  for i := 0 to fMembers.Count - 1 do
+  begin
+    {$IFNDEF FPC}
+    member := fMembers.List[i];
+    {$ELSE}
+    member := fMembers.Items[i];
+    {$ENDIF}
+    if Assigned(member) and member.Owned then member.Free;
+  end;
+  FreeAndNil(fMembers);
+  inherited;
+end;
+
+function TYamlObject.GetCount: Integer;
+begin
+  Result := fMembers.Count;
+end;
+
+function TYamlObject.GetEnumerator: TEnumerator;
+begin
+  Result := TEnumerator.Create(Self);
+end;
+
+class function TYamlObject.GetItemLevel(const aValue: string): Integer;
+var
+  i : Integer;
+  trimed : string;
+begin
+  trimed := aValue.Trim;
+  if trimed.IsEmpty or trimed.StartsWith('#') then Exit(99999);
+
+  for i := Low(aValue) to aValue.Length do
+  begin
+    if aValue[i] <> ' ' then Exit(i);
+  end;
+  Result := Low(aValue);
+end;
+
+function TYamlObject.GetPair(const aIndex: Integer): TYamlPair;
+begin
+  Result := fMembers[aIndex];
+end;
+
+function TYamlObject.GetPairByName(const aPairName: string): TYamlPair;
+var
+  yamlpair : TYamlPair;
+  I: Integer;
+begin
+  for i := 0 to Count - 1 do
+  begin
+    {$IFNDEF FPC}
+    yamlpair := fMembers.List[i];
+    {$ELSE}
+    yamlpair := fMembers.Items[i];
+    {$ENDIF}
+    if CompareText(yamlpair.Name,aPairName) = 0 then Exit(yamlpair);
+  end;
+  Result := nil;
+end;
+
+function TYamlObject.GetValue(const aName: string): TYamlValue;
+var
+  ymlpair: TYamlPair;
+  i: Integer;
+begin
+  for i := 0 to Count - 1 do
+  begin
+    {$IFNDEF FPC}
+    ymlpair := fMembers.List[i];
+    {$ELSE}
+    ymlpair := fMembers.Items[i];
+    {$ENDIF}
+    if CompareText(ymlpair.Name,aName) = 0 then Exit(ymlpair.Value);
+  end;
+  Result := nil;
+end;
+
+class function TYamlObject.ParseArrayValue(const aValue: string): TYamlValue;
+var
+  nint : Int64;
+  nfloat : Double;
+begin
+  if TryStrToInt64(aValue,nint) then Result := TYamlInteger.Create(nint)
+  else if TryStrToFloat(aValue,nfloat) then Result := TYamlFloat.Create(nfloat)
+  else Result := TYamlString.Create(aValue);
+end;
+
+class function TYamlObject.ParsePairName(const aPair: string): string;
+begin
+  Result := Copy(aPair,0,aPair.IndexOf(':'));
+end;
+
+class function TYamlObject.ParsePairValue(const aPair: string): string;
+begin
+  Result := AnsiDequotedStr(Copy(aPair,aPair.IndexOf(':')+2,aPair.Length).Trim, '"');
+end;
+
+class function TYamlObject.ParseValue(yaml : TList<string>; var vIndex : Integer): TYamlAncestor;
+type
+  TYamlType = (ytObject, ytArray, ytScalarArray, ytScalar);
+var
+  name : string;
+  value : string;
+  yvalue : TYamlAncestor;
+  level : Integer;
+  nextlevel : Integer;
+  aitem : string;
+  yamlType : TYamlType;
+begin
+  Result := nil;
+  level := 0;
+  while yaml.Count > vIndex do
+  begin
+    value := yaml[vIndex].Trim;
+
+    name := ParsePairName(value);
+    if (name.IsEmpty) or (value.IsEmpty) or (value.StartsWith('#')) or (value.StartsWith(#9)) then Exit(nil)
+    //else if value.StartsWith('#') then Exit(TYamlComment.Create(value))
+    else if value.StartsWith('-') then
+    begin
+      yaml[vIndex] := StringReplace(yaml[vIndex],'-','',[]).TrimLeft;
+      yamlType := ytObject;
+      Dec(vIndex);
+    end
+    else if value.EndsWith(':') then
+    begin
+      if yaml[vIndex + 1].TrimLeft.StartsWith('-') then yamlType := ytArray
+        else yamlType := ytObject;
+    end
+    else if value.IndexOf(':') < value.Length then
+    begin
+      value := ParsePairValue(value);
+      if (value.StartsWith('[')) and (value.EndsWith(']')) then yamlType := ytScalarArray
+        else yamlType := ytScalar;
+    end
+    else yamlType := TYamlType.ytScalar;
+
+    case yamlType of
+      ytArray : //is array
+        begin
+          yvalue := TYamlArray.Create;
+          level := GetItemLevel(yaml[vIndex + 1]);
+          repeat
+            Inc(vIndex);
+            yvalue.AddDescendant(ParseValue(yaml,vIndex));
+          until (yvalue = nil) or (vIndex >= yaml.Count - 1) or (GetItemLevel(yaml[vIndex + 1]) < level);
+          Exit(TYamlPair.Create(name,TYamlValue(yvalue)));
+        end;
+      ytObject : //is object
+        begin
+          yvalue := TYamlObject.Create;
+          repeat
+            Inc(vIndex);
+            nextlevel := GetItemLevel(yaml[vIndex]);
+            if nextlevel <> 99999 then level := nextlevel;
+
+            yvalue.AddDescendant(ParseValue(yaml,vIndex));
+            //level := GetItemLevel(yaml[vIndex]);
+            //var level2 := GetItemLevel(yaml[offset + 1]);
+          until (yvalue = nil) or (vIndex >= yaml.Count - 1) or (GetItemLevel(yaml[vIndex + 1]) < level);
+          Exit(TYamlPair.Create(name,TYamlValue(yvalue)));
+        end;
+      ytScalarArray : //is scalar array
+        begin
+          yvalue := TYamlArray.Create;
+          value := StringReplace(Copy(value,2,Value.Length-2),', ',#9,[rfReplaceAll]);
+          for aitem in value.Split([#9]) do
+          begin
+            yvalue.AddDescendant(ParseArrayValue(aitem));
+          end;
+          Exit(TYamlPair.Create(name,TYamlValue(yvalue)));
+        end;
+    else Exit(TYamlPair.Create(name,value)); //is scalar
+    end;
+    Inc(vIndex);
+  end;
+end;
+
+procedure TYamlObject.ParseYaml(const aData: string);
+var
+  yaml : TList<string>;
+  line : string;
+  data : string;
+  yamlvalue : TYamlAncestor;
+  vIndex : Integer;
+begin
+  yaml := TList<string>.Create;
+  try
+    vIndex := 0;
+    //normalize tabs
+    data := StringReplace(aData,#9,Spaces(NUM_INDENT),[rfReplaceAll]);
+    {$IFDEF MSWINDOWS}
+    for line in data.Split([#13]) do yaml.Add(StringReplace(line,#10,'',[rfReplaceAll]));
+    {$ELSE}
+    for line in data.Split([#10]) do yaml.Add(StringReplace(line,#13,'',[rfReplaceAll]));
+    {$ENDIF}
+    while yaml.Count > vIndex do
+    begin
+      yamlvalue := ParseValue(yaml,vIndex);
+      if yamlvalue <> nil then AddDescendant(yamlvalue);
+      Inc(vIndex);
+    end;
+  finally
+    yaml.Free;
+  end;
+end;
+
+class function TYamlObject.ParseYamlValue(const aData : string) : TYamlAncestor;
+var
+  yaml : TList<string>;
+  line : string;
+  data : string;
+  yamlvalue : TYamlAncestor;
+  vIndex : Integer;
+begin
+  yaml := TList<string>.Create;
+  try
+    vIndex := 0;
+    //normalize tabs
+    data := StringReplace(aData,#9,Spaces(NUM_INDENT),[rfReplaceAll]);
+    {$IFDEF MSWINDOWS}
+    for line in data.Split([#13]) do yaml.Add(StringReplace(line,#10,'',[rfReplaceAll]));
+    {$ELSE}
+    for line in data.Split([#10]) do yaml.Add(StringReplace(line,#13,'',[rfReplaceAll]));
+    {$ENDIF}
+    if yaml[0].TrimLeft.StartsWith('- ') then Result := TYamlArray.Create
+      else Result := TYamlObject.Create;
+    while yaml.Count > vIndex do
+    begin
+      yamlvalue := ParseValue(yaml,vIndex);
+      if yamlvalue <> nil then Result.AddDescendant(yamlvalue);
+      Inc(vIndex);
+    end;
+  finally
+    yaml.Free;
+  end;
+end;
+
+function TYamlObject.RemovePair(const aPairName: string): TYamlPair;
+var
+  yamlpair: TYamlPair;
+  i: Integer;
+begin
+  for i := 0 to Count - 1 do
+  begin
+    {$IFNDEF FPC}
+    yamlpair := TYamlPair(FMembers.List[i]);
+    {$ELSE}
+    yamlpair := TYamlPair(fMembers.Items[i]);
+    {$ENDIF}
+    if CompareText(yamlpair.Name,aPairName) = 0 then
+    begin
+      fMembers.Remove(yamlpair);
+      Exit(yamlpair);
+    end;
+  end;
+  Result := nil;
+end;
+
+function TYamlObject.ToYaml: string;
+begin
+  Result := ParseToYaml(0);
+end;
+
+function TYamlObject.ParseToYaml(aIndent : Integer) : string;
+const
+  SPECIAL_CHARS: array[1..19] of Char = (':', '{', '}', '[', ']', ',', '&', '*', '#', '?', '|', '-', '<', '>', '=', '!', '%', '@', '\');
+var
+  i : Integer;
+  member : TYamlPair;
+  yaml : TYamlWriter;
+  yvalue : TYamlAncestor;
+  indent : string;
+  isscalar : Boolean;
+  scalar : string;
+  rarray : string;
+begin
+  yaml := TYamlWriter.Create;
+  try
+    indent := StringOfChar(' ',aIndent);
+    for i := 0 to fMembers.Count - 1 do
+    begin
+      member := fMembers[i];
+      if member = nil then continue;
+
+      yvalue := member.Value;
+      if (yvalue.IsScalar) or (yvalue is TYamlNull) then
+      begin
+        if yvalue is TYamlComment then yaml.Writeln(Format('#%s%s',[indent,TYamlComment(member.Value).AsString]))
+        else
+        begin
+          if yvalue is TYamlNull then scalar := 'null'
+          else if (yvalue is TYamlFloat) or (yvalue is TYamlBoolean) then scalar := member.Value.AsString
+            else scalar := member.Value.Value.AsString;
+          if scalar.IsEmpty then scalar := '""';
+          if scalar.IndexOfAny(SPECIAL_CHARS) > -1 then
+            scalar := AnsiQuotedStr(scalar, '"');
+          yaml.Writeln(Format('%s%s: %s',[indent,member.Name,scalar]));
+          if (i < fMembers.Count - 1) and (fMembers[i+1].Value is TYamlComment) then yaml.Writeln('');
+        end;
+      end
+      else if (yvalue is TYamlObject) then
+      begin
+        yaml.Writeln(Format('%s%s:',[indent,member.Name]));
+        yaml.Write((yvalue as TYamlObject).ParseToYaml(aIndent + NUM_INDENT));
+        if aIndent = 0 then yaml.Writeln('');
+      end
+      else if (yvalue is TYamlArray) then
+      begin
+        isscalar := False;
+        rarray := (yvalue as TYamlArray).ParseToYaml(aIndent + NUM_INDENT,isscalar);
+        if isscalar then yaml.Writeln(Format('%s%s: %s',[indent,member.Name,rarray]))
+        else
+        begin
+          yaml.Writeln(Format('%s%s:',[indent,member.Name]));
+          yaml.Write(rarray);
+        end;
+      end;
+    end;
+    Result := yaml.Text;
+  finally
+    yaml.Free;
+  end;
+end;
+
+{ TYamlString }
+
+constructor TYamlString.Create(const aValue: string);
+begin
+  inherited Create;
+  fValue := aValue;
+  fIsNull := False;
+end;
+
+constructor TYamlString.Create;
+begin
+  inherited Create;
+  fIsNull := True;
+end;
+
+function TYamlString.IsNull: Boolean;
+begin
+  Result := fIsNull;
+end;
+
+function TYamlString.IsScalar: Boolean;
+begin
+  Result := True;
+end;
+
+function TYamlString.AsString: string;
+begin
+  Result := fValue;
+end;
+
+function TYamlString.Value: TFlexValue;
+begin
+  Result := fValue;
+end;
+
+{ TYamlInteger }
+
+constructor TYamlInteger.Create(const aValue: Integer);
+begin
+  inherited Create;
+  fValue := aValue;
+  fIsNull := False;
+end;
+
+constructor TYamlInteger.Create;
+begin
+  inherited Create;
+  fIsNull := True;
+end;
+
+function TYamlInteger.IsNull: Boolean;
+begin
+  Result := fIsNull;
+end;
+
+function TYamlInteger.IsScalar: Boolean;
+begin
+  Result := True;
+end;
+
+function TYamlInteger.AsString: string;
+begin
+  Result := IntToStr(fValue);
+end;
+
+function TYamlInteger.Value: TFlexValue;
+begin
+  Result := fValue;
+end;
+
+{ TYamlFloat }
+
+constructor TYamlFloat.Create(const aValue: Double);
+begin
+  inherited Create;
+  fValue := aValue;
+  fIsNull := False;
+end;
+
+constructor TYamlFloat.Create;
+begin
+  inherited Create;
+  fIsNull := True;
+end;
+
+function TYamlFloat.IsNull: Boolean;
+begin
+  Result := fIsNull;
+end;
+
+function TYamlFloat.IsScalar: Boolean;
+begin
+  Result := True;
+end;
+
+function TYamlFloat.AsString: string;
+begin
+  Result := FloatToStr(fValue);
+end;
+
+function TYamlFloat.Value: TFlexValue;
+begin
+  Result := fValue;
+end;
+
+{ TYamlPair }
+
+constructor TYamlPair.Create(const aName: string; const aValue: TYamlValue);
+begin
+  inherited Create;
+  fName := aName;
+  fValue := aValue;
+end;
+
+constructor TYamlPair.Create(const aName, aValue: string);
+begin
+  inherited Create;
+  fName := aName;
+  fValue := TYamlString.Create(aValue);
+end;
+
+constructor TYamlPair.Create(const aName: string; const aValue: Double);
+begin
+  inherited Create;
+  fName := aName;
+  fValue := TYamlFloat.Create(aValue);
+end;
+
+constructor TYamlPair.Create(const aName: string; const aValue: Integer);
+begin
+  inherited Create;
+  fName := aName;
+  fValue := TYamlInteger.Create(aValue);
+end;
+
+destructor TYamlPair.Destroy;
+begin
+  if (fValue <> nil) and fValue.Owned then FreeAndNil(fValue);
+  inherited Destroy;
+end;
+
+function TYamlPair.ToYaml: string;
+var
+  isscalar : Boolean;
+begin
+  if fValue = nil then Exit('null');
+
+  if fValue is TYamlObject then Result := TYamlObject(fValue).ToYaml
+    else if fValue is TYamlArray then Result := TYamlArray(fValue).ParseToYaml(0,isscalar)
+      else Result := Format('%s: %s',[fName,fValue.Value.AsString]);
+
+end;
+
+procedure TYamlPair.AddDescendant(const aDescendent: TYamlAncestor);
+begin
+  if fName = '' then
+    fName := TYamlString(aDescendent).Value
+  else if fValue = nil then
+    fValue:= TYamlValue(aDescendent)
+  else inherited AddDescendant(aDescendent);
+end;
+
+{ TYamlObject.TEnumerator }
+
+constructor TYamlObject.TEnumerator.Create(const aObject: TYamlObject);
+begin
+  inherited Create;
+  fIndex := -1;
+  fObject := aObject;
+end;
+
+function TYamlObject.TEnumerator.GetCurrent: TYamlPair;
+begin
+  {$IFNDEF FPC}
+  Result := fObject.fMembers.List[fIndex];
+  {$ELSE}
+  Result := fObject.fMembers.Items[fIndex];
+  {$ENDIF}
+end;
+
+function TYamlObject.TEnumerator.MoveNext: Boolean;
+begin
+  Inc(fIndex);
+  Result := fIndex < fObject.Count;
+end;
+
+
+{ TYamlValue }
+
+function TYamlValue.Value: TFlexValue;
+begin
+  Result := '';
+end;
+
+{ TYamlArray.TEnumerator }
+
+constructor TYamlArray.TEnumerator.Create(const aArray: TYamlArray);
+begin
+  inherited Create;
+  fIndex := -1;
+  fArray := aArray;
+end;
+
+function TYamlArray.TEnumerator.GetCurrent: TYamlValue;
+begin
+  {$IFNDEF FPC}
+  Result := fArray.fElements.List[fIndex];
+  {$ELSE}
+  Result := fArray.fElements.Items[fIndex];
+  {$ENDIF}
+end;
+
+function TYamlArray.TEnumerator.MoveNext: Boolean;
+begin
+  Inc(fIndex);
+  Result := fIndex < fArray.Count;
+end;
+
+{ TYamlArray }
+
+procedure TYamlArray.AddDescendant(const aDescendant: TYamlAncestor);
+begin
+  fElements.Add(TYamlValue(aDescendant));
+end;
+
+constructor TYamlArray.Create;
+begin
+  inherited Create;
+  fElements := TList<TYamlValue>.Create;
+end;
+
+constructor TYamlArray.Create(const aFirstElem: TYamlValue);
+begin
+  inherited Create;
+  AddElement(aFirstElem);
+end;
+
+procedure TYamlArray.AddElement(const aElement: TYamlValue);
+begin
+  if aElement <> nil then AddDescendant(aElement);
+end;
+
+function TYamlArray.AsString: string;
+var
+  first : Boolean;
+  element : TYamlValue;
+begin
+  first := True;
+  for element in fElements do
+  begin
+    if first then Result := Result + element.AsString
+      else  Result := Result + ',' + element.AsString;
+  end;
+  Result := Format('[%s]',[Result]);
+end;
+
+destructor TYamlArray.Destroy;
+var
+  element: TYamlAncestor;
+  i: Integer;
+begin
+  if Assigned(fElements) then
+  for i := 0 to fElements.Count - 1 do
+  begin
+    element := fElements[i];
+    if Assigned(element) and (element.Owned) then element.Free;
+  end;
+  if Assigned(fElements) then FreeAndNil(fElements);
+  inherited Destroy;
+end;
+
+function TYamlArray.GetCount: Integer;
+begin
+  Result := fElements.Count;
+end;
+
+function TYamlArray.GetEnumerator: TEnumerator;
+begin
+  Result := TEnumerator.Create(Self);
+end;
+
+function TYamlArray.GetValue(const aIndex: Integer): TYamlValue;
+begin
+  Result := fElements[aIndex];
+end;
+
+function TYamlArray.ParseToYaml(aIndent : Integer; var vIsScalar : Boolean) : string;
+var
+  element : TYamlValue;
+  yaml : TYamlWriter;
+  yvalue : TYamlAncestor;
+  indent : string;
+  isscalar : Boolean;
+begin
+  Result := '';
+  yvalue := nil;
+  yaml := TYamlWriter.Create;
+  try
+    indent := StringOfChar(' ',aIndent);
+    if fElements.Count = 0 then
+    begin
+      vIsScalar := True;
+      Exit('[]');
+    end;
+    for element in fElements do
+    begin
+      yvalue := element;
+      if yvalue is TYamlPair then yvalue := TYamlPair(yvalue).value;
+
+      if yvalue.IsScalar then
+      begin
+        {$IFNDEF FPC}
+        if Result = '' then Result := element.AsString
+          else Result := Result + ', ' + element.AsString;
+        {$ELSE}
+        if Result = '' then Result := TYamlPair(element).Value.AsString
+          else Result := Result + ', ' + TYamlPair(element).Value.AsString;
+        {$ENDIF}
+      end
+      else if (yvalue is TYamlObject) then
+      begin
+        yaml.Write(indent + '- ' + (yvalue as TYamlObject).ParseToYaml(aIndent + NUM_INDENT).TrimLeft);
+      end
+      else if (yvalue is TYamlArray) then
+      begin
+        yaml.Write(Format('%s%s',[indent,(yvalue as TYamlArray).ParseToYaml(aIndent + NUM_INDENT,isscalar)]))
+      end;
+      yaml.Writeln('');
+    end;
+    if (yvalue <> nil) and (yvalue.IsScalar) then
+    begin
+      Result := '[' + Result + ']';
+      vIsScalar := True;
+    end
+    else Result := yaml.Text;
+  finally
+    yaml.Free;
+  end;
+end;
+
+{ TYamlWriter }
+
+procedure TYamlWriter.Write(const aValue: string);
+begin
+  fData := fData + aValue;
+end;
+
+procedure TYamlWriter.Writeln(const aValue: string);
+begin
+  fData := fData + aValue + CRLF;
+end;
+
+constructor TYamlWriter.Create;
+begin
+  fData := '';
+end;
+
+{ TYamlNull }
+
+function TYamlNull.IsNull: Boolean;
+begin
+  Result := True;
+end;
+
+function TYamlNull.AsString: string;
+begin
+  Result := 'null';
+end;
+
+function TYamlNull.Value: TFlexValue;
+begin
+  Result := nil;
+end;
+
+{ TYamlBoolean }
+
+constructor TYamlBoolean.Create;
+begin
+  inherited Create;
+  fIsNull := True;
+end;
+
+constructor TYamlBoolean.Create(const aValue: Boolean);
+begin
+  inherited Create;
+  fIsNull := False;
+  fValue := aValue;
+end;
+
+function TYamlBoolean.IsNull: Boolean;
+begin
+  Result := fIsNull;
+end;
+
+function TYamlBoolean.IsScalar: Boolean;
+begin
+  Result := True;
+end;
+
+function TYamlBoolean.AsString: string;
+begin
+  Result := BoolToStr(fValue,True).ToLower;
+end;
+
+function TYamlBoolean.Value: TFlexValue;
+begin
+  Result := fValue;
+end;
+
+{ TYamlComment }
+
+function TYamlComment.AsString: string;
+begin
+  Result := fValue;
+end;
+
+constructor TYamlComment.Create;
+begin
+  inherited Create;
+  fIsNull := True;
+end;
+
+constructor TYamlComment.Create(const aComment: string);
+begin
+  inherited Create;
+  fIsNull := False;
+  fValue := aComment;
+end;
+
+function TYamlComment.IsNull: Boolean;
+begin
+  Result := fIsNull;
+end;
+
+function TYamlComment.IsScalar: Boolean;
+begin
+  Result := True;
+end;
+
+function TYamlComment.Value: TFlexValue;
+begin
+
+end;
+
+end.