Explorar el Código

Merge branch 'master' of https://github.com/exilon/QuickLib

# Conflicts:
#	.gitignore
jkour hace 3 años
padre
commit
d3f3afed8c
Se han modificado 81 ficheros con 13432 adiciones y 3189 borrados
  1. 1 1
      .gitignore
  2. 2 2
      Delphinus.Info.json
  3. 62 38
      Quick.Amazon.pas
  4. 52 7
      Quick.AppService.pas
  5. 10 0
      Quick.Arrays.pas
  6. 9 3
      Quick.AutoMapper.pas
  7. 96 24
      Quick.Azure.pas
  8. 20 0
      Quick.Base64.pas
  9. 8 2
      Quick.Chrono.pas
  10. 18 4
      Quick.Collections.pas
  11. 464 61
      Quick.Commons.pas
  12. 1271 0
      Quick.Conditions.pas
  13. 2 2
      Quick.Config.Base.pas
  14. 3 3
      Quick.Config.Json.pas
  15. 2 2
      Quick.Config.YAML.pas
  16. 4 4
      Quick.Console.pas
  17. 4 6
      Quick.Crypto.pas
  18. 15 4
      Quick.Data.InfluxDB.pas
  19. 213 44
      Quick.Data.Redis.pas
  20. 12 3
      Quick.Debug.Utils.pas
  21. 18 9
      Quick.Expression.pas
  22. 18 9
      Quick.FileMonitor.pas
  23. 105 5
      Quick.Files.pas
  24. 8 4
      Quick.HttpClient.pas
  25. 9 3
      Quick.HttpServer.Request.pas
  26. 2 0
      Quick.HttpServer.Response.pas
  27. 50 10
      Quick.HttpServer.pas
  28. 95 31
      Quick.IOC.pas
  29. 13 10
      Quick.JSON.Utils.pas
  30. 206 66
      Quick.Json.Serializer.pas
  31. 56 11
      Quick.Linq.pas
  32. 1 0
      Quick.Log.pas
  33. 6 0
      Quick.Logger.Intf.pas
  34. 5 14
      Quick.MemoryCache.pas
  35. 83 1
      Quick.Network.pas
  36. 33 22
      Quick.Options.Serializer.Json.pas
  37. 30 21
      Quick.Options.Serializer.Yaml.pas
  38. 159 83
      Quick.Options.pas
  39. 33 8
      Quick.Parameters.pas
  40. 26 5
      Quick.Pooling.pas
  41. 119 9
      Quick.Process.pas
  42. 680 726
      Quick.RTTI.Utils.pas
  43. 218 0
      Quick.RegEx.Utils.pas
  44. 89 0
      Quick.Registry.pas
  45. 81 8
      Quick.SMTP.pas
  46. 2 1
      Quick.Serializer.Intf.pas
  47. 62 4
      Quick.Service.pas
  48. 10 1
      Quick.SysInfo.pas
  49. 323 9
      Quick.Threads.pas
  50. 122 0
      Quick.Url.Utils.pas
  51. 1 1
      Quick.Value.RTTI.pas
  52. 1613 1584
      Quick.YAML.Serializer.pas
  53. 27 8
      Quick.YAML.pas
  54. 43 22
      QuickLib.inc
  55. 58 6
      README.md
  56. 1 0
      samples/delphi/QuickAppService/ConsoleAndService/MyServiceConsole.dpr
  57. 416 39
      samples/delphi/QuickAppService/ConsoleAndService/MyServiceConsole.dproj
  58. 15 2
      samples/delphi/QuickCollections/InterfacedLists.dpr
  59. 1 89
      samples/delphi/QuickCollections/InterfacedLists.dproj
  60. 46 0
      samples/delphi/QuickCommons/Url/Url_Manipulation.dpr
  61. 980 0
      samples/delphi/QuickCommons/Url/Url_Manipulation.dproj
  62. 61 0
      samples/delphi/QuickConditions/ConditionChecks.deployproj
  63. 80 0
      samples/delphi/QuickConditions/ConditionChecks.dpr
  64. 1017 0
      samples/delphi/QuickConditions/ConditionChecks.dproj
  65. 76 101
      samples/delphi/QuickConfig/ConfigToJSON/ConfigToJSON.dproj
  66. BIN
      samples/delphi/QuickConfig/ConfigToJSON/ConfigToJSON.res
  67. 1 0
      samples/delphi/QuickConfig/ConfigToJSON/Main.pas
  68. 388 1
      samples/delphi/QuickConfig/ConfigToYAML/ConfigToYAML.dproj
  69. BIN
      samples/delphi/QuickConfig/ConfigToYAML/ConfigToYAML.res
  70. 1 0
      samples/delphi/QuickConfig/ConfigToYAML/Main.pas
  71. 56 0
      samples/delphi/QuickExpressions/ExpressionsTest.dpr
  72. 980 0
      samples/delphi/QuickExpressions/ExpressionsTest.dproj
  73. 84 0
      samples/delphi/QuickJsonSerializer/ComplexObjects/ComplexObjects.dpr
  74. 980 0
      samples/delphi/QuickJsonSerializer/ComplexObjects/ComplexObjects.dproj
  75. 55 0
      samples/delphi/QuickJsonSerializer/ObjectToJsonStream/ObjectToJsonStream.dpr
  76. 980 0
      samples/delphi/QuickJsonSerializer/ObjectToJsonStream/ObjectToJsonStream.dproj
  77. 2 2
      samples/delphi/QuickOptions/Optionsdemo.dpr
  78. 8 27
      samples/delphi/QuickOptions/Optionsdemo.dproj
  79. 151 1
      samples/delphi/QuickParameters/Parameters.dproj
  80. 19 10
      samples/delphi/QuickSMTP/SendEmail.dpr
  81. 362 16
      samples/delphi/QuickSMTP/SendEmail.dproj

+ 1 - 1
.gitignore

@@ -66,4 +66,4 @@ bin
 *.or
 /Reports
 *.or
-Tests/Builds
+*.delphilsp.json

+ 2 - 2
Delphinus.Info.json

@@ -6,9 +6,9 @@
     "license_file": "LICENSE.txt",
     "platforms": "Win32;Win64;OSX32;Android;IOSDevice32;IOSDevice64;Linux64",
     "package_compiler_min": 22,
-    "package_compiler_max": 33,
+    "package_compiler_max": 35,
     "compiler_min": 22,
-    "compiler_max": 33,
+    "compiler_max": 35,
     "first_version": "1.0",
     "report_url": "",
     "dependencies":

+ 62 - 38
Quick.Amazon.pas

@@ -1,13 +1,13 @@
 { ***************************************************************************
 
-  Copyright (c) 2015-2018 Kike Pérez
+  Copyright (c) 2015-2021 Kike Pérez
 
   Unit        : Quick.Amazon
   Description : Amazon object operations
   Author      : Kike Pérez
   Version     : 1.4
   Created     : 18/11/2016
-  Modified    : 11/09/2020
+  Modified    : 18/11/2021
 
   This file is part of QuickLib: https://github.com/exilon/QuickLib
 
@@ -39,24 +39,35 @@ uses
   System.Generics.Collections,
   IPPeerClient,
   Data.Cloud.CloudAPI,
-  Data.Cloud.AmazonAPI;
+  Data.Cloud.AmazonAPI,
+  Quick.Commons;
 
 const
 
   AWSRegionSet : array of string = [
-  'eu-west-1',
-  'eu-west-1',
-  'eu-central-1',
-  'us-east-1',
-  'us-west-1',
-  'us-west-2',
-  'ap-southeast-1',
-  'ap-southeast-2',
-  'ap-northeast-1',
-  'ap-northeast-2',
-  'sa-east-1',
-  'us-east-1',  // deprecate
-  'us-east-1','us-east-1'];
+    'eu-west-1',
+    'eu-west-2',
+    'eu-west-3',
+    'eu-central-1',
+    'us-east-1',
+    'us-east-2',
+    'us-west-1',
+    'us-west-2',
+    'ap-east-1',
+    'ap-south-1',
+    'ap-southeast-1',
+    'ap-southeast-2',
+    'ap-northeast-1',
+    'ap-northeast-2',
+    'ap-northeast-3',
+    'ca-central-1',
+    'sa-east-1',
+    'us-east-1', // deprecated
+    'eu-west-1', // deprecated
+    'cn-north-1',
+    'cn-northwest-1',
+    'eu-north-1',
+    'me-south-1'];
 
 type
 
@@ -92,6 +103,7 @@ type
       procedure SetAWSRegion(Value : TAmazonRegion);
       function FileToArray(cFilename : string) : TArray<Byte>;
       function StreamToArray(cStream : TStream) : TArray<Byte>;
+      function ByteContent(DataStream: TStream): TBytes;
     public
       constructor Create; overload;
       constructor Create(amAccountName, amAccountKey : string); overload;
@@ -145,7 +157,16 @@ end;
 procedure TQuickAmazon.SetAWSRegion(Value : TAmazonRegion);
 begin
   fAWSRegion := Value;
-  fconAmazon.StorageEndpoint := Format('s3-%s.amazonaws.com',[GetAWSRegion(Value)]);
+
+  //fconAmazon.StorageEndpoint := Format('s3-%s.amazonaws.com',[GetAWSRegion(Value)]);
+  //fconAmazon.StorageEndpoint := Format('s3.%s.amazonaws.com',[GetAWSRegion(Value)]);
+  {$IFDEF DELPHISYDNEY_UP}
+  if not StrInArray(Value,AWSRegionSet) then raise Exception.CreateFmt('%s is not a valid region for AmazonS3!',[Value]);
+
+  fconAmazon.Region := Value;
+  {$ELSE}
+  fconAmazon.StorageEndpoint := Format('s3.%s.amazonaws.com',[GetAWSRegion(Value)]);
+  {$ENDIF}
 end;
 
 procedure TQuickAmazon.SetAccountName(amAccountName : string);
@@ -183,13 +204,7 @@ var
 begin
   fs := TFileStream.Create(cFilename, fmOpenRead);
   try
-    bs := TBytesStream.Create(Result);
-    try
-      bs.LoadFromStream(fs);
-      Result := bs.Bytes;
-    finally
-      bs.Free
-    end;
+    Result := ByteContent(fs);
   finally
     fs.Free;
   end;
@@ -208,12 +223,18 @@ begin
   end;
 end;
 
-{function TQuickAmazon.StreamToArray(cStream : TStream) : TArray<Byte>;
+function TQuickAmazon.ByteContent(DataStream: TStream): TBytes;
+var
+  Buffer: TBytes;
 begin
-  SetLength(Result,cStream.Size);
-  cStream.WriteData(Result,Length(Result));
-end;}
-
+  if not Assigned(DataStream) then Exit(nil);
+  SetLength(Buffer, DataStream.Size);
+  // the content may have been read
+  DataStream.Position := 0;
+  if DataStream.Size > 0 then
+  DataStream.Read(Buffer[0], DataStream.Size);
+  Result := Buffer;
+end;
 
 function GetResponseInfo(amResponseInfo : TCloudResponseInfo) : TAmazonResponseInfo;
 begin
@@ -234,23 +255,26 @@ var
 begin
   AmazonS3 := TAmazonStorage.Create(fconAmazon);
   if amBucket = '' then amBucket := '$root';
-  CloudResponseInfo := TCloudResponseInfo.Create;
   try
     Content := FileToArray(cFilename);
     if amObjectName = '' then amObjectName := cFilename;
     if amObjectName.StartsWith('/') then amObjectName := Copy(amObjectName,2,Length(amObjectName));
-    Result := AmazonS3.UploadObject(amBucket,amObjectName,Content,False,nil,nil,amACLType,CloudResponseInfo);
-    amResponseInfo := GetResponseInfo(CloudResponseInfo);
+    CloudResponseInfo := TCloudResponseInfo.Create;
+    try
+      Result := AmazonS3.UploadObject(amBucket,amObjectName,Content,False,nil,nil,amACLType,CloudResponseInfo{$IFDEF DELPHIRX11_UP},fAWSRegion{$ENDIF});
+      amResponseInfo := GetResponseInfo(CloudResponseInfo);
+    finally
+      CloudResponseInfo.Free;
+    end;
   finally
     AmazonS3.Free;
-    CloudResponseInfo.Free;
   end;
 end;
 
 function TQuickAmazon.PutObject(amBucket : string; cStream : TStream; amObjectName : string; amACLType : TAmazonACLType; var amResponseInfo : TAmazonResponseInfo) : Boolean;
 var
   AmazonS3 : TAmazonStorage;
-  Content : TArray<Byte>;
+  Content : TBytes;
   CloudResponseInfo : TCloudResponseInfo;
 begin
   amResponseInfo.StatusCode := 500;
@@ -263,8 +287,8 @@ begin
       CloudResponseInfo := TCloudResponseInfo.Create;
       try
         //CloudResponseInfo.Headers.AddPair();
-        Content := StreamToArray(cStream);
-        Result := AmazonS3.UploadObject(amBucket,amObjectName,Content,False,nil,nil,amACLType,CloudResponseInfo);
+        Content := ByteContent(cStream);
+        Result := AmazonS3.UploadObject(amBucket,amObjectName,Content,False,nil,nil,amACLType,CloudResponseInfo{$IFDEF DELPHIRX11_UP},fAWSRegion{$ENDIF});
         amResponseInfo := GetResponseInfo(CloudResponseInfo);
       finally
         CloudResponseInfo.Free;
@@ -297,7 +321,7 @@ begin
       else fs := TFileStream.Create(cFilenameTo,fmCreate);
     try
       try
-        AmazonS3.GetObject(amBucket,amObjectName,fs,CloudResponseInfo);
+        AmazonS3.GetObject(amBucket,amObjectName,fs,CloudResponseInfo{$IFDEF DELPHIRX11_UP},fAWSRegion{$ENDIF});
         amResponseInfo := GetResponseInfo(CloudResponseInfo);
         if amResponseInfo.StatusCode = 200 then Result := True;
       except
@@ -326,7 +350,7 @@ begin
     CloudResponseInfo := TCloudResponseInfo.Create;
     try
       try
-        AmazonS3.GetObject(amBucket,amObjectName,Result,CloudResponseInfo);
+        AmazonS3.GetObject(amBucket,amObjectName,Result,CloudResponseInfo{$IFDEF DELPHIRX11_UP},fAWSRegion{$ENDIF});
         amResponseInfo := GetResponseInfo(CloudResponseInfo);
       except
         Result := nil;

+ 52 - 7
Quick.AppService.pas

@@ -63,6 +63,10 @@ type
                 ssRunning = SERVICE_RUNNING,
                 ssPaused = SERVICE_PAUSED);
 
+  TSvcStartType = (stAuto = SERVICE_AUTO_START,
+                   stManual = SERVICE_DEMAND_START,
+                   stDisabled = SERVICE_DISABLED);
+
   TSvcInitializeEvent = procedure of object;
   {$IFDEF FPC}
   TSvcAnonMethod = procedure of object;
@@ -77,6 +81,12 @@ type
     fSvHandle : SC_HANDLE;
     fServiceName : string;
     fDisplayName : string;
+    fLoadOrderGroup : string;
+    fDependencies : string;
+    fDesktopInteraction : Boolean;
+    fUsername : string;
+    fUserPass : string;
+    fStartType : TSvcStartType;   
     fFileName : string;
     fSilent : Boolean;
     fStatus : TSvcStatus;
@@ -95,6 +105,12 @@ type
     destructor Destroy; override;
     property ServiceName : string read fServiceName write fServiceName;
     property DisplayName : string read fDisplayName write fDisplayName;
+    property LoadOrderGroup : string read fLoadOrderGroup write fLoadOrderGroup;
+    property Dependencies : string read fDependencies write fDependencies;
+    property DesktopInteraction : Boolean read fDesktopInteraction write fDesktopInteraction;
+    property UserName : string read fUserName write fUserName;
+    property UserPass : string read fUserPass write fUserPass;
+    property StartType : TSvcStartType read fStartType write fStartType;
     property FileName : string read fFileName write fFileName;
     property Silent : Boolean read fSilent write fSilent;
     property CanInstallWithOtherName : Boolean read fCanInstallWithOtherName write fCanInstallWithOtherName;
@@ -183,6 +199,12 @@ begin
   inherited;
   fServiceName := DEF_SERVICENAME;
   fDisplayName := DEF_DISPLAYNAME;
+  fLoadOrderGroup := '';
+  fDependencies := '';
+  fDesktopInteraction := False;
+  fUserName := '';
+  fUserPass := '';
+  fStartType := TSvcStartType.stAuto;
   fFileName := ParamStr(0);
   fSilent := True;
   fStatus := TSvcStatus.ssStopped;
@@ -280,6 +302,13 @@ procedure TAppService.Install;
 const
   cInstallMsg = 'Service "%s" installed successfully!';
   cSCMError = 'Error trying to open SC Manager (you need admin permissions)';
+var
+  servicetype : Cardinal;
+  starttype : Cardinal;
+  svcloadgroup : PChar;
+  svcdependencies : PChar;
+  svcusername : PChar;
+  svcuserpass : PChar;
 begin
   fSCMHandle := OpenSCManager(nil,nil,SC_MANAGER_ALL_ACCESS);
 
@@ -289,19 +318,35 @@ begin
       else MessageBox(0,cSCMError,PChar(fServiceName),MB_ICONERROR or MB_OK or MB_TASKMODAL or MB_TOPMOST);
     Exit;
   end;
+  //service interacts with desktop
+  if fDesktopInteraction then servicetype := SERVICE_WIN32_OWN_PROCESS and SERVICE_INTERACTIVE_PROCESS
+    else servicetype := SERVICE_WIN32_OWN_PROCESS; 
+  //service load order
+  if fLoadOrderGroup.IsEmpty then svcloadgroup := nil
+    else svcloadgroup := PChar(fLoadOrderGroup);
+  //service dependencies
+  if fDependencies.IsEmpty then svcdependencies := nil
+    else svcdependencies := PChar(fDependencies);
+  //service user name
+  if fUserName.IsEmpty then svcusername := nil
+    else svcusername := PChar(fUserName);
+  //service user password
+  if fUserPass.IsEmpty then svcuserpass := nil
+    else svcuserpass := PChar(fUserPass);
+    
   fSvHandle := CreateService(fSCMHandle,
                               PChar(fServiceName),
                               PChar(fDisplayName),
                               SERVICE_ALL_ACCESS,
-                              SERVICE_WIN32_OWN_PROCESS,
-                              SERVICE_AUTO_START,
-                              SERVICE_ERROR_IGNORE,
+                              servicetype,
+                              Cardinal(fStartType),
+                              SERVICE_ERROR_NORMAL,
                               PChar(fFileName),
-                              'System Reserved',
-                              nil,
+                              svcloadgroup,
                               nil,
-                              nil, //user
-                              nil); //password
+                              svcdependencies,
+                              svcusername, //user
+                              svcuserpass); //password
 
   if fSvHandle <> 0 then
   begin

+ 10 - 0
Quick.Arrays.pas

@@ -53,6 +53,9 @@ type
       public
         constructor Create(var aArray: TArray<T>);
       end;
+  private type
+    arrayofT = array of T;
+    ParrayofT = ^arrayofT;
   private
     fArray : TArray<T>;
     function GetItem(Index : Integer) : T;
@@ -60,6 +63,7 @@ type
     function GetCapacity: Integer;
     function GetCount: Integer;
     procedure SetCapacity(const Value: Integer);
+    function GetPArray: ParrayofT;
   public
     function GetEnumerator: TEnumerator<T>;
     property AsArray : TArray<T> read fArray;
@@ -72,6 +76,7 @@ type
     procedure Remove(aItem : T);
     function Contains(aItem : T) : Boolean;
     function IndexOf(aItem : T) : Integer;
+    property PArray : ParrayofT read GetPArray;
     class operator Implicit(const Value : TxArray<T>) : TArray<T>;
     class operator Implicit(const Value : TArray<T>) : TxArray<T>;
   end;
@@ -128,6 +133,11 @@ begin
   Result := fArray[Index];
 end;
 
+function TXArray<T>.GetPArray: ParrayofT;
+begin
+  Pointer(Result) := fArray;
+end;
+
 procedure TXArray<T>.SetCapacity(const Value: Integer);
 begin
   if Value = High(fArray) then Exit;

+ 9 - 3
Quick.AutoMapper.pas

@@ -1,13 +1,13 @@
 { ***************************************************************************
 
-  Copyright (c) 2015-2020 Kike Pérez
+  Copyright (c) 2015-2021 Kike Pérez
 
   Unit        : Quick.AutoMapper
   Description : Auto Mapper object properties
   Author      : Kike Pérez
   Version     : 1.5
   Created     : 25/08/2018
-  Modified    : 07/04/2020
+  Modified    : 07/04/2021
 
   This file is part of QuickLib: https://github.com/exilon/QuickLib
 
@@ -295,7 +295,8 @@ begin
           except
             on E : Exception do raise EAUtoMapperError.CreateFmt('Error mapping property "%s" : %s',[tgtprop.Name,e.message]);
           end;
-          if clname.StartsWith('TObjectList') then TObjListMapper.Map(rType.GetProperty(tgtprop.Name).GetValue(aSrcObj).AsObject,obj,aCustomMapping)
+          if clname.StartsWith('TList') then TListMapper.Map(rType.GetProperty(tgtprop.Name).GetValue(aSrcObj).AsObject,obj,aCustomMapping)
+          else if clname.StartsWith('TObjectList') then TObjListMapper.Map(rType.GetProperty(tgtprop.Name).GetValue(aSrcObj).AsObject,obj,aCustomMapping)
             else TObjMapper.Map(rType.GetProperty(tgtprop.Name).GetValue(aSrcObj).AsObject,obj,aCustomMapping)
           {$ELSE}
           TObjMapper.Map(GetObjectProp(aSrcObj,tgtprop.Name),obj,aCustomMapping);
@@ -469,6 +470,11 @@ begin
       tkChar, tkString, tkWChar, tkWString : TList<string>(aTgtList).Capacity := value.GetArrayLength;
       tkInteger, tkInt64 : TList<Integer>(aTgtList).Capacity := value.GetArrayLength;
       tkFloat : TList<Extended>(aTgtList).Capacity := value.GetArrayLength;
+      tkRecord :
+        begin
+          TObjMapper.Map(aSrcList,aTgtList,aCustomMapping);
+          exit;
+        end;
       else TList<TObject>(aTgtList).Capacity := value.GetArrayLength;
     end;
 

+ 96 - 24
Quick.Azure.pas

@@ -1,13 +1,13 @@
 { ***************************************************************************
 
-  Copyright (c) 2015-2020 Kike Pérez
+  Copyright (c) 2015-2021 Kike Pérez
 
   Unit        : Quick.Azure
   Description : Azure blobs operations
   Author      : Kike Pérez
   Version     : 1.4
   Created     : 27/08/2015
-  Modified    : 07/04/2020
+  Modified    : 21/10/2021
 
   This file is part of QuickLib: https://github.com/exilon/QuickLib
 
@@ -76,6 +76,7 @@ type
       procedure SetAzureProtocol(azProtocol : TAzureProtocol);
       function FileToArray(cFilename : string) : TArray<Byte>;
       function StreamToArray(cStream : TStream) : TArray<Byte>;
+      function ByteContent(DataStream: TStream): TBytes;
       function GMT2DateTime(const gmtdate : string):TDateTime;
       function CheckContainer(const aContainer : string) : string;
       function RemoveFirstSlash(const aValue : string) : string;
@@ -165,13 +166,7 @@ var
 begin
   fs := TFileStream.Create(cFilename, fmOpenRead);
   try
-    bs := TBytesStream.Create(Result);
-    try
-      bs.LoadFromStream(fs);
-      Result := bs.Bytes;
-    finally
-      bs.Free
-    end;
+    Result := ByteContent(fs);
   finally
     fs.Free;
   end;
@@ -190,6 +185,19 @@ begin
   end;
 end;
 
+function TQuickAzure.ByteContent(DataStream: TStream): TBytes;
+var
+  Buffer: TBytes;
+begin
+  if not Assigned(DataStream) then Exit(nil);
+  SetLength(Buffer, DataStream.Size);
+  // the content may have been read
+  DataStream.Position := 0;
+  if DataStream.Size > 0 then
+  DataStream.Read(Buffer[0], DataStream.Size);
+  Result := Buffer;
+end;
+
 function TQuickAzure.GMT2DateTime(const gmtdate : string):TDateTime;
   function GetMonthDig(Value : string):Integer;
   const
@@ -278,7 +286,6 @@ var
   container : string;
   blobname : string;
 begin
-  Result := False;
   BlobService := TAzureBlobService.Create(fconAzure);
   try
     container := CheckContainer(azContainer);
@@ -302,11 +309,12 @@ end;
 function TQuickAzure.PutBlob(const azContainer : string; cStream : TStream; const azBlobName : string; out azResponseInfo : TAzureResponseInfo) : Boolean;
 var
   BlobService : TAzureBlobService;
-  Content : TArray<Byte>;
+  Content : TBytes;
   CloudResponseInfo : TCloudResponseInfo;
   container : string;
   blobname : string;
 begin
+  Result := False;
   azResponseInfo.StatusCode := 500;
   if cStream.Size = 0 then
   begin
@@ -322,7 +330,7 @@ begin
       BlobService.Timeout := fTimeout;
       CloudResponseInfo := TCloudResponseInfo.Create;
       try
-        Content := StreamToArray(cStream);
+        Content := ByteContent(cStream);
         Result := BlobService.PutBlockBlob(container,blobname,Content,EmptyStr,nil,nil,CloudResponseInfo);
         azResponseInfo := GetResponseInfo(CloudResponseInfo);
       finally
@@ -349,7 +357,6 @@ var
   container : string;
   blobname : string;
 begin
-  Result := False;
   container := CheckContainer(azContainer);
   blobname := RemoveFirstSlash(azBlobName);
   BlobService := TAzureBlobService.Create(fconAzure);
@@ -380,7 +387,7 @@ function TQuickAzure.GetBlob(const azContainer, azBlobName : string; out azRespo
 begin
   Stream := TMemoryStream.Create;
   try
-    GetBlob(azContainer,azBlobName,azResponseInfo,TStream(Stream));
+    Result := GetBlob(azContainer,azBlobName,azResponseInfo,TStream(Stream));
   except
     Stream.Free;
   end;
@@ -398,7 +405,6 @@ var
   container : string;
   blobname : string;
 begin
-  Result := False;
   container := CheckContainer(azContainer);
   blobname := RemoveFirstSlash(azBlobName);
   BlobService := TAzureBlobService.Create(fconAzure);
@@ -431,7 +437,6 @@ var
   sourceblobname : string;
   targetblobname : string;
 begin
-  Result := False;
   sourcecontainer := CheckContainer(azSourceContainer);
   targetcontainer := CheckContainer(azTargetContainer);
   sourceblobname := RemoveFirstSlash(azSourceBlobName);
@@ -557,7 +562,6 @@ var
   container : string;
   blobname : string;
 begin
-  Result := False;
   container := CheckContainer(azContainer);
   blobname := RemoveFirstSlash(azBlobName);
   BlobService := TAzureBlobService.Create(fconAzure);
@@ -590,6 +594,7 @@ var
   xmlresp : string;
   folder : string;
   prop : TPair<string,string>;
+  previousMaker : string;
 begin
   Result := TBlobList.Create(True);
   cNextMarker := '';
@@ -602,7 +607,8 @@ begin
     repeat
       CloudResponseInfo := TCloudResponseInfo.Create;
       try
-        azBlobList := BlobService.ListBlobs(azContainer,azBlobsStartWith,'/',cNextMarker,100,[],cNextMarker,blobprefix,xmlresp,CloudResponseInfo);
+        previousMaker := cNextMarker;
+        azBlobList := BlobService.ListBlobs(azContainer,azBlobsStartWith,'/',previousMaker,100,[],cNextMarker,blobprefix,xmlresp,CloudResponseInfo);
         azResponseInfo := GetResponseInfo(CloudResponseInfo);
         if Assigned(azBlobList) then Result.Capacity := High(azBlobList);
         //get folders (prefix)
@@ -650,6 +656,8 @@ var
   cNextMarker : string;
   AzParams : TStrings;
   container : string;
+  xmlresp : string;
+  previousMarker : string;
 begin
   Result := TBlobList.Create(True);
   cNextMarker := '';
@@ -698,6 +706,63 @@ begin
 end;
 {$ENDIF}
 
+{$IFDEF DELPHITOKYO_UP}
+function TQuickAzure.ListBlobsNames(const azContainer, azBlobsStartWith : string; Recursive : Boolean; out azResponseInfo : TAzureResponseInfo) : TStrings;
+var
+  BlobService : TAzureBlobService;
+  azBlob : TAzureBlobItem;
+  azBlobList : TArray<TAzureBlobItem>;
+  Blob : TAzureBlobObject;
+  CloudResponseInfo : TCloudResponseInfo;
+  cNextMarker : string;
+  container : string;
+  prefix : string;
+  blobprefix : TArray<string>;
+  xmlresp : string;
+  folder : string;
+  prop : TPair<string,string>;
+  previousMaker : string;
+begin
+  Result := TStringList.Create;
+  cNextMarker := '';
+  container := CheckContainer(azContainer);
+  BlobService := TAzureBlobService.Create(fconAzure);
+  try
+    if Recursive then prefix := ''
+      else prefix := '/';
+    BlobService.Timeout := fTimeout;
+    repeat
+      CloudResponseInfo := TCloudResponseInfo.Create;
+      try
+        previousMaker := cNextMarker;
+        azBlobList := BlobService.ListBlobs(azContainer,azBlobsStartWith,'/',previousMaker,100,[],cNextMarker,blobprefix,xmlresp,CloudResponseInfo);
+        azResponseInfo := GetResponseInfo(CloudResponseInfo);
+        if Assigned(azBlobList) then Result.Capacity := High(azBlobList);
+        //get folders (prefix)
+        for folder in blobprefix do
+        begin
+          Blob := TAzureBlobObject.Create;
+          if folder.EndsWith('/') then Blob.Name := RemoveLastChar(folder)
+            else Blob.Name := folder;
+          Result.Add(Copy(Blob.Name,Blob.Name.LastDelimiter('/')+2,Blob.Name.Length));
+        end;
+        //get files (blobs)
+        if Assigned(azBlobList) then
+        begin
+          for azBlob in azBlobList do
+          begin
+            Result.Add(azBlob.Name);
+          end;
+        end;
+      finally
+        CloudResponseInfo.Free;
+      end;
+    until (cNextMarker = '') or (azResponseInfo.StatusCode <> 200);
+  finally
+    BlobService.Free;
+  end;
+end;
+{$ELSE}
 function TQuickAzure.ListBlobsNames(const azContainer, azBlobsStartWith : string; Recursive : Boolean; out azResponseInfo : TAzureResponseInfo) : TStrings;
 var
   BlobService : TAzureBlobService;
@@ -746,6 +811,7 @@ begin
     CloudResponseInfo.Free;
   end;
 end;
+{$ENDIF}
 
 function TQuickAzure.ExistsContainer(const azContainer : string) : Boolean;
 var
@@ -833,11 +899,14 @@ begin
   try
     BlobService.Timeout := fTimeout;
     CloudResponseInfo := TCloudResponseInfo.Create;
-    Result := BlobService.CreateContainer(azContainer,nil,azPublicAccess,CloudResponseInfo);
-    azResponseInfo := GetResponseInfo(CloudResponseInfo);
+    try
+      Result := BlobService.CreateContainer(azContainer,nil,azPublicAccess,CloudResponseInfo);
+      azResponseInfo := GetResponseInfo(CloudResponseInfo);
+    finally
+      CloudResponseInfo.Free;
+    end;
   finally
     BlobService.Free;
-    CloudResponseInfo.Free;
   end;
 end;
 
@@ -853,11 +922,14 @@ begin
   try
     BlobService.Timeout := fTimeout;
     CloudResponseInfo := TCloudResponseInfo.Create;
-    Result := BlobService.DeleteContainer(azContainer,CloudResponseInfo);
-    azResponseInfo := GetResponseInfo(CloudResponseInfo);
+    try
+      Result := BlobService.DeleteContainer(azContainer,CloudResponseInfo);
+      azResponseInfo := GetResponseInfo(CloudResponseInfo);
+    finally
+      CloudResponseInfo.Free;
+    end;
   finally
     BlobService.Free;
-    CloudResponseInfo.Free;
   end;
 end;
 

+ 20 - 0
Quick.Base64.pas

@@ -33,6 +33,7 @@ unit Quick.Base64;
 interface
 
 uses
+  System.SysUtils,
   {$IFDEF DELPHIXE7_UP}
   System.NetEncoding;
   {$ELSE}
@@ -42,6 +43,10 @@ uses
 
 function Base64Encode(const Input: string): string;
 function Base64Decode(const Input: string): string;
+{$IFDEF DELPHIXE7_UP}
+function Base64DecodeFromBinary(const Input: string) : string;
+function Base64DecodeToBytes(const Input: string) : TBytes;
+{$ENDIF}
 
 implementation
 
@@ -63,5 +68,20 @@ begin
   {$ENDIF}
 end;
 
+{$IFDEF DELPHIXE7_UP}
+function Base64DecodeFromBinary(const Input: string) : string;
+var
+  b : TBytes;
+begin
+  b := TNetEncoding.Base64.DecodeStringToBytes(Input);
+  Result := TEncoding.ANSI.GetString(b);
+end;
+
+function Base64DecodeToBytes(const Input: string) : TBytes;
+begin
+  Result := TNetEncoding.Base64.DecodeStringToBytes(Input);
+end;
+{$ENDIF}
+
 end.
 

+ 8 - 2
Quick.Chrono.pas

@@ -1,13 +1,13 @@
 { ***************************************************************************
 
-  Copyright (c) 2015-2020 Kike Pérez
+  Copyright (c) 2015-2021 Kike Pérez
 
   Unit        : Quick.Chrono
   Description : Chronometers time elapsed and estimated time to do a task
   Author      : Kike Pérez
   Version     : 1.5
   Created     : 27/08/2015
-  Modified    : 27/06/2020
+  Modified    : 06/05/2021
 
   This file is part of QuickLib: https://github.com/exilon/QuickLib
 
@@ -134,6 +134,7 @@ type
     function GetIsRunning: Boolean;
   public
     constructor Create(const StartOnCreate: Boolean = false);
+    class function NewChrono(const StartOnCreate: Boolean = True) : IChronometer;
     procedure Start;
     procedure Stop;
     procedure Reset;
@@ -263,6 +264,11 @@ begin
   Result := fIsRunning;
 end;
 
+class function TChronometer.NewChrono(const StartOnCreate: Boolean = True) : IChronometer;
+begin
+  Result := TChronometer.Create(StartOnCreate);
+end;
+
 class function TChronometer.MillisecondsToString(aMilliseconds : Int64; LongFormat : Boolean = False) : string;
 begin
   Result := MillisecondsToString(aMilliseconds.ToExtended,pfTruncate,LongFormat);

+ 18 - 4
Quick.Collections.pas

@@ -1,13 +1,13 @@
 { ***************************************************************************
 
-  Copyright (c) 2016-2020 Kike Pérez
+  Copyright (c) 2016-2022 Kike Pérez
 
   Unit        : Quick.Collections
   Description : Generic Collections
   Author      : Kike Pérez
   Version     : 1.2
   Created     : 07/03/2020
-  Modified    : 07/04/2020
+  Modified    : 27/01/2022
 
   This file is part of QuickLib: https://github.com/exilon/QuickLib
 
@@ -286,7 +286,11 @@ end;
 
 function TxList<T>.ExtractAt(Index: Integer): T;
 begin
+  {$If Defined(FPC) OR Defined(DELPHIRX102_UP)}
   Result := fList.ExtractAt(Index);
+  {$ELSE}
+  Result := fList.Extract(fList[Index]);
+  {$ENDIF}
 end;
 
 function TxList<T>.ExtractItem(const Value: T; Direction: TDirection): T;
@@ -296,7 +300,8 @@ end;
 
 function TxList<T>.First: T;
 begin
-  Result := fList.First;
+  if fList.Count > 0 then Result := fList.First
+    else Result := default(T);
 end;
 
 procedure TxList<T>.FromList(const aList: TList<T>);
@@ -367,7 +372,11 @@ end;
 
 procedure TxList<T>.InsertRange(Index: Integer; const Values: array of T; Count: Integer);
 begin
+  {$If Defined(FPC) OR Defined(DELPHIRX102_UP)}
   fList.InsertRange(Index,Values,Count);
+  {$ELSE}
+  fList.InsertRange(Index,Values);
+  {$ENDIF}
 end;
 
 procedure TxList<T>.InsertRange(Index: Integer; const Values: array of T);
@@ -377,7 +386,8 @@ end;
 
 function TxList<T>.Last: T;
 begin
-  Result := fList.Last;
+  if fList.Count > 0 then Result := fList.Last
+    else Result := default(T)
 end;
 
 function TxList<T>.LastIndexOf(const Value: T): Integer;
@@ -451,7 +461,11 @@ end;
 
 function TxList<T>.Where(const aMatchString: string; aUseRegEx: Boolean): ILinqArray<T>;
 begin
+  {$IFDEF DELPHIRX104_UP}
+  Result := TLinqArray<T>.Create(fList.PList^);
+  {$ELSE}
   Result := TLinqArray<T>.Create(fList.ToArray);
+  {$ENDIF}
   Result.Where(aMatchString, aUseRegEx);
 end;
 

+ 464 - 61
Quick.Commons.pas

@@ -1,13 +1,13 @@
-{ ***************************************************************************
+{ ***************************************************************************
 
-  Copyright (c) 2016-2020 Kike Pérez
+  Copyright (c) 2016-2022 Kike P�rez
 
   Unit        : Quick.Commons
   Description : Common functions
-  Author      : Kike Pérez
+  Author      : Kike P�rez
   Version     : 2.0
   Created     : 14/07/2017
-  Modified    : 06/08/2020
+  Modified    : 19/01/2022
 
   This file is part of QuickLib: https://github.com/exilon/QuickLib
 
@@ -39,6 +39,7 @@ interface
     Types,
     {$IFDEF MSWINDOWS}
       Windows,
+      ActiveX,
       ShlObj,
     {$ENDIF MSWINDOWS}
     {$IFDEF FPC}
@@ -54,6 +55,9 @@ interface
     Androidapi.Helpers,
     Androidapi.JNI.JavaTypes,
     Androidapi.JNI.GraphicsContentViewText,
+    {$IFDEF DELPHIRX103_UP}
+      Androidapi.JNI.App,
+    {$ENDIF}
     {$ENDIF}
     {$IFDEF IOS}
     iOSapi.UIKit,
@@ -86,9 +90,9 @@ const
   LOG_ALL = [etInfo, etSuccess, etWarning, etError, etDebug, etDone, etTrace, etCritical, etException];
   LOG_DEBUG = [etInfo,etSuccess,etWarning,etError,etDebug];
   {$IFDEF DELPHIXE7_UP}
-  EventStr : array of string = ['INFO','SUCC','WARN','ERROR','DEBUG','TRACE'];
+  EventStr : array of string = ['INFO','SUCC','WARN','ERROR','DEBUG','DONE','TRACE','CRITICAL','EXCEPTION'];
   {$ELSE}
-  EventStr : array[0..5] of string = ('INFO','SUCC','WARN','ERROR','DEBUG','TRACE');
+  EventStr : array[0..8] of string = ('INFO','SUCC','WARN','ERROR','DEBUG','DONE','TRACE','CRITICAL','EXCEPTION');
   {$ENDIF}
 type
   TPasswordComplexity = set of (pfIncludeNumbers,pfIncludeSigns);
@@ -226,6 +230,47 @@ type
     procedure Clear;
   end;
 
+  {$IFDEF DELPHIXE7_UP}
+  TDateTimeHelper = record helper for TDateTime
+  public
+    function ToSQLString : string;
+    procedure FromNow;
+    procedure FromUTC(const aUTCTime : TDateTime);
+    function IncDay(const aValue : Cardinal = 1) : TDateTime;
+    function DecDay(const aValue : Cardinal = 1) : TDateTime;
+    function IncMonth(const aValue : Cardinal = 1) : TDateTime;
+    function DecMonth(const aValue : Cardinal = 1) : TDateTime;
+    function IncYear(const aValue : Cardinal = 1) : TDateTime;
+    function DecYear(const aValue : Cardinal = 1) : TDateTime;
+    function IsEqualTo(const aDateTime : TDateTime) : Boolean;
+    function IsAfter(const aDateTime : TDateTime) : Boolean;
+    function IsBefore(const aDateTime : TDateTime) : Boolean;
+    function IsSameDay(const aDateTime : TDateTime) : Boolean;
+    function IsSameTime(const aTime : TTime) : Boolean;
+    function DayOfTheWeek : Word;
+    function ToJsonFormat : string;
+    function ToGMTFormat: string;
+    function ToTimeStamp : TTimeStamp;
+    function ToUTC : TDateTime;
+    function ToMilliseconds : Int64;
+    function ToString : string;
+    function Date : TDate;
+    function Time : TTime;
+    function IsAM : Boolean;
+    function IsPM : Boolean;
+  end;
+
+  TDateHelper = record helper for TDate
+  public
+    function ToString : string;
+  end;
+
+  TTimeHelper = record helper for TTime
+  public
+    function ToString : string;
+  end;
+  {$ENDIF}
+
   EEnvironmentPath = class(Exception);
   EShellError = class(Exception);
 
@@ -240,7 +285,15 @@ type
   //converts a Windows path to Unix path
   function WindowsToUnixPath(const WindowsPath: string): string;
   //corrects malformed urls
-  function CorrectURLPath(cUrl : string) : string;
+  function CorrectURLPath(const cUrl : string) : string;
+  //get url parts
+  function UrlGetProtocol(const aUrl : string) : string;
+  function UrlGetHost(const aUrl : string) : string;
+  function UrlGetPath(const aUrl : string) : string;
+  function UrlGetQuery(const aUrl : string) : string;
+  function UrlRemoveProtocol(const aUrl : string) : string;
+  function UrlRemoveQuery(const aUrl : string) : string;
+  function UrlSimpleEncode(const aUrl : string) : string;
   //get typical environment paths as temp, desktop, etc
   procedure GetEnvironmentPaths;
   {$IFDEF MSWINDOWS}
@@ -277,7 +330,7 @@ type
   //returns n times a char
   function FillStr(const C : Char; const Count : Integer) : string;
   //checks if string exists in array of string
-  function StrInArray(const aValue : string; const aInArray : array of string) : Boolean;
+  function StrInArray(const aValue : string; const aInArray : array of string; aCaseSensitive : Boolean = True) : Boolean;
   //checks if integer exists in array of integer
   function IntInArray(const aValue : Integer; const aInArray : array of Integer) : Boolean;
   //check if array is empty
@@ -302,12 +355,20 @@ type
   function GetLoggedUserName : string;
   //returns computer name
   function GetComputerName : string;
+  //check if remote desktop session
+  {$IFDEF MSWINDOWS}
+  function IsRemoteSession : Boolean;
+  {$ENDIF}
+  //extract domain and user name from user login
+  function ExtractDomainAndUser(const aUser : string; out oDomain, oUser : string) : Boolean;
   //Changes incorrect delims in path
   function NormalizePathDelim(const cPath : string; const Delim : Char) : string;
   //combine paths normalized with delim
   function CombinePaths(const aFirstPath, aSecondPath: string; aDelim : Char): string;
+  //Removes firs segment of a path
+  function RemoveFirstPathSegment(const cdir : string) : string;
   //Removes last segment of a path
-  function RemoveLastPathSegment(cDir : string) : string;
+  function RemoveLastPathSegment(const cDir : string) : string;
   //returns path delimiter if found
   function GetPathDelimiter(const aPath : string) : string;
   //returns first segment of a path
@@ -343,19 +404,23 @@ type
   //save stream to file
   procedure SaveStreamToFile(aStream : TStream; const aFilename : string);
   //save stream to string
-  function StreamToString(aStream : TStream) : string;
-  function StreamToString2(const aStream: TStream; const aEncoding: TEncoding): string;
+  function StreamToString(const aStream: TStream; const aEncoding: TEncoding): string;
+  function StreamToStringEx(aStream : TStream) : string;
   //save string to stream
-  procedure StringToStream(const aStr : string; aStream : TStream);
-  procedure StringToStream2(const aStr : string; aStream : TStream);
+  procedure StringToStream(const aStr : string; aStream : TStream; const aEncoding: TEncoding);
+  procedure StringToStreamEx(const aStr : string; aStream : TStream);
   //returns a real comma separated text from stringlist
   function CommaText(aList : TStringList) : string; overload;
   //returns a real comma separated text from array of string
   function CommaText(aArray : TArray<string>) : string; overload;
-  //returns a string CRLF from array of string
-  function ArrayToString(aArray : TArray<string>) : string;
+  //returns a string CRLF separated from array of string
+  function ArrayToString(aArray : TArray<string>) : string; overload;
+  //returns a string with separator from array of string
+  function ArrayToString(aArray : TArray<string>; aSeparator : string) : string; overload;
   //converts TStrings to array
-  function StringsToArray(aStrings : TStrings) : TArray<string>;
+  function StringsToArray(aStrings : TStrings) : TArray<string>; overload;
+  //converts string comma or semicolon separated to array
+  function StringsToArray(const aString : string) : TArray<string>; overload;
   {$IFDEF MSWINDOWS}
   //process messages on console applications
   procedure ProcessMessages;
@@ -380,6 +445,7 @@ type
   //get simple quoted or dequoted string
   function SpQuotedStr(const str : string): string;
   function UnSpQuotedStr(const str : string): string;
+  function UnQuotedStr(const str : string; const aQuote : Char) : string;
   //ternary operator
   function Ifx(aCondition : Boolean; const aIfIsTrue, aIfIsFalse : string) : string; overload;
   function Ifx(aCondition : Boolean; const aIfIsTrue, aIfIsFalse : Integer) : Integer; overload;
@@ -502,7 +568,7 @@ begin
     until NumNumbers = MinNumbers;
   end;
   //checks if need include signs
-  if pfIncludeNumbers in Complexity then
+  if pfIncludeSigns in Complexity then
   begin
     MinSigns := Round(PasswordLength / 10 * 1);
     NumSigns := 0;
@@ -544,7 +610,7 @@ begin
   Result := StringReplace(WindowsPath, '\', '/',[rfReplaceAll, rfIgnoreCase]);
 end;
 
-function CorrectURLPath(cUrl : string) : string;
+function CorrectURLPath(const cUrl : string) : string;
 var
   nurl : string;
 begin
@@ -554,6 +620,65 @@ begin
   //TNetEncoding.Url.Encode()
 end;
 
+function UrlGetProtocol(const aUrl : string) : string;
+begin
+  Result := aUrl.SubString(0,aUrl.IndexOf('://'));
+end;
+
+function UrlGetHost(const aUrl : string) : string;
+var
+  url : string;
+  len : Integer;
+begin
+  url := UrlRemoveProtocol(aUrl);
+
+  if url.Contains('/') then len := url.IndexOf('/')
+    else len := url.Length;
+
+  Result := url.SubString(0,len);
+end;
+
+function UrlGetPath(const aUrl : string) : string;
+var
+  url : string;
+  len : Integer;
+begin
+  url := UrlRemoveProtocol(aUrl);
+  if not url.Contains('/') then Exit('');
+  len := url.IndexOf('?');
+  if len < 0 then len := url.Length
+    else len := url.IndexOf('?') - url.IndexOf('/');
+  Result := url.Substring(url.IndexOf('/'),len);
+end;
+
+function UrlGetQuery(const aUrl : string) : string;
+begin
+  if not aUrl.Contains('?') then Exit('');
+
+  Result := aUrl.Substring(aUrl.IndexOf('?')+1);
+end;
+
+function UrlRemoveProtocol(const aUrl : string) : string;
+var
+  pos : Integer;
+begin
+  pos := aUrl.IndexOf('://');
+  if pos < 0 then pos := 0
+    else pos := pos + 3;
+  Result := aUrl.SubString(pos, aUrl.Length);
+end;
+
+function UrlRemoveQuery(const aUrl : string) : string;
+begin
+  if not aUrl.Contains('?') then Exit(aUrl);
+  Result := aUrl.Substring(0,aUrl.IndexOf('?'));
+end;
+
+function UrlSimpleEncode(const aUrl : string) : string;
+begin
+  Result := StringReplace(aUrl,' ','%20',[rfReplaceAll]);
+end;
+
 procedure GetEnvironmentPaths;
 begin
   //gets path
@@ -587,15 +712,25 @@ end;
 {$IFDEF MSWINDOWS}
 function GetSpecialFolderPath(folderID : Integer) : string;
 var
+  shellMalloc: IMalloc;
   ppidl: PItemIdList;
 begin
-  SHGetSpecialFolderLocation(0, folderID, ppidl);
-  SetLength(Result, MAX_PATH);
-  if not SHGetPathFromIDList(ppidl,{$IFDEF FPC}PAnsiChar(Result){$ELSE}PChar(Result){$ENDIF}) then
-  begin
-    raise EShellError.create(Format('GetSpecialFolderPath: Invalid PIPL (%d)',[folderID]));
+  ppidl := nil;
+  try
+    if SHGetMalloc(shellMalloc) = NOERROR then
+    begin
+      SHGetSpecialFolderLocation(0, folderID, ppidl);
+      SetLength(Result, MAX_PATH);
+      if not SHGetPathFromIDList(ppidl,{$IFDEF FPC}PAnsiChar(Result){$ELSE}PChar(Result){$ENDIF}) then
+      begin
+        raise EShellError.create(Format('GetSpecialFolderPath: Invalid PIPL (%d)',[folderID]));
+      end;
+      SetLength(Result, lStrLen({$IFDEF FPC}PAnsiChar(Result){$ELSE}PChar(Result){$ENDIF}));
+    end;
+  finally
+    if ppidl <> nil then
+      shellMalloc.Free(ppidl);
   end;
-  SetLength(Result, lStrLen({$IFDEF FPC}PAnsiChar(Result){$ELSE}PChar(Result){$ENDIF}));
 end;
 
 function Is64bitOS : Boolean;
@@ -624,7 +759,10 @@ function HasConsoleOutput : Boolean;
   begin
     try
       stout := GetStdHandle(Std_Output_Handle);
-      Win32Check(stout <> Invalid_Handle_Value);
+      {$WARN SYMBOL_PLATFORM OFF}
+      //Allready checked that we are on a windows platform
+        Win32Check(stout <> Invalid_Handle_Value);
+      {$WARN SYMBOL_PLATFORM ON}
       Result := stout <> 0;
     except
       Result := False;
@@ -731,13 +869,20 @@ begin
 end;
 
 
-function StrInArray(const aValue : string; const aInArray : array of string) : Boolean;
+function StrInArray(const aValue : string; const aInArray : array of string; aCaseSensitive : Boolean = True) : Boolean;
 var
   s : string;
 begin
   for s in aInArray do
   begin
-    if s = aValue then Exit(True);
+    if aCaseSensitive then
+    begin
+      if s = aValue then Exit(True);
+    end
+    else
+    begin
+      if CompareText(aValue,s) = 0 then Exit(True);
+    end;
   end;
   Result := False;
 end;
@@ -897,7 +1042,11 @@ function GetLoggedUserName : string;
     {$IFDEF POSIX}
     try
       plogin := getlogin;
+      {$IFDEF NEXTGEN}
+      Result := string(plogin);
+      {$ELSE}
       Result := Copy(plogin,1,Length(Trim(plogin)));
+      {$ENDIF}
     except
       Result := 'N/A';
     end;
@@ -983,6 +1132,36 @@ function GetComputerName : string;
   {$ENDIF}
 {$ENDIF}
 
+{$IFDEF MSWINDOWS}
+function IsRemoteSession : Boolean;
+const
+  SM_REMOTECONTROL      = $2001;
+  SM_REMOTESESSION      = $1000;
+begin
+  Result := (GetSystemMetrics(SM_REMOTESESSION) <> 0) or (GetSystemMetrics(SM_REMOTECONTROL) <> 0);
+end;
+{$ENDIF}
+
+function ExtractDomainAndUser(const aUser : string; out oDomain, oUser : string) : Boolean;
+begin
+  //check if domain specified into username
+  if aUser.Contains('\') then
+  begin
+    oDomain := Copy(aUser,Low(aUser),Pos('\',aUser)-1);
+    oUser := Copy(aUser,Pos('\',aUser)+1,aUser.Length);
+    Exit(True);
+  end
+  else if aUser.Contains('@') then
+  begin
+    oDomain := Copy(aUser,Pos('@',aUser)+1,aUser.Length);
+    oUser := Copy(aUser,Low(aUser),Pos('@',aUser)-1);
+    Exit(True);
+  end;
+  oDomain := '';
+  oUser := aUser;
+  Result := False;
+end;
+
 function NormalizePathDelim(const cPath : string; const Delim : Char) : string;
 begin
   if Delim = '\' then Result := StringReplace(cPath,'/',Delim,[rfReplaceAll])
@@ -990,9 +1169,12 @@ begin
 end;
 
 function CombinePaths(const aFirstPath, aSecondPath: string; aDelim : Char): string;
+var
+  path1 : string;
+  path2 : string;
 begin
-  var path1 := NormalizePathDelim(aFirstPath,aDelim);
-  var path2 := NormalizePathDelim(aSecondPath,aDelim);
+  path1 := NormalizePathDelim(aFirstPath,aDelim);
+  path2 := NormalizePathDelim(aSecondPath,aDelim);
   if path1.EndsWith(aDelim) then
   begin
     if path2.StartsWith(aDelim) then Result := path1 + path2.Substring(1)
@@ -1005,33 +1187,61 @@ begin
   end;
 end;
 
-function RemoveLastPathSegment(cDir : string) : string;
+function RemoveFirstPathSegment(const cdir : string) : string;
+var
+  posi : Integer;
+  delim : Char;
+  dir : string;
+  StartsWithDelim : Boolean;
+begin
+  if cDir.Contains('\') then delim := '\'
+    else if cDir.Contains('/') then delim := '/'
+      else
+      begin
+        Exit('');
+      end;
+
+  dir := NormalizePathDelim(cDir,delim);
+  if dir.StartsWith(delim) then
+  begin
+    dir := Copy(dir,2,dir.Length);
+    StartsWithDelim := True;
+  end
+  else StartsWithDelim := False;
+
+  if dir.CountChar(delim) = 0 then Exit('')
+    else posi := Pos(delim,dir)+1;
+  Result := Copy(dir,posi,dir.Length);
+  if (not Result.IsEmpty) and (StartsWithDelim) then Result := delim + Result;
+end;
+
+function RemoveLastPathSegment(const cDir : string) : string;
 var
   posi : Integer;
   delim : Char;
+  dir : string;
   EndsWithDelim : Boolean;
 begin
   if cDir.Contains('\') then delim := '\'
     else if cDir.Contains('/') then delim := '/'
       else
       begin
-        Result := '';
-        Exit;
+        Exit('');
       end;
-  NormalizePathDelim(cDir,delim);
+  dir := NormalizePathDelim(cDir,delim);
 
-  if cDir.EndsWith(delim) then
+  if dir.EndsWith(delim) then
   begin
-    cDir := Copy(cDir,1,cDir.Length-1);
+    dir := Copy(dir,1,dir.Length-1);
     EndsWithDelim := True;
   end
   else EndsWithDelim := False;
 
-  if cDir.CountChar(delim) > 1 then posi := cDir.LastDelimiter(delim)
-    else posi := Pos(delim,cDir)-1;
-  if posi = cDir.Length then posi := 0;
-  Result := Copy(cDir,1,posi);
-  if (Result <> '') and (EndsWithDelim) then Result := Result + delim;
+  if dir.CountChar(delim) > 1 then posi := dir.LastDelimiter(delim)
+    else posi := Pos(delim,dir)-1;
+  if posi = dir.Length then posi := 0;
+  Result := Copy(dir,1,posi);
+  if (not Result.IsEmpty) and (EndsWithDelim) then Result := Result + delim;
 end;
 
 function GetPathDelimiter(const aPath : string) : string;
@@ -1050,7 +1260,8 @@ begin
   if delimiter.IsEmpty then Exit(aPath);
   if aPath.StartsWith(delimiter) then spath := Copy(aPath,2,aPath.Length)
     else spath := aPath;
-  Result := Copy(spath,0,spath.IndexOf(delimiter));
+  if spath.Contains(delimiter) then Result := Copy(spath,0,spath.IndexOf(delimiter))
+    else Result := spath;
 end;
 
 function GetLastPathSegment(const aPath : string) : string;
@@ -1155,7 +1366,11 @@ end;
       var
         PkgInfo : JPackageInfo;
       begin
+        {$IFDEF DELPHIRX103_UP}
+        PkgInfo := TAndroidHelper.Activity.getPackageManager.getPackageInfo(TAndroidHelper.Activity.getPackageName,0);
+        {$ELSE}
         PkgInfo := SharedActivity.getPackageManager.getPackageInfo(SharedActivity.getPackageName,0);
+        {$ENDIF}
         Result := IntToStr(PkgInfo.VersionCode);
       end;
       {$ELSE} //IOS
@@ -1259,7 +1474,11 @@ end;
       var
         PkgInfo : JPackageInfo;
       begin
+        {$IFDEF DELPHIRX103_UP}
+        PkgInfo := TAndroidHelper.Activity.getPackageManager.getPackageInfo(TAndroidHelper.Activity.getPackageName,0);
+        {$ELSE}
         PkgInfo := SharedActivity.getPackageManager.getPackageInfo(SharedActivity.getPackageName,0);
+        {$ENDIF}
         Result := JStringToString(PkgInfo.versionName);
       end;
       {$ELSE} //IOS
@@ -1424,7 +1643,17 @@ begin
   end;
 end;
 
-function StreamToString(aStream : TStream) : string;
+function StreamToString(const aStream: TStream; const aEncoding: TEncoding): string;
+var
+  sbytes: TBytes;
+begin
+  aStream.Position := 0;
+  SetLength(sbytes, aStream.Size);
+  aStream.ReadBuffer(sbytes,aStream.Size);
+  Result := aEncoding.GetString(sbytes);
+end;
+
+function StreamToStringEx(aStream : TStream) : string;
 var
   ss : TStringStream;
 begin
@@ -1451,27 +1680,11 @@ begin
   end;
 end;
 
-function StreamToString2(const aStream: TStream; const aEncoding: TEncoding): string;
-var
-  sbytes: TBytes;
-begin
-  aStream.Position := 0;
-  SetLength(sbytes, aStream.Size);
-  aStream.ReadBuffer(sbytes,aStream.Size);
-  Result := aEncoding.GetString(sbytes);
-end;
-
-procedure StringToStream(const aStr : string; aStream : TStream);
-begin
-  aStream.Seek(0,soBeginning);
-  aStream.WriteBuffer(Pointer(aStr)^,aStr.Length * SizeOf(Char));
-end;
-
-procedure StringToStream2(const aStr : string; aStream : TStream);
+procedure StringToStream(const aStr : string; aStream : TStream; const aEncoding: TEncoding);
 var
   stream : TStringStream;
 begin
-  stream := TStringStream.Create(aStr,TEncoding.UTF8);
+  stream := TStringStream.Create(aStr,aEncoding);
   try
     aStream.CopyFrom(stream,stream.Size);
   finally
@@ -1479,6 +1692,11 @@ begin
   end;
 end;
 
+procedure StringToStreamEx(const aStr : string; aStream : TStream);
+begin
+  aStream.Seek(0,soBeginning);
+  aStream.WriteBuffer(Pointer(aStr)^,aStr.Length * SizeOf(Char));
+end;
 
 function CommaText(aList : TStringList) : string;
 var
@@ -1523,6 +1741,7 @@ var
   value : string;
   sb : TStringBuilder;
 begin
+  Result := '';
   if High(aArray) < 0 then Exit;
   sb := TStringBuilder.Create;
   try
@@ -1531,6 +1750,30 @@ begin
       sb.Append(value);
       sb.Append(#10#13);
     end;
+    Result := sb.ToString;
+  finally
+    sb.Free;
+  end;
+end;
+
+function ArrayToString(aArray : TArray<string>; aSeparator : string) : string;
+var
+  value : string;
+  sb : TStringBuilder;
+  isfirst : Boolean;
+begin
+  Result := '';
+  if High(aArray) < 0 then Exit;
+  isfirst := True;
+  sb := TStringBuilder.Create;
+  try
+    for value in aArray do
+    begin
+      if isfirst then isfirst := False
+        else sb.Append(aSeparator);
+      sb.Append(value);
+    end;
+    Result := sb.ToString;
   finally
     sb.Free;
   end;
@@ -1548,6 +1791,13 @@ begin
   end;
 end;
 
+function StringsToArray(const aString : string) : TArray<string>;
+var
+  item : string;
+begin
+  for item in aString.Split([';',',']) do Result := Result + [item.Trim];
+end;
+
 { TCounter }
 
 procedure TCounter.Init(aMaxValue : Integer);
@@ -1843,7 +2093,7 @@ end;
 
 function DateTimeToSQL(aDateTime : TDateTime) : string;
 begin
-  Result := FormatDateTime('YYYYMMDD hh:mm:ss',aDateTime);
+  Result := FormatDateTime('YYYY-MM-DD hh:mm:ss',aDateTime);
 end;
 
 function IsInteger(const aValue : string) : Boolean;
@@ -1919,6 +2169,12 @@ begin
   end;
 end;
 
+function UnQuotedStr(const str : string; const aQuote : Char) : string;
+begin
+  if (str.Length > 0) and (str[Low(str)] = aQuote) and (str[High(str)] = aQuote) then Result := Copy(str, Low(str)+1, High(str) - 2)
+    else Result := str;
+end;
+
 function Ifx(aCondition : Boolean; const aIfIsTrue, aIfIsFalse : string) : string;
 begin
   if aCondition then Result := aIfIsTrue else Result := aIfIsFalse;
@@ -1956,6 +2212,151 @@ end;
   {$ENDIF}
 {$ENDIF}
 
+{ TDateTimeHelper }
+
+{$IFDEF DELPHIXE7_UP}
+function TDateTimeHelper.ToSQLString : string;
+begin
+  Result := DateTimeToSQL(Self);
+end;
+
+procedure TDateTimeHelper.FromNow;
+begin
+  Self := Now;
+end;
+
+procedure TDateTimeHelper.FromUTC(const aUTCTime: TDateTime);
+begin
+  Self := UTCToLocalTime(aUTCTime);
+end;
+
+function TDateTimeHelper.IncDay(const aValue : Cardinal = 1) : TDateTime;
+begin
+  Result := System.DateUtils.IncDay(Self,aValue);
+end;
+
+function TDateTimeHelper.DecDay(const aValue : Cardinal = 1) : TDateTime;
+begin
+  Result := System.DateUtils.IncDay(Self,-aValue);
+end;
+
+function TDateTimeHelper.IncMonth(const aValue : Cardinal = 1) : TDateTime;
+begin
+  Result := SysUtils.IncMonth(Self,aValue);
+end;
+
+function TDateTimeHelper.DecMonth(const aValue : Cardinal = 1) : TDateTime;
+begin
+  Result := SysUtils.IncMonth(Self,-aValue);
+end;
+
+function TDateTimeHelper.IncYear(const aValue : Cardinal = 1) : TDateTime;
+begin
+  Result := System.DateUtils.IncYear(Self,aValue);
+end;
+
+function TDateTimeHelper.DecYear(const aValue : Cardinal = 1) : TDateTime;
+begin
+  Result := System.DateUtils.IncYear(Self,-aValue);
+end;
+
+function TDateTimeHelper.IsEqualTo(const aDateTime : TDateTime) : Boolean;
+begin
+  Result := Self = aDateTime;
+end;
+
+function TDateTimeHelper.IsAfter(const aDateTime : TDateTime) : Boolean;
+begin
+  Result := Self > aDateTime;
+end;
+
+function TDateTimeHelper.IsBefore(const aDateTime : TDateTime) : Boolean;
+begin
+  Result := Self < aDateTime;
+end;
+
+function TDateTimeHelper.IsSameDay(const aDateTime : TDateTime) : Boolean;
+begin
+  Result := System.DateUtils.SameDate(Self,aDateTime);
+end;
+
+function TDateTimeHelper.IsSameTime(const aTime : TTime) : Boolean;
+begin
+  Result := System.DateUtils.SameTime(Self,aTime);
+end;
+
+function TDateTimeHelper.DayOfTheWeek : Word;
+begin
+  Result := System.DateUtils.NthDayOfWeek(Self);
+end;
+
+function TDateTimeHelper.ToJsonFormat : string;
+begin
+  Result := DateTimeToJsonDate(Self);
+end;
+
+function TDateTimeHelper.ToGMTFormat : string;
+begin
+  Result := DateTimeToGMT(Self);
+end;
+
+function TDateTimeHelper.ToTimeStamp : TTimeStamp;
+begin
+  Result := DateTimeToTimeStamp(Self);
+end;
+
+function TDateTimeHelper.ToUTC : TDateTime;
+begin
+  Result := LocalTimeToUTC(Self);
+end;
+
+function TDateTimeHelper.ToMilliseconds : Int64;
+begin
+  {$IFDEF DELPHIRX104_ANDUP}
+  Result := System.DateUtils.DateTimeToMilliseconds(Self);
+  {$ELSE}
+  Result := System.DateUtils.MilliSecondOf(Self);
+  {$ENDIF}
+end;
+
+function TDateTimeHelper.ToString : string;
+begin
+  Result := DateTimeToStr(Self);
+end;
+
+function TDateTimeHelper.Date : TDate;
+begin
+  Result := System.DateUtils.DateOf(Self);
+end;
+
+function TDateTimeHelper.Time : TTime;
+begin
+  Result := System.DateUtils.TimeOf(Self);
+end;
+
+function TDateTimeHelper.IsAM : Boolean;
+begin
+  Result := System.DateUtils.IsAM(Self);
+end;
+
+function TDateTimeHelper.IsPM : Boolean;
+begin
+  Result := System.DateUtils.IsPM(Self);
+end;
+
+{ TDateHelper }
+function TDateHelper.ToString : string;
+begin
+  Result := DateToStr(Self);
+end;
+
+{ TTimeHelper }
+function TTimeHelper.ToString : string;
+begin
+  Result := TimeToStr(Self);
+end;
+{$ENDIF}
+
 {$IFNDEF NEXTGEN}
 initialization
   try
@@ -1974,6 +2375,8 @@ initialization
   end;
 {$ENDIF}
 
+
 end.
 
 
+

+ 1271 - 0
Quick.Conditions.pas

@@ -0,0 +1,1271 @@
+{ ***************************************************************************
+
+  Copyright (c) 2016-2021 Kike Pérez
+
+  Unit        : Quick.Conditions
+  Description : Conditions validator
+  Author      : Kike Pérez
+  Version     : 2.0
+  Created     : 05/05/2021
+  Modified    : 11/05/2021
+
+  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.Conditions;
+
+{$i QuickLib.inc}
+
+interface
+
+uses
+  System.SysUtils,
+  System.StrUtils,
+  Quick.Commons;
+
+type
+  ICondition = interface
+  ['{54F1E937-CE14-426A-9FC5-C6C7944915A2}']
+  end;
+
+  TCondition = class(TInterfacedObject,ICondition)
+  protected
+    fName : string;
+    fExceptionClass : ExceptClass;
+    fPostCondition : Boolean;
+  public
+    constructor Create;
+    procedure ThrowException(const aMsg : string); overload;
+    procedure ThrowException(const aMsg : string; aValues : array of const); overload;
+    procedure ThrowException(aExceptionClass : ExceptClass; const aMsg : string); overload;
+  end;
+
+  IStringCondition = interface(ICondition)
+  ['{B9591175-22E0-4624-94E2-B183DEE1F793}']
+    function WithExceptionOnFailure(aExceptionClass : ExceptClass) : IStringCondition;
+    function IsEmpty : IStringCondition; overload;
+    function IsEmpty(const aCustomMessage : string) : IStringCondition; overload;
+    function IsNotEmpty : IStringCondition; overload;
+    function IsNotEmpty(const aCustomMessage : string) : IStringCondition; overload;
+    function StartsWith(const aText : string; aIgnoreCase : Boolean = False) : IStringCondition; overload;
+    function StartsWith(const aText, aCustomMessage : string; aIgnoreCase : Boolean = False): IStringCondition; overload;
+    function DoesNotStartsWith(const aText : string; aIgnoreCase : Boolean = False) : IStringCondition; overload;
+    function DoesNotStartsWith(const aText, aCustomMessage : string; aIgnoreCase : Boolean = False) : IStringCondition; overload;
+    function EndsWith(const aText : string; aIgnoreCase : Boolean = False) : IStringCondition; overload;
+    function EndsWith(const aText, aCustomMessage : string; aIgnoreCase : Boolean = False) : IStringCondition; overload;
+    function DoesNotEndsWith(const aText : string; aIgnoreCase : Boolean = False) : IStringCondition; overload;
+    function DoesNotEndsWith(const aText,aCustomMessage : string; aIgnoreCase : Boolean = False) : IStringCondition; overload;
+    function Contains(const aText : string; aIgnoreCase : Boolean = False) : IStringCondition; overload;
+    function Contains(const aText, aCustomMessage : string; aIgnoreCase : Boolean = False) : IStringCondition; overload;
+    function DoesNotContains(const aText: string; aIgnoreCase: Boolean = False): IStringCondition; overload;
+    function DoesNotContains(const aText, aCustomMessage: string; aIgnoreCase: Boolean = False): IStringCondition; overload;
+    function HasLength(aLen : Integer) : IStringCondition; overload;
+    function HasLength(aLen : Integer; const aCustomMessage : string) : IStringCondition; overload;
+    function DoesNotHasLength(aLen : Integer) : IStringCondition; overload;
+    function DoesNotHasLength(aLen : Integer; const aCustomMessage : string) : IStringCondition; overload;
+    function IsLongerThan(aLen : Integer) : IStringCondition; overload;
+    function IsLongerThan(aLen : Integer; const aCustomMessage : string) : IStringCondition; overload;
+    function IsLongerOrEqual(aLen : Integer) : IStringCondition; overload;
+    function IsLongerOrEqual(aLen : Integer; const aCustomMessage : string) : IStringCondition; overload;
+    function IsShorterThan(aLen : Integer) : IStringCondition; overload;
+    function IsShorterThan(aLen : Integer; const aCustomMessage : string) : IStringCondition; overload;
+    function IsShorterOrEqual(aLen : Integer) : IStringCondition; overload;
+    function IsShorterOrEqual(aLen : Integer; const aCustomMessage : string) : IStringCondition; overload;
+    function HasLengthRange(aMin, aMax : Integer) : IStringCondition; overload;
+    function HasLengthRange(aMin, aMax : Integer; const aCustomMessage : string) : IStringCondition; overload;
+    function IsUpperCase : IStringCondition; overload;
+    function IsUpperCase(const aCustomMessage : string) : IStringCondition; overload;
+    function IsLowerCase : IStringCondition; overload;
+    function IsLowerCase(const aCustomMessage : string) : IStringCondition; overload;
+    function IsNotUpperCase : IStringCondition; overload;
+    function IsNotUpperCase(const aCustomMessage : string) : IStringCondition; overload;
+    function IsNotLowerCase : IStringCondition; overload;
+    function IsNotLowerCase(const aCustomMessage : string) : IStringCondition; overload;
+    function Evaluate(aExpression : Boolean) : IStringCondition; overload;
+    function Evaluate(aExpression : Boolean; const aCustomMessage : string) : IStringCondition; overload;
+  end;
+
+  IIntegerCondition = interface(ICondition)
+  ['{A34856DD-175B-40BB-BC64-CF131CB448C7}']
+    function WithExceptionOnFailure(aExceptionClass : ExceptClass) : IIntegerCondition;
+    function IsInRange(aMin, aMax : Int64) : IIntegerCondition; overload;
+    function IsInRange(aMin, aMax : Int64; const aCustomMessage : string) : IIntegerCondition; overload;
+    function IsNotInRange(aMin, aMax : Int64) : IIntegerCondition; overload;
+    function IsNotInRange(aMin, aMax : Int64; const aCustomMessage : string) : IIntegerCondition; overload;
+    function IsEqualTo(aValue : Int64) : IIntegerCondition; overload;
+    function IsEqualTo(aValue : Int64; const aCustomMessage : string) : IIntegerCondition; overload;
+    function IsNotEqualTo(aValue : Int64) : IIntegerCondition; overload;
+    function IsNotEqualTo(aValue : Int64; const aCustomMessage : string) : IIntegerCondition; overload;
+    function IsGreaterThan(aValue : Int64) : IIntegerCondition; overload;
+    function IsGreaterThan(aValue : Int64; const aCustomMessage : string) : IIntegerCondition; overload;
+    function IsNotGreaterThan(aValue : Int64) : IIntegerCondition; overload;
+    function IsNotGreaterThan(aValue : Int64; const aCustomMessage : string) : IIntegerCondition; overload;
+    function IsGreaterOrEqual(aValue : Int64) : IIntegerCondition; overload;
+    function IsGreaterOrEqual(aValue : Int64; const aCustomMessage : string) : IIntegerCondition; overload;
+    function IsNotGreaterOrEqual(aValue : Int64) : IIntegerCondition; overload;
+    function IsNotGreaterOrEqual(aValue : Int64; const aCustomMessage : string) : IIntegerCondition; overload;
+    function IsLessThan(aValue : Int64) : IIntegerCondition; overload;
+    function IsLessThan(aValue : Int64; const aCustomMessage : string) : IIntegerCondition; overload;
+    function IsNotLessThan(aValue : Int64) : IIntegerCondition; overload;
+    function IsNotLessThan(aValue : Int64; const aCustomMessage : string) : IIntegerCondition; overload;
+    function IsLessOrEqual(aValue : Int64) : IIntegerCondition; overload;
+    function IsLessOrEqual(aValue : Int64; const aCustomMessage : string) : IIntegerCondition; overload;
+    function IsNotLessOrEqual(aValue : Int64) : IIntegerCondition; overload;
+    function IsNotLessOrEqual(aValue : Int64; const aCustomMessage : string) : IIntegerCondition; overload;
+    function Evaluate(aExpression : Boolean) : IIntegerCondition; overload;
+    function Evaluate(aExpression : Boolean; const aCustomMessage : string) : IIntegerCondition; overload;
+  end;
+
+  IFloatCondition = interface(ICondition)
+  ['{D0237A24-A00F-4B96-BA7B-0FF9BE7363E5}']
+    function WithExceptionOnFailure(aExceptionClass : ExceptClass) : IFloatCondition;
+    function IsInRange(aMin, aMax : Extended) : IFloatCondition; overload;
+    function IsInRange(aMin, aMax : Extended; const aCustomMessage : string) : IFloatCondition; overload;
+    function IsNotInRange(aMin, aMax : Extended) : IFloatCondition; overload;
+    function IsNotInRange(aMin, aMax : Extended; const aCustomMessage : string) : IFloatCondition; overload;
+    function IsEqualTo(aValue : Extended) : IFloatCondition; overload;
+    function IsEqualTo(aValue : Extended; const aCustomMessage : string) : IFloatCondition; overload;
+    function IsNotEqualTo(aValue : Extended) : IFloatCondition; overload;
+    function IsNotEqualTo(aValue : Extended; const aCustomMessage : string) : IFloatCondition; overload;
+    function IsGreaterThan(aValue : Extended) : IFloatCondition; overload;
+    function IsGreaterThan(aValue : Extended; const aCustomMessage : string) : IFloatCondition; overload;
+    function IsNotGreaterThan(aValue : Extended) : IFloatCondition; overload;
+    function IsNotGreaterThan(aValue : Extended; const aCustomMessage : string) : IFloatCondition; overload;
+    function IsGreaterOrEqual(aValue : Extended) : IFloatCondition; overload;
+    function IsGreaterOrEqual(aValue : Extended; const aCustomMessage : string) : IFloatCondition; overload;
+    function IsNotGreaterOrEqual(aValue : Extended) : IFloatCondition; overload;
+    function IsNotGreaterOrEqual(aValue : Extended; const aCustomMessage : string) : IFloatCondition; overload;
+    function IsLessThan(aValue : Extended) : IFloatCondition; overload;
+    function IsLessThan(aValue : Extended; const aCustomMessage : string) : IFloatCondition; overload;
+    function IsNotLessThan(aValue : Extended) : IFloatCondition; overload;
+    function IsNotLessThan(aValue : Extended; const aCustomMessage : string) : IFloatCondition; overload;
+    function IsLessOrEqual(aValue : Extended) : IFloatCondition; overload;
+    function IsLessOrEqual(aValue : Extended; const aCustomMessage : string) : IFloatCondition; overload;
+    function IsNotLessOrEqual(aValue : Extended) : IFloatCondition; overload;
+    function IsNotLessOrEqual(aValue : Extended; const aCustomMessage : string) : IFloatCondition; overload;
+    function Evaluate(aExpression : Boolean) : IFloatCondition; overload;
+    function Evaluate(aExpression : Boolean; const aCustomMessage : string) : IFloatCondition; overload;
+  end;
+
+  IObjectCondition = interface(ICondition)
+  ['{497E21D2-7780-4C3B-B51E-921847491FC1}']
+    function WithExceptionOnFailure(aExceptionClass : ExceptClass) : IObjectCondition;
+    function IsNull : IObjectCondition; overload;
+    function IsNull(const aCustomMessage : string): IObjectCondition; overload;
+    function IsNotNull : IObjectCondition; overload;
+    function IsNotNull(const aCustomMessage : string) : IObjectCondition; overload;
+    function IsOfType(aClass : TClass) : IObjectCondition; overload;
+    function IsOfType(aClass : TClass; const aCustomMessage : string) : IObjectCondition; overload;
+    function DoesNotOfType(aClass : TClass) : IObjectCondition; overload;
+    function DoesNotOfType(aClass : TClass; const aCustomMessage : string) : IObjectCondition; overload;
+    function Evaluate(aExpression : Boolean) : IObjectCondition; overload;
+    function Evaluate(aExpression : Boolean; const aCustomMessage : string) : IObjectCondition; overload;
+  end;
+
+  TStringCondition = class(TCondition,IStringCondition)
+  private
+    fValue : string;
+  public
+    constructor Create(const aValue : string; const aName : string; aPostCondition : Boolean);
+    function WithExceptionOnFailure(aExceptionClass : ExceptClass) : IStringCondition;
+    function IsEmpty : IStringCondition; overload;
+    function IsEmpty(const aCustomMessage : string) : IStringCondition; overload;
+    function IsNotEmpty : IStringCondition; overload;
+    function IsNotEmpty(const aCustomMessage : string) : IStringCondition; overload;
+    function StartsWith(const aText : string; aIgnoreCase : Boolean = False) : IStringCondition; overload;
+    function StartsWith(const aText, aCustomMessage : string; aIgnoreCase : Boolean = False): IStringCondition; overload;
+    function DoesNotStartsWith(const aText : string; aIgnoreCase : Boolean = False) : IStringCondition; overload;
+    function DoesNotStartsWith(const aText, aCustomMessage : string; aIgnoreCase : Boolean = False) : IStringCondition; overload;
+    function EndsWith(const aText : string; aIgnoreCase : Boolean = False) : IStringCondition; overload;
+    function EndsWith(const aText, aCustomMessage : string; aIgnoreCase : Boolean = False) : IStringCondition; overload;
+    function DoesNotEndsWith(const aText : string; aIgnoreCase : Boolean = False) : IStringCondition; overload;
+    function DoesNotEndsWith(const aText,aCustomMessage : string; aIgnoreCase : Boolean = False) : IStringCondition; overload;
+    function Contains(const aText : string; aIgnoreCase : Boolean = False) : IStringCondition; overload;
+    function Contains(const aText, aCustomMessage : string; aIgnoreCase : Boolean = False) : IStringCondition; overload;
+    function DoesNotContains(const aText: string; aIgnoreCase: Boolean = False): IStringCondition; overload;
+    function DoesNotContains(const aText, aCustomMessage: string; aIgnoreCase: Boolean = False): IStringCondition; overload;
+    function HasLength(aLen : Integer) : IStringCondition; overload;
+    function HasLength(aLen : Integer; const aCustomMessage : string) : IStringCondition; overload;
+    function DoesNotHasLength(aLen : Integer) : IStringCondition; overload;
+    function DoesNotHasLength(aLen : Integer; const aCustomMessage : string) : IStringCondition; overload;
+    function IsLongerThan(aLen : Integer) : IStringCondition; overload;
+    function IsLongerThan(aLen : Integer; const aCustomMessage : string) : IStringCondition; overload;
+    function IsLongerOrEqual(aLen : Integer) : IStringCondition; overload;
+    function IsLongerOrEqual(aLen : Integer; const aCustomMessage : string) : IStringCondition; overload;
+    function IsShorterThan(aLen : Integer) : IStringCondition; overload;
+    function IsShorterThan(aLen : Integer; const aCustomMessage : string) : IStringCondition; overload;
+    function IsShorterOrEqual(aLen : Integer) : IStringCondition; overload;
+    function IsShorterOrEqual(aLen : Integer; const aCustomMessage : string) : IStringCondition; overload;
+    function HasLengthRange(aMin, aMax : Integer) : IStringCondition; overload;
+    function HasLengthRange(aMin, aMax : Integer; const aCustomMessage : string) : IStringCondition; overload;
+    function IsUpperCase : IStringCondition; overload;
+    function IsUpperCase(const aCustomMessage : string) : IStringCondition; overload;
+    function IsLowerCase : IStringCondition; overload;
+    function IsLowerCase(const aCustomMessage : string) : IStringCondition; overload;
+    function IsNotUpperCase : IStringCondition; overload;
+    function IsNotUpperCase(const aCustomMessage : string) : IStringCondition; overload;
+    function IsNotLowerCase : IStringCondition; overload;
+    function IsNotLowerCase(const aCustomMessage : string) : IStringCondition; overload;
+    function Evaluate(aExpression : Boolean) : IStringCondition; overload;
+    function Evaluate(aExpression : Boolean; const aCustomMessage : string) : IStringCondition; overload;
+  end;
+
+  TIntegerCondition = class(TCondition,IIntegerCondition)
+  private
+    fValue : Int64;
+  public
+    constructor Create(const aValue : Int64; const aName : string; aPostCondition : Boolean);
+    function WithExceptionOnFailure(aExceptionClass : ExceptClass) : IIntegerCondition;
+    function IsInRange(aMin, aMax : Int64) : IIntegerCondition; overload;
+    function IsInRange(aMin, aMax : Int64; const aCustomMessage : string) : IIntegerCondition; overload;
+    function IsNotInRange(aMin, aMax : Int64) : IIntegerCondition; overload;
+    function IsNotInRange(aMin, aMax : Int64; const aCustomMessage : string) : IIntegerCondition; overload;
+    function IsEqualTo(aValue : Int64) : IIntegerCondition; overload;
+    function IsEqualTo(aValue : Int64; const aCustomMessage : string) : IIntegerCondition; overload;
+    function IsNotEqualTo(aValue : Int64) : IIntegerCondition; overload;
+    function IsNotEqualTo(aValue : Int64; const aCustomMessage : string) : IIntegerCondition; overload;
+    function IsGreaterThan(aValue : Int64) : IIntegerCondition; overload;
+    function IsGreaterThan(aValue : Int64; const aCustomMessage : string) : IIntegerCondition; overload;
+    function IsNotGreaterThan(aValue : Int64) : IIntegerCondition; overload;
+    function IsNotGreaterThan(aValue : Int64; const aCustomMessage : string) : IIntegerCondition; overload;
+    function IsGreaterOrEqual(aValue : Int64) : IIntegerCondition; overload;
+    function IsGreaterOrEqual(aValue : Int64; const aCustomMessage : string) : IIntegerCondition; overload;
+    function IsNotGreaterOrEqual(aValue : Int64) : IIntegerCondition; overload;
+    function IsNotGreaterOrEqual(aValue : Int64; const aCustomMessage : string) : IIntegerCondition; overload;
+    function IsLessThan(aValue : Int64) : IIntegerCondition; overload;
+    function IsLessThan(aValue : Int64; const aCustomMessage : string) : IIntegerCondition; overload;
+    function IsNotLessThan(aValue : Int64) : IIntegerCondition; overload;
+    function IsNotLessThan(aValue : Int64; const aCustomMessage : string) : IIntegerCondition; overload;
+    function IsLessOrEqual(aValue : Int64) : IIntegerCondition; overload;
+    function IsLessOrEqual(aValue : Int64; const aCustomMessage : string) : IIntegerCondition; overload;
+    function IsNotLessOrEqual(aValue : Int64) : IIntegerCondition; overload;
+    function IsNotLessOrEqual(aValue : Int64; const aCustomMessage : string) : IIntegerCondition; overload;
+    function Evaluate(aExpression : Boolean) : IIntegerCondition; overload;
+    function Evaluate(aExpression : Boolean; const aCustomMessage : string) : IIntegerCondition; overload;
+  end;
+
+  TFloatCondition = class(TCondition,IFloatCondition)
+  private
+    fValue : Extended;
+  public
+    constructor Create(const aValue : Extended; const aName : string; aPostCondition : Boolean);
+    function WithExceptionOnFailure(aExceptionClass : ExceptClass) : IFloatCondition;
+    function IsInRange(aMin, aMax : Extended) : IFloatCondition; overload;
+    function IsInRange(aMin, aMax : Extended; const aCustomMessage : string) : IFloatCondition; overload;
+    function IsNotInRange(aMin, aMax : Extended) : IFloatCondition; overload;
+    function IsNotInRange(aMin, aMax : Extended; const aCustomMessage : string) : IFloatCondition; overload;
+    function IsEqualTo(aValue : Extended) : IFloatCondition; overload;
+    function IsEqualTo(aValue : Extended; const aCustomMessage : string) : IFloatCondition; overload;
+    function IsNotEqualTo(aValue : Extended) : IFloatCondition; overload;
+    function IsNotEqualTo(aValue : Extended; const aCustomMessage : string) : IFloatCondition; overload;
+    function IsGreaterThan(aValue : Extended) : IFloatCondition; overload;
+    function IsGreaterThan(aValue : Extended; const aCustomMessage : string) : IFloatCondition; overload;
+    function IsNotGreaterThan(aValue : Extended) : IFloatCondition; overload;
+    function IsNotGreaterThan(aValue : Extended; const aCustomMessage : string) : IFloatCondition; overload;
+    function IsGreaterOrEqual(aValue : Extended) : IFloatCondition; overload;
+    function IsGreaterOrEqual(aValue : Extended; const aCustomMessage : string) : IFloatCondition; overload;
+    function IsNotGreaterOrEqual(aValue : Extended) : IFloatCondition; overload;
+    function IsNotGreaterOrEqual(aValue : Extended; const aCustomMessage : string) : IFloatCondition; overload;
+    function IsLessThan(aValue : Extended) : IFloatCondition; overload;
+    function IsLessThan(aValue : Extended; const aCustomMessage : string) : IFloatCondition; overload;
+    function IsNotLessThan(aValue : Extended) : IFloatCondition; overload;
+    function IsNotLessThan(aValue : Extended; const aCustomMessage : string) : IFloatCondition; overload;
+    function IsLessOrEqual(aValue : Extended) : IFloatCondition; overload;
+    function IsLessOrEqual(aValue : Extended; const aCustomMessage : string) : IFloatCondition; overload;
+    function IsNotLessOrEqual(aValue : Extended) : IFloatCondition; overload;
+    function IsNotLessOrEqual(aValue : Extended; const aCustomMessage : string) : IFloatCondition; overload;
+    function Evaluate(aExpression : Boolean) : IFloatCondition; overload;
+    function Evaluate(aExpression : Boolean; const aCustomMessage : string) : IFloatCondition; overload;
+  end;
+
+  TObjectCondition = class(TCondition,IObjectCondition)
+  private
+    fValue : TObject;
+  public
+    constructor Create(const aValue : TObject; const aName : string; aPostCondition : Boolean);
+    function WithExceptionOnFailure(aExceptionClass : ExceptClass) : IObjectCondition;
+    function IsNull : IObjectCondition; overload;
+    function IsNull(const aCustomMessage : string): IObjectCondition; overload;
+    function IsNotNull : IObjectCondition; overload;
+    function IsNotNull(const aCustomMessage : string) : IObjectCondition; overload;
+    function IsOfType(aClass : TClass) : IObjectCondition; overload;
+    function IsOfType(aClass : TClass; const aCustomMessage : string) : IObjectCondition; overload;
+    function DoesNotOfType(aClass : TClass) : IObjectCondition; overload;
+    function DoesNotOfType(aClass : TClass; const aCustomMessage : string) : IObjectCondition; overload;
+    function Evaluate(aExpression : Boolean) : IObjectCondition; overload;
+    function Evaluate(aExpression : Boolean; const aCustomMessage : string) : IObjectCondition; overload;
+  end;
+
+  IConditionValidator = interface
+  ['{F707606E-7603-4690-BE76-2443B0A36D5F}']
+    function Requires(const aValue : string; const aName : string = '') : IStringCondition; overload;
+    function Requires(const aValue : Int64; const aName : string = '') : IIntegerCondition; overload;
+    function Requires(const aValue : Extended; const aName : string = '') : IFloatCondition; overload;
+    function Requires(const aValue : TObject; const aName : string = '') : IObjectCondition; overload;
+    function Ensures(const aValue : string; const aName : string = '') : IStringCondition; overload;
+    function Ensures(const aValue : Int64; const aName : string = '') : IIntegerCondition; overload;
+    function Ensures(const aValue : Extended; const aName : string = '') : IFloatCondition; overload;
+    function Ensures(const aValue : TObject; const aName : string = '') : IObjectCondition; overload;
+  end;
+
+  TConditionValidator = class(TInterfacedObject,IConditionValidator)
+  public
+    function Requires(const aValue : string; const aName : string = '') : IStringCondition; overload;
+    function Requires(const aValue : Int64; const aName : string = '') : IIntegerCondition; overload;
+    function Requires(const aValue : Extended; const aName : string = '') : IFloatCondition; overload;
+    function Requires(const aValue : TObject; const aName : string = '') : IObjectCondition; overload;
+    function Ensures(const aValue : string; const aName : string = '') : IStringCondition; overload;
+    function Ensures(const aValue : Int64; const aName : string = '') : IIntegerCondition; overload;
+    function Ensures(const aValue : Extended; const aName : string = '') : IFloatCondition; overload;
+    function Ensures(const aValue : TObject; const aName : string = '') : IObjectCondition; overload;
+  end;
+
+  EPreConditionError = class(Exception);
+  EPostConditionError = class(Exception);
+
+  function Condition : IConditionValidator;
+
+implementation
+
+function Condition : IConditionValidator;
+begin
+  Result := TConditionValidator.Create;
+end;
+
+{ TEvaluator }
+
+function TConditionValidator.Requires(const aValue: string; const aName : string = ''): IStringCondition;
+begin
+  Result := TStringCondition.Create(aValue,aName,False);
+end;
+
+function TConditionValidator.Requires(const aValue: Int64; const aName : string = ''): IIntegerCondition;
+begin
+  Result := TIntegerCondition.Create(aValue,aName,False);
+end;
+
+function TConditionValidator.Requires(const aValue: Extended; const aName : string = ''): IFloatCondition;
+begin
+  Result := TFloatCondition.Create(aValue,aName,False);
+end;
+
+function TConditionValidator.Requires(const aValue: TObject; const aName : string = ''): IObjectCondition;
+begin
+  Result := TObjectCondition.Create(aValue,aName,False);
+end;
+
+function TConditionValidator.Ensures(const aValue, aName: string): IStringCondition;
+begin
+  Result := TStringCondition.Create(aValue,aName,True);
+end;
+
+function TConditionValidator.Ensures(const aValue: Int64; const aName: string): IIntegerCondition;
+begin
+  Result := TIntegerCondition.Create(aValue,aName,True);
+end;
+
+function TConditionValidator.Ensures(const aValue: Extended; const aName: string): IFloatCondition;
+begin
+  Result := TFloatCondition.Create(aValue,aName,True);
+end;
+
+function TConditionValidator.Ensures(const aValue: TObject; const aName: string): IObjectCondition;
+begin
+  Result := TObjectCondition.Create(aValue,aName,True);
+end;
+
+{ TStringCondition }
+
+constructor TStringCondition.Create(const aValue: string; const aName : string; aPostCondition : Boolean);
+begin
+  fName := aName;
+  fValue := aValue;
+  fPostCondition := aPostCondition;
+end;
+
+function TStringCondition.WithExceptionOnFailure(aExceptionClass: ExceptClass): IStringCondition;
+begin
+  fExceptionClass := aExceptionClass;
+  Result := Self;
+end;
+
+function TStringCondition.IsEmpty: IStringCondition;
+begin
+  Result := Self.IsEmpty('');
+end;
+
+function TStringCondition.IsEmpty(const aCustomMessage : string): IStringCondition;
+begin
+  if not fValue.IsEmpty then
+  begin
+    if not aCustomMessage.IsEmpty then ThrowException(EArgumentNilException,aCustomMessage)
+      else ThrowException('must be empty');
+  end;
+  Result := Self;
+end;
+
+function TStringCondition.IsNotEmpty: IStringCondition;
+begin
+  Result := Self.IsNotEmpty('');
+end;
+
+function TStringCondition.IsNotEmpty(const aCustomMessage : string): IStringCondition;
+begin
+  if fValue.IsEmpty then
+  begin
+    if not aCustomMessage.IsEmpty then ThrowException(EArgumentNilException,aCustomMessage)
+      else ThrowException('should not be empty');
+  end;
+  Result := Self;
+end;
+
+function TStringCondition.StartsWith(const aText: string; aIgnoreCase : Boolean = False): IStringCondition;
+begin
+  Result := Self.StartsWith(aText,'',aIgnoreCase);
+end;
+
+function TStringCondition.StartsWith(const aText, aCustomMessage : string; aIgnoreCase : Boolean = False): IStringCondition;
+begin
+  if not fValue.StartsWith(aText,aIgnoreCase) then
+  begin
+    if not aCustomMessage.IsEmpty then ThrowException(EArgumentException,aCustomMessage)
+      else ThrowException('must start with "%s"',[aText])
+  end;
+  Result := Self;
+end;
+
+function TStringCondition.DoesNotStartsWith(const aText: string; aIgnoreCase: Boolean): IStringCondition;
+begin
+  Result := Self.DoesNotStartsWith(aText,'',aIgnoreCase);
+end;
+
+function TStringCondition.DoesNotStartsWith(const aText, aCustomMessage: string; aIgnoreCase: Boolean): IStringCondition;
+begin
+  if fValue.StartsWith(aText,aIgnoreCase) then
+  begin
+    if not aCustomMessage.IsEmpty then ThrowException(EArgumentException,aCustomMessage)
+      else ThrowException('should not start with "%s"',[aText]);
+  end;
+  Result := Self;
+end;
+
+function TStringCondition.EndsWith(const aText: string; aIgnoreCase : Boolean = False): IStringCondition;
+begin
+  Result := Self.EndsWith(aText,'',aIgnoreCase);
+end;
+
+function TStringCondition.EndsWith(const aText, aCustomMessage: string; aIgnoreCase : Boolean = False): IStringCondition;
+begin
+  if not fValue.EndsWith(aText,aIgnoreCase) then
+  begin
+    if not aCustomMessage.IsEmpty then ThrowException(EArgumentException,aCustomMessage)
+      else ThrowException('must end with "%s"',[aText]);
+  end;
+  Result := Self;
+end;
+
+function TStringCondition.DoesNotEndsWith(const aText: string; aIgnoreCase: Boolean): IStringCondition;
+begin
+  Result := Self.DoesNotEndsWith(aText,'',aIgnoreCase);
+end;
+
+function TStringCondition.DoesNotEndsWith(const aText, aCustomMessage: string; aIgnoreCase: Boolean): IStringCondition;
+begin
+  if fValue.EndsWith(aText,aIgnoreCase) then
+  begin
+    if not aCustomMessage.IsEmpty then ThrowException(EArgumentException,aCustomMessage)
+      else ThrowException('should not be end with "%s"',[aText]);
+  end;
+  Result := Self;
+end;
+
+function TStringCondition.Contains(const aText: string; aIgnoreCase: Boolean): IStringCondition;
+begin
+  Result := Self.Contains(aText,'',aIgnoreCase);
+end;
+
+function TStringCondition.Contains(const aText, aCustomMessage: string; aIgnoreCase: Boolean): IStringCondition;
+begin
+  if aIgnoreCase then
+  begin
+    if not ContainsText(fValue,aText) then
+    begin
+      if not aCustomMessage.IsEmpty then ThrowException(EArgumentException,aCustomMessage)
+        else ThrowException('must contain "%s"',[aText]);
+    end;
+  end
+  else
+  begin
+    if not fValue.Contains(aText) then
+    begin
+      if not aCustomMessage.IsEmpty then ThrowException(EArgumentException,aCustomMessage)
+        else ThrowException('must contain "%s"',[aText]);
+    end;
+  end;
+  Result := Self;
+end;
+
+function TStringCondition.DoesNotContains(const aText: string; aIgnoreCase: Boolean = False): IStringCondition;
+begin
+  Result := Self.DoesNotContains(aText,'',aIgnoreCase);
+end;
+
+function TStringCondition.DoesNotContains(const aText, aCustomMessage: string; aIgnoreCase: Boolean = False): IStringCondition;
+begin
+  if aIgnoreCase then
+  begin
+    if ContainsText(fValue,aText) then
+    begin
+      if not aCustomMessage.IsEmpty then ThrowException(EArgumentException,aCustomMessage)
+        else ThrowException('should not contain "%s"',[aText]);
+    end;
+  end
+  else
+  begin
+    if fValue.Contains(aText) then
+    begin
+      if not aCustomMessage.IsEmpty then ThrowException(EArgumentException,aCustomMessage)
+        else ThrowException('should not contain "%s"',[aText]);
+    end;
+  end;
+  Result := Self;
+end;
+
+function TStringCondition.HasLength(aLen: Integer): IStringCondition;
+begin
+  Result := Self.HasLength(aLen,'');
+end;
+
+function TStringCondition.HasLength(aLen: Integer; const aCustomMessage : string): IStringCondition;
+begin
+  if fValue.Length <> aLen then
+  begin
+    if not aCustomMessage.IsEmpty then ThrowException(EArgumentException,aCustomMessage)
+      else ThrowException('must be %d length',[aLen]);
+  end;
+  Result := Self;
+end;
+
+function TStringCondition.DoesNotHasLength(aLen: Integer): IStringCondition;
+begin
+  Result := Self.DoesNotHasLength(aLen,'');
+end;
+
+function TStringCondition.DoesNotHasLength(aLen: Integer; const aCustomMessage : string): IStringCondition;
+begin
+  if fValue.Length = aLen then
+  begin
+    if not aCustomMessage.IsEmpty then ThrowException(EArgumentException,aCustomMessage)
+      else ThrowException('should not be %d length',[aLen]);
+  end;
+  Result := Self;
+end;
+
+function TStringCondition.IsShorterThan(aLen: Integer): IStringCondition;
+begin
+  Result := Self.IsShorterThan(aLen,'');
+end;
+
+function TStringCondition.IsShorterThan(aLen: Integer; const aCustomMessage : string): IStringCondition;
+begin
+  if fValue.Length >= aLen then
+  begin
+    if not aCustomMessage.IsEmpty then ThrowException(EArgumentException,aCustomMessage)
+      else ThrowException('must be shorten than %d',[aLen]);
+  end;
+  Result := Self;
+end;
+
+function TStringCondition.IsShorterOrEqual(aLen: Integer): IStringCondition;
+begin
+  Result := Self.IsShorterOrEqual(aLen,'');
+end;
+
+function TStringCondition.IsShorterOrEqual(aLen: Integer; const aCustomMessage : string): IStringCondition;
+begin
+  if fValue.Length > aLen then
+  begin
+    if not aCustomMessage.IsEmpty then ThrowException(EArgumentException,aCustomMessage)
+      else ThrowException('must be shorter or equal to %d',[aLen]);
+  end;
+  Result := Self;
+end;
+
+function TStringCondition.IsLongerOrEqual(aLen: Integer): IStringCondition;
+begin
+  Result := Self.IsLongerOrEqual(aLen,'');
+end;
+
+function TStringCondition.IsLongerOrEqual(aLen: Integer; const aCustomMessage : string): IStringCondition;
+begin
+  if fValue.Length < aLen then
+  begin
+    if not aCustomMessage.IsEmpty then ThrowException(EArgumentException,aCustomMessage)
+      else ThrowException('must be longer or equal to %d',[aLen]);
+  end;
+  Result := Self;
+end;
+
+function TStringCondition.IsLongerThan(aLen: Integer): IStringCondition;
+begin
+  Result := Self.IsLongerThan(aLen,'');
+end;
+
+function TStringCondition.IsLongerThan(aLen: Integer; const aCustomMessage : string): IStringCondition;
+begin
+  if fValue.Length <= aLen then
+  begin
+    if not aCustomMessage.IsEmpty then ThrowException(EArgumentException,aCustomMessage)
+      else ThrowException('must be longer than %d',[aLen]);
+  end;
+  Result := Self;
+end;
+
+function TStringCondition.HasLengthRange(aMin, aMax: Integer): IStringCondition;
+begin
+  Result := Self.HasLengthRange(aMin,aMax,'');
+end;
+
+function TStringCondition.HasLengthRange(aMin, aMax: Integer; const aCustomMessage : string): IStringCondition;
+begin
+  if (fValue.Length < aMin) or (fValue.Length > aMax) then
+  begin
+    if not aCustomMessage.IsEmpty then ThrowException(EArgumentOutOfRangeException,aCustomMessage)
+      else ThrowException('must be in %d-%d length range',[aMin,aMax]);
+  end;
+  Result := Self;
+end;
+
+function TStringCondition.IsUpperCase: IStringCondition;
+begin
+  Result := Self.IsUpperCase('');
+end;
+
+function TStringCondition.IsUpperCase(const aCustomMessage : string): IStringCondition;
+begin
+  if fValue.ToUpper <> fValue then
+  begin
+    if not aCustomMessage.IsEmpty then ThrowException(EArgumentException,aCustomMessage)
+      else ThrowException('must be upper case');
+  end;
+  Result := Self;
+end;
+
+function TStringCondition.IsLowerCase: IStringCondition;
+begin
+  Result := Self.IsLowerCase('');
+end;
+
+function TStringCondition.IsLowerCase(const aCustomMessage : string): IStringCondition;
+begin
+  if fValue.ToLower <> fValue then
+  begin
+    if not aCustomMessage.IsEmpty then ThrowException(EArgumentException,aCustomMessage)
+      else ThrowException('must be lower case');
+  end;
+  Result := Self;
+end;
+
+function TStringCondition.IsNotUpperCase: IStringCondition;
+begin
+  Result := Self.IsNotUpperCase('');
+end;
+
+function TStringCondition.IsNotUpperCase(const aCustomMessage : string): IStringCondition;
+begin
+  if fValue.ToUpper = fValue then
+  begin
+    if not aCustomMessage.IsEmpty then ThrowException(EArgumentException,aCustomMessage)
+      else ThrowException('should not be upper case');
+  end;
+  Result := Self;
+end;
+
+function TStringCondition.IsNotLowerCase: IStringCondition;
+begin
+  Result := Self.IsNotLowerCase('');
+end;
+
+function TStringCondition.IsNotLowerCase(const aCustomMessage : string): IStringCondition;
+begin
+  if fValue.ToLower = fValue then
+  begin
+    if not aCustomMessage.IsEmpty then ThrowException(EArgumentException,aCustomMessage)
+      else ThrowException('should not be lower case');
+  end;
+  Result := Self;
+end;
+
+function TStringCondition.Evaluate(aExpression: Boolean): IStringCondition;
+begin
+  Result := Self.Evaluate(aExpression,'');
+end;
+
+function TStringCondition.Evaluate(aExpression: Boolean; const aCustomMessage : string): IStringCondition;
+begin
+  if not aExpression then
+  begin
+    if not aCustomMessage.IsEmpty then ThrowException(EArgumentException,aCustomMessage)
+      else  ThrowException('must meet condition');
+  end;
+end;
+
+{ TIntegerCondition }
+
+constructor TIntegerCondition.Create(const aValue: Int64; const aName : string; aPostCondition : Boolean);
+begin
+  fName := aName;
+  fValue := aValue;
+  fPostCondition := aPostCondition;
+end;
+
+function TIntegerCondition.WithExceptionOnFailure(aExceptionClass: ExceptClass): IIntegerCondition;
+begin
+  fExceptionClass := aExceptionClass;
+  Result := Self;
+end;
+
+function TIntegerCondition.IsEqualTo(aValue: Int64): IIntegerCondition;
+begin
+  Result := Self.IsEqualTo(aValue,'');
+end;
+
+function TIntegerCondition.IsEqualTo(aValue: Int64; const aCustomMessage : string): IIntegerCondition;
+begin
+  if fValue <> aValue then
+  begin
+    if not aCustomMessage.IsEmpty then ThrowException(EArgumentException,aCustomMessage)
+      else ThrowException('must be equal to %d',[aValue]);
+  end;
+  Result := Self;
+end;
+
+function TIntegerCondition.IsGreaterOrEqual(aValue: Int64): IIntegerCondition;
+begin
+  Result := Self.IsGreaterOrEqual(aValue,'');
+end;
+
+function TIntegerCondition.IsGreaterOrEqual(aValue: Int64; const aCustomMessage : string): IIntegerCondition;
+begin
+  if fValue < aValue then
+  begin
+    if not aCustomMessage.IsEmpty then ThrowException(EArgumentException,aCustomMessage)
+      else ThrowException('must be greather or equal to %d',[aValue]);
+  end;
+  Result := Self;
+end;
+
+function TIntegerCondition.IsGreaterThan(aValue: Int64): IIntegerCondition;
+begin
+  Result := Self.IsGreaterThan(aValue,'');
+end;
+
+function TIntegerCondition.IsGreaterThan(aValue: Int64; const aCustomMessage : string): IIntegerCondition;
+begin
+  if fValue <= aValue then
+  begin
+    if not aCustomMessage.IsEmpty then ThrowException(EArgumentException,aCustomMessage)
+      else ThrowException('must be greather than %d',[aValue]);
+  end;
+  Result := Self;
+end;
+
+function TIntegerCondition.IsInRange(aMin, aMax: Int64): IIntegerCondition;
+begin
+  Result := Self.IsInRange(aMin,aMax,'');
+end;
+
+function TIntegerCondition.IsInRange(aMin, aMax: Int64; const aCustomMessage : string): IIntegerCondition;
+begin
+  if (fValue < aMin) or (fValue > aMax) then
+  begin
+    if not aCustomMessage.IsEmpty then ThrowException(EArgumentOutOfRangeException,aCustomMessage)
+      else ThrowException('must be in %d-%d range',[aMin,aMax]);
+  end;
+  Result := Self;
+end;
+
+function TIntegerCondition.IsLessOrEqual(aValue: Int64): IIntegerCondition;
+begin
+  Result := Self.IsLessOrEqual(aValue,'');
+end;
+
+function TIntegerCondition.IsLessOrEqual(aValue: Int64; const aCustomMessage : string): IIntegerCondition;
+begin
+  if fValue > aValue then
+  begin
+    if not aCustomMessage.IsEmpty then ThrowException(EArgumentException,aCustomMessage)
+      else ThrowException('must be less or equal to %d',[aValue]);
+  end;
+  Result := Self;
+end;
+
+function TIntegerCondition.IsLessThan(aValue: Int64): IIntegerCondition;
+begin
+  Result := Self.IsLessThan(aValue,'');
+end;
+
+function TIntegerCondition.IsLessThan(aValue: Int64; const aCustomMessage : string): IIntegerCondition;
+begin
+  if fValue >= aValue then
+  begin
+    if not aCustomMessage.IsEmpty then ThrowException(EArgumentException,aCustomMessage)
+      else ThrowException('must be less than %d',[aValue]);
+  end;
+  Result := Self;
+end;
+
+function TIntegerCondition.IsNotEqualTo(aValue: Int64): IIntegerCondition;
+begin
+  Result := Self.IsNotEqualTo(aValue,'');
+end;
+
+function TIntegerCondition.IsNotEqualTo(aValue: Int64; const aCustomMessage : string): IIntegerCondition;
+begin
+  if fValue = aValue then
+  begin
+    if not aCustomMessage.IsEmpty then ThrowException(EArgumentException,aCustomMessage)
+      else ThrowException('should not be equal to %d',[aValue]);
+  end;
+  Result := Self;
+end;
+
+function TIntegerCondition.IsNotGreaterOrEqual(aValue: Int64): IIntegerCondition;
+begin
+  Result := Self.IsNotGreaterOrEqual(aValue,'');
+end;
+
+function TIntegerCondition.IsNotGreaterOrEqual(aValue: Int64; const aCustomMessage : string): IIntegerCondition;
+begin
+  if fValue >= aValue then
+  begin
+    if not aCustomMessage.IsEmpty then ThrowException(EArgumentException,aCustomMessage)
+      else ThrowException('should not be greater or equal to %d',[aValue]);
+  end;
+  Result := Self;
+end;
+
+function TIntegerCondition.IsNotGreaterThan(aValue: Int64): IIntegerCondition;
+begin
+  Result := Self.IsNotGreaterThan(aValue,'');
+end;
+
+function TIntegerCondition.IsNotGreaterThan(aValue: Int64; const aCustomMessage : string): IIntegerCondition;
+begin
+  if fValue > aValue then
+  begin
+    if not aCustomMessage.IsEmpty then ThrowException(EArgumentException,aCustomMessage)
+      else ThrowException('should not be greater than %d',[aValue]);
+  end;
+  Result := Self;
+end;
+
+function TIntegerCondition.IsNotInRange(aMin, aMax: Int64): IIntegerCondition;
+begin
+  Result := Self.IsNotInRange(aMin,aMax,'');
+end;
+
+function TIntegerCondition.IsNotInRange(aMin, aMax: Int64; const aCustomMessage : string): IIntegerCondition;
+begin
+  if (fValue >= aMin) and (fValue <= aMax) then
+  begin
+    if not aCustomMessage.IsEmpty then ThrowException(EArgumentOutOfRangeException,aCustomMessage)
+      else ThrowException('should not be in range %d-%d',[aMin,aMax]);
+  end;
+  Result := Self;
+end;
+
+function TIntegerCondition.IsNotLessOrEqual(aValue: Int64): IIntegerCondition;
+begin
+  Result := Self.IsNotLessOrEqual(aValue,'');
+end;
+
+function TIntegerCondition.IsNotLessOrEqual(aValue: Int64; const aCustomMessage : string): IIntegerCondition;
+begin
+  if fValue <= aValue then
+  begin
+    if not aCustomMessage.IsEmpty then ThrowException(EArgumentException,aCustomMessage)
+      else ThrowException('should not be less or equal to %d',[aValue]);
+  end;
+  Result := Self;
+end;
+
+function TIntegerCondition.IsNotLessThan(aValue: Int64): IIntegerCondition;
+begin
+  Result := Self.IsNotLessThan(aValue,'');
+end;
+
+function TIntegerCondition.IsNotLessThan(aValue: Int64; const aCustomMessage : string): IIntegerCondition;
+begin
+  if fValue < aValue then
+  begin
+    if not aCustomMessage.IsEmpty then ThrowException(EArgumentException,aCustomMessage)
+      else ThrowException('should not be less than %d',[aValue]);
+  end;
+  Result := Self;
+end;
+
+function TIntegerCondition.Evaluate(aExpression: Boolean): IIntegerCondition;
+begin
+  Result := Self.Evaluate(aExpression,'');
+end;
+
+function TIntegerCondition.Evaluate(aExpression: Boolean; const aCustomMessage : string): IIntegerCondition;
+begin
+  if not aExpression then
+  begin
+    if not aCustomMessage.IsEmpty then ThrowException(EArgumentException,aCustomMessage)
+      else ThrowException('must meet condition');
+  end;
+end;
+
+{ TFloatCondition }
+
+constructor TFloatCondition.Create(const aValue: Extended; const aName : string; aPostCondition : Boolean);
+begin
+  fName := aName;
+  fValue := aValue;
+  fPostCondition := aPostCondition;
+end;
+
+function TFloatCondition.WithExceptionOnFailure(aExceptionClass: ExceptClass): IFloatCondition;
+begin
+  fExceptionClass := aExceptionClass;
+  Result := Self;
+end;
+
+function TFloatCondition.IsEqualTo(aValue: Extended): IFloatCondition;
+begin
+  Result := Self.IsEqualTo(aValue,'');
+end;
+
+function TFloatCondition.IsEqualTo(aValue: Extended; const aCustomMessage : string): IFloatCondition;
+begin
+  if fValue <> aValue then
+  begin
+    if not aCustomMessage.IsEmpty then ThrowException(EArgumentException,aCustomMessage)
+      else ThrowException('must be equal to %d',[aValue]);
+  end;
+  Result := Self;
+end;
+
+function TFloatCondition.IsGreaterOrEqual(aValue: Extended): IFloatCondition;
+begin
+  Result := Self.IsGreaterOrEqual(aValue,'');
+end;
+
+function TFloatCondition.IsGreaterOrEqual(aValue: Extended; const aCustomMessage : string): IFloatCondition;
+begin
+  if fValue < aValue then
+  begin
+    if not aCustomMessage.IsEmpty then ThrowException(EArgumentException,aCustomMessage)
+      else ThrowException('must be greather or equal to %d',[aValue]);
+  end;
+  Result := Self;
+end;
+
+function TFloatCondition.IsGreaterThan(aValue: Extended): IFloatCondition;
+begin
+  Result := Self.IsGreaterThan(aValue,'');
+end;
+
+function TFloatCondition.IsGreaterThan(aValue: Extended; const aCustomMessage : string): IFloatCondition;
+begin
+  if fValue <= aValue then
+  begin
+    if not aCustomMessage.IsEmpty then ThrowException(EArgumentException,aCustomMessage)
+      else ThrowException('must be greather than %d',[aValue]);
+  end;
+  Result := Self;
+end;
+
+function TFloatCondition.IsInRange(aMin, aMax: Extended): IFloatCondition;
+begin
+  Result := Self.IsInRange(aMin,aMax,'');
+end;
+
+function TFloatCondition.IsInRange(aMin, aMax: Extended; const aCustomMessage : string): IFloatCondition;
+begin
+  if (fValue < aMin) or (fValue > aMax) then
+  begin
+    if not aCustomMessage.IsEmpty then ThrowException(EArgumentOutOfRangeException,aCustomMessage)
+      else ThrowException('must be in %d-%d range',[aMin,aMax]);
+  end;
+  Result := Self;
+end;
+
+function TFloatCondition.IsLessOrEqual(aValue: Extended): IFloatCondition;
+begin
+  Result := Self.IsLessOrEqual(aValue,'');
+end;
+
+function TFloatCondition.IsLessOrEqual(aValue: Extended; const aCustomMessage : string): IFloatCondition;
+begin
+  if fValue > aValue then
+  begin
+    if not aCustomMessage.IsEmpty then ThrowException(EArgumentException,aCustomMessage)
+      else ThrowException('must be less or equal to %d',[aValue]);
+  end;
+  Result := Self;
+end;
+
+function TFloatCondition.IsLessThan(aValue: Extended): IFloatCondition;
+begin
+  Result := Self.IsLessThan(aValue,'');
+end;
+
+function TFloatCondition.IsLessThan(aValue: Extended; const aCustomMessage : string): IFloatCondition;
+begin
+  if fValue >= aValue then
+  begin
+    if not aCustomMessage.IsEmpty then ThrowException(EArgumentException,aCustomMessage)
+      else ThrowException('must be less than %d',[aValue]);
+  end;
+  Result := Self;
+end;
+
+function TFloatCondition.IsNotEqualTo(aValue: Extended): IFloatCondition;
+begin
+  Result := Self.IsNotEqualTo(aValue,'');
+end;
+
+function TFloatCondition.IsNotEqualTo(aValue: Extended; const aCustomMessage : string): IFloatCondition;
+begin
+  if fValue = aValue then
+  begin
+    if not aCustomMessage.IsEmpty then ThrowException(EArgumentException,aCustomMessage)
+      else ThrowException('should not be equal to %d',[aValue]);
+  end;
+  Result := Self;
+end;
+
+function TFloatCondition.IsNotGreaterOrEqual(aValue: Extended): IFloatCondition;
+begin
+  Result := Self.IsNotGreaterOrEqual(aValue,'');
+end;
+
+function TFloatCondition.IsNotGreaterOrEqual(aValue: Extended; const aCustomMessage : string): IFloatCondition;
+begin
+  if fValue >= aValue then
+  begin
+    if not aCustomMessage.IsEmpty then ThrowException(EArgumentException,aCustomMessage)
+      else ThrowException('should not be greater or equal to %d',[aValue]);
+  end;
+  Result := Self;
+end;
+
+function TFloatCondition.IsNotGreaterThan(aValue: Extended): IFloatCondition;
+begin
+  Result := Self.IsNotGreaterThan(aValue,'');
+end;
+
+function TFloatCondition.IsNotGreaterThan(aValue: Extended; const aCustomMessage : string): IFloatCondition;
+begin
+  if fValue > aValue then
+  begin
+    if not aCustomMessage.IsEmpty then ThrowException(EArgumentException,aCustomMessage)
+      else ThrowException('should not be greater than %d',[aValue]);
+  end;
+  Result := Self;
+end;
+
+function TFloatCondition.IsNotInRange(aMin, aMax: Extended): IFloatCondition;
+begin
+  Result := Self.IsNotInRange(aMin,aMax,'');
+end;
+
+function TFloatCondition.IsNotInRange(aMin, aMax: Extended; const aCustomMessage : string): IFloatCondition;
+begin
+  if (fValue >= aMin) and (fValue <= aMax) then
+  begin
+    if not aCustomMessage.IsEmpty then ThrowException(EArgumentOutOfRangeException,aCustomMessage)
+      else ThrowException('should not be in range %d-%d',[aMin,aMax]);
+  end;
+  Result := Self;
+end;
+
+function TFloatCondition.IsNotLessOrEqual(aValue: Extended): IFloatCondition;
+begin
+  Result := Self.IsNotLessOrEqual(aValue,'');
+end;
+
+function TFloatCondition.IsNotLessOrEqual(aValue: Extended; const aCustomMessage : string): IFloatCondition;
+begin
+  if fValue <= aValue then
+  begin
+    if not aCustomMessage.IsEmpty then ThrowException(EArgumentException,aCustomMessage)
+      else ThrowException('should not be less or equal to %d',[aValue]);
+  end;
+  Result := Self;
+end;
+
+function TFloatCondition.IsNotLessThan(aValue: Extended): IFloatCondition;
+begin
+  Result := Self.IsNotLessThan(aValue,'');
+end;
+
+function TFloatCondition.IsNotLessThan(aValue: Extended; const aCustomMessage : string): IFloatCondition;
+begin
+  if fValue < aValue then
+  begin
+    if not aCustomMessage.IsEmpty then ThrowException(EArgumentException,aCustomMessage)
+      else ThrowException('should not be less than %d',[aValue]);
+  end;
+  Result := Self;
+end;
+
+function TFloatCondition.Evaluate(aExpression: Boolean): IFloatCondition;
+begin
+  Result := Self.Evaluate(aExpression,'');
+end;
+
+function TFloatCondition.Evaluate(aExpression: Boolean; const aCustomMessage : string): IFloatCondition;
+begin
+  if not aExpression then
+  begin
+    if not aCustomMessage.IsEmpty then ThrowException(EArgumentException,aCustomMessage)
+      else ThrowException('must meet condition');
+  end;
+end;
+
+{ TObjectCondition }
+
+constructor TObjectCondition.Create(const aValue: TObject; const aName: string; aPostCondition : Boolean);
+begin
+  fName := aName;
+  fValue := aValue;
+  fPostCondition := aPostCondition;
+end;
+
+function TObjectCondition.WithExceptionOnFailure(aExceptionClass: ExceptClass): IObjectCondition;
+begin
+  fExceptionClass := aExceptionClass;
+  Result := Self;
+end;
+
+function TObjectCondition.IsNull: IObjectCondition;
+begin
+  Result := Self.IsNull('');
+end;
+
+function TObjectCondition.IsNull(const aCustomMessage: string): IObjectCondition;
+begin
+  if fValue <> nil then
+  begin
+    if not aCustomMessage.IsEmpty then ThrowException(EArgumentNilException,aCustomMessage)
+      else ThrowException('must be null');
+  end;
+  Result := Self;
+end;
+
+function TObjectCondition.IsNotNull: IObjectCondition;
+begin
+  Result := Self.IsNotNull('');
+end;
+
+function TObjectCondition.IsNotNull(const aCustomMessage: string): IObjectCondition;
+begin
+  if fValue = nil then
+  begin
+    if not aCustomMessage.IsEmpty then ThrowException(EArgumentNilException,aCustomMessage)
+      else ThrowException('should not be null');
+  end;
+  Result := Self;
+end;
+
+function TObjectCondition.IsOfType(aClass: TClass): IObjectCondition;
+begin
+  Result := Self.IsOfType(aClass,'');
+end;
+
+function TObjectCondition.IsOfType(aClass: TClass; const aCustomMessage: string): IObjectCondition;
+begin
+  if not(fValue is aClass) then
+  begin
+    if not aCustomMessage.IsEmpty then ThrowException(EArgumentException,aCustomMessage)
+      else ThrowException('must be of type "%s"',[aClass.ClassName]);
+  end;
+  Result := Self;
+end;
+
+function TObjectCondition.DoesNotOfType(aClass: TClass): IObjectCondition;
+begin
+  Result := Self.DoesNotOfType(aClass,'');
+end;
+
+function TObjectCondition.DoesNotOfType(aClass: TClass; const aCustomMessage: string): IObjectCondition;
+begin
+  if fValue is aClass then
+  begin
+    if not aCustomMessage.IsEmpty then ThrowException(EArgumentException,aCustomMessage)
+      else ThrowException('should not be of type "%s"',[aClass.ClassName]);
+  end;
+  Result := Self;
+end;
+
+function TObjectCondition.Evaluate(aExpression: Boolean): IObjectCondition;
+begin
+  Result := Self.Evaluate(aExpression,'');
+end;
+
+function TObjectCondition.Evaluate(aExpression: Boolean; const aCustomMessage: string): IObjectCondition;
+begin
+  if not aExpression then
+  begin
+    if not aCustomMessage.IsEmpty then ThrowException(EArgumentException,aCustomMessage)
+      else ThrowException('must meet condition');
+  end;
+  Result := Self;
+end;
+
+{ TCondition }
+
+constructor TCondition.Create;
+begin
+  fName := '';
+  fExceptionClass := nil;
+  fPostCondition := False;
+end;
+
+procedure TCondition.ThrowException(const aMsg: string);
+var
+  rexception : ExceptClass;
+begin
+  if fExceptionClass <> nil then raise fExceptionClass.Create(aMsg)
+  else
+  begin
+    if fPostCondition then rexception := EPostConditionError
+      else rexception := EPreConditionError;
+    if fName.IsEmpty then raise rexception.Create(aMsg)
+      else raise rexception.CreateFmt('[%s] %s',[fName,aMsg]);
+  end;
+end;
+
+procedure TCondition.ThrowException(const aMsg: string; aValues: array of const);
+begin
+  if fExceptionClass <> nil then raise fExceptionClass.Create(aMsg)
+    else ThrowException(Format(aMsg,aValues));
+end;
+
+procedure TCondition.ThrowException(aExceptionClass : ExceptClass; const aMsg : string);
+begin
+  if fExceptionClass <> nil then raise fExceptionClass.Create(aMsg)
+    else raise aExceptionClass.Create(aMsg);
+end;
+
+end.

+ 2 - 2
Quick.Config.Base.pas

@@ -59,7 +59,7 @@ type
     procedure Load(cConfig : TAppConfig); virtual; abstract;
     procedure Save(cConfig : TAppConfig); virtual; abstract;
   public
-    constructor Create; virtual;
+    constructor Create;
     property CreateIfNotExists : Boolean read fCreateIfNotExists write fCreateIfNotExists;
     property SerializeLevel : TSerializeProperty read fSerializeLevel write fSerializeLevel;
     property UseEnumNames : Boolean read fUseEnumNames write fUseEnumNames;
@@ -75,7 +75,7 @@ type
   protected
     fProvider : TAppConfigProvider;
   public
-    constructor Create(aConfigProvider : TAppConfigProvider); virtual;
+    constructor Create(aConfigProvider : TAppConfigProvider);
     destructor Destroy; override;
     {$IFNDEF FPC}[TNotSerializableProperty]{$ENDIF}
     property OnApplyConfig : TApplyConfigEvent read fOnApplyConfig write fOnApplyConfig;

+ 3 - 3
Quick.Config.Json.pas

@@ -1,13 +1,13 @@
 { ***************************************************************************
 
-  Copyright (c) 2015-2019 Kike Pérez
+  Copyright (c) 2015-2021 Kike Pérez
 
   Unit        : Quick.Config.Json
   Description : Save config to JSON file
   Author      : Kike Pérez
   Version     : 1.5
   Created     : 21/10/2017
-  Modified    : 12/02/2019
+  Modified    : 10/03/2021
 
   This file is part of QuickLib: https://github.com/exilon/QuickLib
 
@@ -217,7 +217,7 @@ begin
       try
         //Streamer.Options := Streamer.Options + [jsoDateTimeAsString ,jsoUseFormatString];
         //Streamer.DateTimeFormat := 'yyyy-mm-dd"T"hh:mm:ss.zz';
-        json.Text := serializer.ObjectToJson(cConfig,True);
+        json.Text := serializer.ObjectToJson(cConfig,cConfig.JsonIndent);
       finally
         serializer.Free;
       end;

+ 2 - 2
Quick.Config.YAML.pas

@@ -77,7 +77,7 @@ type
     procedure Load(cConfig : TAppConfig); override;
     procedure Save(cConfig : TAppConfig); override;
   public
-    constructor Create(const aFilename : string; aReloadIfFileChanged : Boolean = False); virtual;
+    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;
@@ -92,7 +92,7 @@ type
     function GetProvider : TAppConfigYMALProvider;
     procedure ReloadNotify;
   public
-    constructor Create(const aFilename : string; aReloadIfFileChanged : Boolean = False); virtual;
+    constructor Create(const aFilename : string; aReloadIfFileChanged : Boolean = False);
     destructor Destroy; override;
     property Provider : TAppConfigYMALProvider read GetProvider;
     function ToYAML : string;

+ 4 - 4
Quick.Console.pas

@@ -1,13 +1,13 @@
 { ***************************************************************************
 
-  Copyright (c) 2016-2020 Kike Pérez
+  Copyright (c) 2016-2021 Kike Pérez
 
   Unit        : Quick.Console
   Description : Console output with colors and optional file log
   Author      : Kike Pérez
   Version     : 1.9
   Created     : 10/05/2017
-  Modified    : 05/06/2020
+  Modified    : 05/08/2021
 
   This file is part of QuickLib: https://github.com/exilon/QuickLib
 
@@ -338,7 +338,7 @@ begin
     begin
       TextColor(cColor);
       {$I-}
-      Write(cMsg{$IFDEF LINUX} +#13{$ENDIF});
+      Write(cMsg);//{$IFDEF LINUX} +#13{$ENDIF});
       {$I+}
       TextColor(LastMode);
     end;
@@ -876,7 +876,7 @@ begin
                 pBuffer[dRead] := #0;
                 OemToCharA(pBuffer,dBuffer);
                 if Assigned(CallBack) then CallBack(dBuffer);
-                if Assigned(OutputLines) then OutputLines.Add(dBuffer);
+                if Assigned(OutputLines) then OutputLines.Add(string(dBuffer));
               until (dRead < CReadBuffer);
             end;
             //Application.ProcessMessages;

+ 4 - 6
Quick.Crypto.pas

@@ -30,10 +30,8 @@ unit Quick.Crypto;
 
 interface
 
-uses
-
-function AES128_Encrypt(Value, Password: string): string;
-function AES128_Decrypt(Value, Password: string): string;
+function AES128_Encrypt(const Value, Password: string): string;
+function AES128_Decrypt(const Value, Password: string): string;
 
 implementation
 
@@ -130,7 +128,7 @@ begin
   end;
 end;
 
-function AES128_Encrypt(Value, Password: string): string;
+function AES128_Encrypt(const Value, Password: string): string;
 var
   hCProv: HCRYPTPROV;
   hKey: HCRYPTKEY;
@@ -164,7 +162,7 @@ begin
   end;
 end;
 
-function AES128_Decrypt(Value, Password: string): string;
+function AES128_Decrypt(const Value, Password: string): string;
 var
   hCProv: HCRYPTPROV;
   hKey: HCRYPTKEY;

+ 15 - 4
Quick.Data.InfluxDB.pas

@@ -59,6 +59,7 @@ type
     fCreateDataBaseIfNotExists : Boolean;
     procedure CreateDataBase;
     function GenerateWriteQuery(const aMeasurement : string; aTagPairs : IList<TPair>; aFieldPairs : IList<TFlexPair>; aTime : TDateTime): string;
+    procedure EscapeData(var aTags : string);
     procedure SetWriteURL;
     procedure SetPassword(const Value: string);
     procedure SetUserName(const Value: string);
@@ -147,6 +148,7 @@ procedure TInfluxDBData.Write(const aMeasurement: string; const aFieldKey : stri
 var
   fields : IList<TFlexPair>;
 begin
+  fields := TxList<TFlexPair>.Create;
   fields.Add(TFlexPair.Create(aFieldKey,aFieldValue));
   if atime <> 0 then Write(GenerateWriteQuery(aMeasurement,nil,fields,aTime))
     else Write(GenerateWriteQuery(aMeasurement,nil,fields,Now()));
@@ -187,6 +189,11 @@ begin
     raise EInfluxDBData.Create(Format('[TInfluxDBData] : Response %d : %s trying to create database',[resp.StatusCode,resp.StatusText]));
 end;
 
+procedure TInfluxDBData.EscapeData(var aTags : string);
+begin
+  aTags := StringReplace(aTags,' ','\ ',[rfReplaceAll]);
+end;
+
 function TInfluxDBData.GenerateWriteQuery(const aMeasurement : string; aTagPairs : IList<TPair>; aFieldPairs : IList<TFlexPair>; aTime : TDateTime): string;
 var
   incinfo : TStringList;
@@ -200,14 +207,18 @@ begin
     //add global tags
     for tagpair in fTags do
     begin
-      incinfo.Add(Format('%s=%s',[tagpair.Name,tagpair.Value]));
+      if not tagpair.Value.IsEmpty then incinfo.Add(Format('%s=%s',[tagpair.Name,tagpair.Value]));
     end;
     //add current query tags
-    for tagpair in aTagPairs do
+    if aTagPairs <> nil then
     begin
-      incinfo.Add(Format('%s=%s',[tagpair.Name,tagpair.Value]));
+      for tagpair in aTagPairs do
+      begin
+        if not tagpair.Value.IsEmpty then incinfo.Add(Format('%s=%s',[tagpair.Name,tagpair.Value]));
+      end;
     end;
     tags := CommaText(incinfo);
+    EscapeData(tags);
 
     incinfo.Clear;
 
@@ -232,7 +243,7 @@ var
 begin
   if not fInitiated then Init;
 
-  stream := TStringStream.Create(aLine);
+  stream := TStringStream.Create(aLine,TEncoding.UTF8);
   var a := aline;
   try
     try

+ 213 - 44
Quick.Data.Redis.pas

@@ -1,13 +1,13 @@
 { ***************************************************************************
 
-  Copyright (c) 2015-2020 Kike Pérez
+  Copyright (c) 2015-2021 Kike Pérez
 
   Unit        : Quick.Data.Redis
   Description : Redis client
   Author      : Kike Pérez
   Version     : 1.0
   Created     : 22/02/2020
-  Modified    : 12/07/2020
+  Modified    : 15/10/2021
 
   This file is part of QuickLib: https://github.com/exilon/QuickLib
 
@@ -40,6 +40,7 @@ uses
   System.SysUtils,
   System.DateUtils,
   IdTCPClient,
+  IdGlobal,
   Quick.Commons;
 
 type
@@ -61,6 +62,7 @@ type
     procedure SetIsDone(const Value: Boolean);
     procedure SetResponse(const Value: string);
   public
+    constructor Create;
     property IsDone : Boolean read GetIsDone write SetIsDone;
     property Response : string read GetResponse write SetResponse;
   end;
@@ -70,6 +72,26 @@ type
     Score : Int64;
   end;
 
+  IRedisCommand = interface
+  ['{13A978D1-C689-403F-8623-3489E4DEE060}']
+    function AddArgument(const aValue : string) : IRedisCommand; overload;
+    function AddArgument(const aValue : Int64) : IRedisCommand; overload;
+    function AddArgument(const aValue : Extended) : IRedisCommand; overload;
+    function ToCommand : string;
+  end;
+
+  TRedisCommand = class(TInterfacedObject,IRedisCommand)
+  private
+    fCommand : string;
+    fArguments : array of string;
+  public
+    constructor Create(const aCommand : string);
+    function AddArgument(const aValue : string) : IRedisCommand; overload;
+    function AddArgument(const aValue : Int64) : IRedisCommand; overload;
+    function AddArgument(const aValue : Extended) : IRedisCommand; overload;
+    function ToCommand : string;
+  end;
+
   TRedisClient = class
   private
     fTCPClient : TIdTCPClient;
@@ -81,11 +103,14 @@ type
     fConnectionTimeout : Integer;
     fReadTimeout : Integer;
     fConnected : Boolean;
+    fRaiseErrorIfCommandFails : Boolean;
     procedure SetConnectionTimeout(const Value: Integer);
     procedure SetReadTimeout(const Value: Integer);
-    function Command(const aCommand : string; const aArguments : string = '') : IRedisResponse; overload;
+    function Command(const aCommand : string; const aArguments : string) : IRedisResponse; overload;
     function Command(const aCommand, aArgumentsFormat : string; aValues : array of const) : IRedisResponse; overload;
+    function Command(const aCommand : string) : IRedisResponse; overload;
     function EscapeString(const json: string) : string;
+    //function BulkString(const aValue : string) : string;
   public
     constructor Create;
     destructor Destroy; override;
@@ -96,6 +121,7 @@ type
     property Password : string read fPassword write fPassword;
     property ConnectionTimeout : Integer read fConnectionTimeout write SetConnectionTimeout;
     property ReadTimeout : Integer read fReadTimeout write SetReadTimeout;
+    property RaiseErrorIfCommandFails : Boolean read fRaiseErrorIfCommandFails write fRaiseErrorIfCommandFails;
     property Connected : Boolean read fConnected;
     function RedisSELECT(dbIndex : Integer) : Boolean;
     function RedisSET(const aKey, aValue : string; aTTLMs : Integer = -1) : Boolean;
@@ -135,13 +161,19 @@ implementation
 const
 
   DEF_REDIS_PORT = 6379;
-  CRLF = #10#13;
+  CRLF = #13#10;
   DEF_CONNECTIONTIMEOUT = 30000;
   DEF_READTIMETOUT = 10000;
 
 
 { TRedisResponse }
 
+constructor TRedisResponse.Create;
+begin
+  fIsDone := False;
+  fResponse := '';
+end;
+
 function TRedisResponse.GetIsDone: Boolean;
 begin
   Result := fIsDone;
@@ -175,17 +207,18 @@ begin
   fPassword := '';
   fConnectionTimeout := DEF_CONNECTIONTIMEOUT;
   fReadTimeout := DEF_READTIMETOUT;
+  fRaiseErrorIfCommandFails := False;
   fTCPClient := TIdTCPClient.Create;
 end;
 
 destructor TRedisClient.Destroy;
 begin
   try
-    if fTCPClient.Connected then RedisQUIT;
-    fTCPClient.IOHandler.InputBuffer.Clear;
-    fTCPClient.IOHandler.WriteBufferFlush;
-    if fTCPClient.Connected then fTCPClient.Disconnect(False);
-    fTCPClient.Free;
+    try
+      Disconnect;
+    finally
+      fTCPClient.Free;
+    end;
   except
     //avoid closing errors
   end;
@@ -194,24 +227,26 @@ end;
 
 procedure TRedisClient.Disconnect;
 begin
-  if fConnected then RedisQUIT;
+  if fTCPClient.Connected then
+  begin
+    RedisQUIT;
+    fTCPClient.IOHandler.InputBuffer.Clear;
+    fTCPClient.IOHandler.WriteBufferFlush;
+    if fTCPClient.Connected then fTCPClient.Disconnect(False);
+  end;
   fConnected := False;
 end;
 
 procedure TRedisClient.Connect;
 begin
-  if not fTCPClient.Connected then
-  begin
-    fTCPClient.Host := fHost;
-    fTCPClient.Port := fPort;
-    fTCPClient.ConnectTimeout := fConnectionTimeout;
-    fTCPClient.ReadTimeout := fConnectionTimeout;
-  end;
   try
-    fTCPClient.Connect; //first connection
     //connect password and database
     if not fTCPClient.Connected then
     begin
+      fTCPClient.Host := fHost;
+      fTCPClient.Port := fPort;
+      fTCPClient.ConnectTimeout := fConnectionTimeout;
+      fTCPClient.ReadTimeout := fConnectionTimeout;
       fTCPClient.Connect;
       if not fTCPClient.Connected then raise ERedisConnectionError.Create('Can''t connect to Redis Server!');
     end;
@@ -224,6 +259,7 @@ begin
     begin
       if not RedisSELECT(fDataBaseNumber) then raise ERedisConnectionError.CreateFmt('Can''t select Redis Database "%d"',[fDataBaseNumber]);
     end;
+    fTCPClient.IOHandler.MaxLineLength := MaxInt;
     fConnected := True;
   except
     on E : Exception do raise ERedisConnectionError.CreateFmt('Can''t connect to Redis service %s:%d (%s)',[Self.Host,Self.Port,e.Message]);
@@ -234,9 +270,16 @@ function TRedisClient.EscapeString(const json: string): string;
 begin
   Result := StringReplace(json,'\','\\',[rfReplaceAll]);
   Result := StringReplace(Result,'"','\"',[rfReplaceAll]);
+  Result := StringReplace(Result,#13,'\r',[rfReplaceAll]);
+  Result := StringReplace(Result,#10,'\n',[rfReplaceAll]);
   //Result := StringReplace(Result,'/','\/"',[rfReplaceAll]);
 end;
 
+//function TRedisClient.BulkString(const aValue : string) : string;
+//begin
+//  Result := Format('$%d%s%s%s',[aValue.Length,CRLF,aValue,CRLF]);
+//end;
+
 procedure TRedisClient.SetConnectionTimeout(const Value: Integer);
 begin
   if fConnectionTimeout <> Value then
@@ -260,7 +303,12 @@ begin
   Result := Command(aCommand,Format(aArgumentsFormat,aValues));
 end;
 
-function TRedisclient.Command(const aCommand : string; const aArguments : string = '') : IRedisResponse;
+function TRedisclient.Command(const aCommand : string; const aArguments : string) : IRedisResponse;
+begin
+  Result := Command(aCommand + ' ' + aArguments + CRLF);
+end;
+
+function TRedisClient.Command(const aCommand : string) : IRedisResponse;
   function TrimResponse(const aResponse : string) : string;
   begin
     Result := Copy(aResponse,Low(aResponse) + 1, aResponse.Length);
@@ -271,7 +319,8 @@ begin
   Result := TRedisResponse.Create;
   try
     if not fTCPClient.Connected then Connect;
-    fTCPClient.IOHandler.Write(aCommand + ' ' + aArguments + CRLF);
+    //Writeln('*'+ (aArguments.CountChar('$') + 1).ToString + CRLF + BulkString(aCommand) + aArguments);
+    fTCPClient.IOHandler.Write(aCommand);
     if fTCPClient.IOHandler.CheckForDataOnSource(fReadTimeout) then
     begin
       res := fTCPClient.IOHandler.ReadLn;
@@ -308,10 +357,12 @@ begin
             Result.Response := TrimResponse(res);
             Result.IsDone := True;
           end;
+        else Result.Response := TrimResponse(res);
       end;
     end;
+    if (fRaiseErrorIfCommandFails) and (not Result.IsDone) then raise ERedisCommandError.CreateFmt('command fail (%s)',[Result.Response]);
   except
-    on E : Exception do raise ERedisCommandError.CreateFmt('%s error: %s',[aCommand,e.message]);
+    on E : Exception do raise ERedisCommandError.CreateFmt('Redis error: %s [%s...]',[e.message,aCommand.Substring(0,20)]);
   end;
 end;
 
@@ -326,26 +377,41 @@ begin
 end;
 
 function TRedisClient.RedisSET(const aKey, aValue: string; aTTLMs: Integer = -1): Boolean;
+var
+  rediscmd : IRedisCommand;
 begin
-  Result := Command('SET','%s "%s" PX %d',[aKey,EscapeString(aValue),aTTLMs]).IsDone;
+  rediscmd := TRedisCommand.Create('SET')
+               .AddArgument(aKey)
+               .AddArgument(aValue)
+               .AddArgument('PX')
+               .AddArgument(aTTLMs);
+  Result := Command(rediscmd.ToCommand).IsDone;
 end;
 
 function TRedisClient.RedisRPOP(const aKey: string; out oValue: string): Boolean;
+var
+  rediscmd : IRedisCommand;
 begin
-  Result := False;
-  if Command('RPOP','%s',[aKey]).IsDone then
+  rediscmd := TRedisCommand.Create('RPOP')
+               .AddArgument(aKey);
+  if Command(rediscmd.ToCommand).IsDone then
   begin
     oValue := fTCPClient.IOHandler.ReadLn;
     Result := True;
-  end;
+  end
+  else Result := False;
 end;
 
 function TRedisClient.RedisBRPOP(const aKey: string; out oValue: string; aWaitTimeoutSecs : Integer): Boolean;
 var
+  rediscmd : IRedisCommand;
   response : IRedisResponse;
 begin
   Result := False;
-  response := Command('BRPOP','%s %d',[aKey,aWaitTimeoutSecs]);
+  rediscmd := TRedisCommand.Create('BRPOP')
+               .AddArgument(aKey)
+               .AddArgument(aWaitTimeoutSecs);
+  response := Command(rediscmd.ToCommand);
   if response.IsDone then
   begin
     //if response.Response = '-1' then Exit;
@@ -353,7 +419,7 @@ begin
     fTCPClient.IOHandler.ReadLn; //key
     fTCPClient.IOHandler.ReadLn; //$int
     oValue := fTCPClient.IOHandler.ReadLn; //value
-    Result := True;
+    if not oValue.IsEmpty then Result := True;
   end
   else
   begin
@@ -363,28 +429,41 @@ end;
 
 function TRedisClient.RedisBRPOPLPUSH(const aKey, aKeyToMove: string; out oValue: string; aWaitTimeoutSecs: Integer): Boolean;
 var
+  rediscmd : IRedisCommand;
   response : IRedisResponse;
 begin
-  response := Command('BRPOPLPUSH','%s %s %d',[aKey,aKeyToMove,aWaitTimeoutSecs]);
+  Result := False;
+  rediscmd := TRedisCommand.Create('BRPOPLPUSH')
+               .AddArgument(aKey)
+               .AddArgument(aKeyToMove)
+               .AddArgument(aWaitTimeoutSecs);
+  response := Command(rediscmd.ToCommand);
   if response.IsDone then
   begin
     oValue := fTCPClient.IOHandler.ReadLn; //value
-    Result := True;
+    if not oValue.IsEmpty then Result := True;
   end
   else raise ERedisCommandError.CreateFmt('BRPOPLPUSH Error: %s',[response.Response]);
 end;
 
 function TRedisClient.RedisDEL(const aKey: string): Boolean;
+var
+  rediscmd : IRedisCommand;
 begin
-  Result := Command('DEL',aKey).IsDone;
+  rediscmd := TRedisCommand.Create('DEL')
+               .AddArgument(aKey);
+  Result := Command(rediscmd.ToCommand).IsDone;
 end;
 
 function TRedisClient.RedisLLEN(const aKey : string): Integer;
 var
+  rediscmd : IRedisCommand;
   response : IRedisResponse;
 begin
   Result := 0;
-  response := Command('LLEN',aKey);
+  rediscmd := TRedisCommand.Create('LLEN')
+               .AddArgument(aKey);
+  response := Command(rediscmd.ToCommand);
   if response.IsDone then
   begin
     Result := response.Response.ToInteger;
@@ -393,10 +472,14 @@ end;
 
 function TRedisClient.RedisTTL(const aKey, aValue : string): Integer;
 var
+  rediscmd : IRedisCommand;
   response : IRedisResponse;
 begin
   Result := 0;
-  response := Command('TTL','%s "%s"',[aKey,EscapeString(aValue)]);
+  rediscmd := TRedisCommand.Create('TTL')
+               .AddArgument(aKey)
+               .AddArgument(aValue);
+  response := Command(rediscmd.ToCommand);
   if response.IsDone then
   begin
     Result := response.Response.ToInteger;
@@ -405,9 +488,14 @@ end;
 
 function TRedisClient.RedisZADD(const aKey, aValue: string; aScore: Int64): Boolean;
 var
+  rediscmd : IRedisCommand;
   response : IRedisResponse;
 begin
-  response := Command('ZADD','%s %d "%s"',[aKey,aScore,EscapeString(aValue)]);
+  rediscmd := TRedisCommand.Create('ZADD')
+               .AddArgument(aKey)
+               .AddArgument(aScore)
+               .AddArgument(aValue);
+  response := Command(rediscmd.ToCommand);
   if response.IsDone then
   begin
     Result := response.Response.ToInteger = 1;
@@ -417,12 +505,17 @@ end;
 
 function TRedisClient.RedisZRANGE(const aKey: string; aStartPosition, aEndPosition: Int64): TArray<string>;
 var
+  rediscmd : IRedisCommand;
   response : IRedisResponse;
   value : string;
   i : Integer;
 begin
   Result := [];
-  response := Command('ZRANGE','%s %d %d',[aKey,aStartPosition,aEndPosition]);
+  rediscmd := TRedisCommand.Create('ZRANGE')
+               .AddArgument(aKey)
+               .AddArgument(aStartPosition)
+               .AddArgument(aEndPosition);
+  response := Command(rediscmd.ToCommand);
   if response.IsDone then
   begin
     for i := 1 to (response.Response.ToInteger) do
@@ -437,6 +530,7 @@ end;
 
 function TRedisClient.RedisZRANGEBYSCORE(const aKey: string; aMinScore, aMaxScore: Int64): TArray<TRedisSortedItem>;
 var
+  rediscmd : IRedisCommand;
   response : IRedisResponse;
   item : TRedisSortedItem;
   i : Integer;
@@ -444,7 +538,12 @@ var
   score : string;
 begin
   Result := [];
-  response := Command('ZRANGEBYSCORE','%s %d %d WITHSCORES',[aKey,aMinScore,aMaxScore]);
+  rediscmd := TRedisCommand.Create('ZRANGEBYSCORE')
+               .AddArgument(aKey)
+               .AddArgument(aMinScore)
+               .AddArgument(aMaxScore)
+               .AddArgument('WITHSCORES');
+  response := Command(rediscmd.ToCommand);
   if response.IsDone then
   begin
     for i := 1 to (response.Response.ToInteger Div 2) do
@@ -463,10 +562,14 @@ end;
 
 function TRedisClient.RedisZREM(const aKey, aValue: string): Boolean;
 var
+  rediscmd : IRedisCommand;
   response : IRedisResponse;
 begin
   Result := False;
-  response := Command('ZREM','%s "%s"',[aKey,EscapeString(aValue)]);
+  rediscmd := TRedisCommand.Create('ZREM')
+               .AddArgument(aKey)
+               .AddArgument(aValue);
+  response := Command(rediscmd.ToCommand);
   if response.IsDone then
   begin
     Result := response.Response.ToInteger = 1;
@@ -474,9 +577,13 @@ begin
 end;
 
 function TRedisClient.RedisLPOP(const aKey: string; out oValue: string): Boolean;
+var
+  rediscmd : IRedisCommand;
 begin
   Result := False;
-  if Command('LPOP','%s',[aKey]).IsDone then
+  rediscmd := TRedisCommand.Create('LPOP')
+               .AddArgument(aKey);
+  if Command(rediscmd.ToCommand).IsDone then
   begin
     oValue := fTCPClient.IOHandler.ReadLn;
     Result := True;
@@ -485,9 +592,13 @@ end;
 
 function TRedisClient.RedisBLPOP(const aKey: string; out oValue: string; aWaitTimeoutSecs : Integer): Boolean;
 var
+  rediscmd : IRedisCommand;
   response : IRedisResponse;
 begin
-  response := Command('BLPOP','%s %d',[aKey,aWaitTimeoutSecs]);
+  rediscmd := TRedisCommand.Create('BLPOP')
+               .AddArgument(aKey)
+               .AddArgument(aWaitTimeoutSecs);
+  response := Command(rediscmd.ToCommand);
   if response.IsDone then
   begin
     fTCPClient.IOHandler.ReadLn; //$int
@@ -500,18 +611,35 @@ begin
 end;
 
 function TRedisClient.RedisLPUSH(const aKey, aValue : string) : Boolean;
+var
+  rediscmd : IRedisCommand;
 begin
-  Result := Command('LPUSH','%s "%s"',[aKey,EscapeString(aValue)]).IsDone;
+  rediscmd := TRedisCommand.Create('LPUSH')
+               .AddArgument(aKey)
+               .AddArgument(aValue);
+  Result := Command(rediscmd.ToCommand).IsDone;
 end;
 
 function TRedisClient.RedisLREM(const aKey, aValue: string; aNumOccurrences: Integer): Boolean;
+var
+  rediscmd : IRedisCommand;
 begin
-  Result := Command('LREM','%s "%s" %d',[aKey,EscapeString(aValue),aNumOccurrences * -1]).IsDone;
+  rediscmd := TRedisCommand.Create('LREM')
+               .AddArgument(aKey)
+               .AddArgument(aNumOccurrences * -1)
+               .AddArgument(aValue);
+  Result := Command(rediscmd.ToCommand).IsDone;
 end;
 
 function TRedisClient.RedisLTRIM(const aKey : string; aFirstElement, aMaxSize : Int64) : Boolean;
+var
+  rediscmd : IRedisCommand;
 begin
-  Result := Command('LTRIM','%s %d %d',[aKey,aFirstElement,fMaxSize]).IsDone;
+  rediscmd := TRedisCommand.Create('LTRIM')
+               .AddArgument(aKey)
+               .AddArgument(aFirstElement)
+               .AddArgument(aMaxSize);
+  Result := Command(rediscmd.ToCommand).IsDone;
 end;
 
 function TRedisClient.RedisAUTH(const aPassword : string) : Boolean;
@@ -543,9 +671,13 @@ begin
 end;
 
 function TRedisClient.RedisGET(const aKey: string; out oValue: string): Boolean;
+var
+  rediscmd : IRedisCommand;
 begin
   Result := False;
-  if Command('GET','%s',[aKey]).IsDone then
+  rediscmd := TRedisCommand.Create('GET')
+               .AddArgument(aKey);
+  if Command(rediscmd.ToCommand).IsDone then
   begin
     oValue := fTCPClient.IOHandler.ReadLn;
     Result := True;
@@ -555,7 +687,7 @@ end;
 function TRedisClient.RedisPING : Boolean;
 begin
   Result := False;
-  if Command('PING').IsDone then
+  if Command('PING'+ CRLF).IsDone then
   begin
     Result := fTCPClient.IOHandler.ReadLn = 'PONG';
   end;
@@ -564,10 +696,47 @@ end;
 function TRedisClient.RedisQUIT : Boolean;
 begin
   try
-    Result := Command('QUIT').IsDone;
+    Result := Command('QUIT' + CRLF).IsDone;
   except
     Result := False;
   end;
 end;
 
+{ TRedisCommand }
+
+constructor TRedisCommand.Create(const aCommand: string);
+begin
+  fCommand := aCommand;
+  fArguments := fArguments + [fCommand];
+end;
+
+function TRedisCommand.AddArgument(const aValue: string) : IRedisCommand;
+begin
+  Result := Self;
+  fArguments := fArguments + [aValue];
+end;
+
+function TRedisCommand.AddArgument(const aValue: Extended): IRedisCommand;
+begin
+  Result := Self;
+  fArguments := fArguments + [aValue.ToString];
+end;
+
+function TRedisCommand.AddArgument(const aValue: Int64): IRedisCommand;
+begin
+  Result := Self;
+  fArguments := fArguments + [aValue.ToString];
+end;
+
+function TRedisCommand.ToCommand: string;
+var
+  arg : string;
+begin
+  Result := '*' + (High(fArguments) + 1).ToString + CRLF;
+  for arg in fArguments do
+  begin
+    Result := Result + '$' + arg.Length.ToString + CRLF + arg + CRLF;
+  end;
+end;
+
 end.

+ 12 - 3
Quick.Debug.Utils.pas

@@ -171,7 +171,8 @@ end;
 
 class destructor TDebugger.Destroy;
 begin
-
+  fSerializer := nil;
+  fLogger := nil;
 end;
 
 class function TDebugger.TimeIt(aOwner : TObject; const aFunctionName, aDescription: string): IDebugMehtodChrono;
@@ -182,8 +183,16 @@ end;
 
 class function TDebugger.Enter(aOwner : TObject; const aFunctionName: string) : IDebugMethodEnter;
 begin
-  fLogger.Debug(Format('[ENTER] >> %s.%s',[aOwner.ClassName,aFunctionName]));
-  Result := TDebugMethodEnter.Create(fLogger,Format('%s.%s',[aOwner.ClassName,aFunctionName]));
+  if aOwner <> nil then
+  begin
+    fLogger.Debug(Format('[ENTER] >> %s.%s',[aOwner.ClassName,aFunctionName]));
+    Result := TDebugMethodEnter.Create(fLogger,Format('%s.%s',[aOwner.ClassName,aFunctionName]));
+  end
+  else
+  begin
+    fLogger.Debug(Format('[ENTER] >> %s',[aFunctionName]));
+    Result := TDebugMethodEnter.Create(fLogger,aFunctionName);
+  end;
 end;
 
 class function TDebugger.NewChrono(aStarted : Boolean) : IChronometer;

+ 18 - 9
Quick.Expression.pas

@@ -1,13 +1,13 @@
 { ***************************************************************************
 
-  Copyright (c) 2016-2020 Kike Pérez
+  Copyright (c) 2016-2021 Kike Pérez
 
   Unit        : Quick.Expression
   Description : Expression parser & validator
   Author      : Kike Pérez
   Version     : 1.0
   Created     : 04/05/2019
-  Modified    : 12/03/2020
+  Modified    : 06/02/2021
 
   This file is part of QuickLib: https://github.com/exilon/QuickLib
 
@@ -102,7 +102,8 @@ type
     class function GetCombine(const aValue : string) : TCombine;
   public
     class function Parse(const aExpression : string) : TExpression;
-    class function Validate(const aValue : TValue; const aExpression : string) : Boolean;
+    class function Validate(const aValue : TValue; const aExpression : string) : Boolean; overload;
+    class function Validate(const aExpression : string) : Boolean; overload;
   end;
 
   ENotValidExpression = class(Exception);
@@ -238,6 +239,11 @@ begin
     else Result := GetMultiExpression(exp);
 end;
 
+class function TExpressionParser.Validate(const aExpression: string): Boolean;
+begin
+  Result := Validate(nil,aExpression);
+end;
+
 class function TExpressionParser.Validate(const aValue: TValue; const aExpression: string): Boolean;
 var
   exp : TExpression;
@@ -345,13 +351,16 @@ var
   value1 : TFlexValue;
 begin
   Result := False;
-  if aValue.IsEmpty then Exit;
-  if aValue.IsObject then
+  if aValue.IsEmpty then value1 := fValue1
+  else
   begin
-    if fValue1.Contains('.') then value1.AsTValue := TRTTI.GetPathValue(aValue.AsObject,fValue1)
-      else value1.AsTValue := TRTTI.GetPropertyValueEx(aValue.AsObject,fValue1);
-  end
-  else value1.AsTValue := aValue;
+    if aValue.IsObject then
+    begin
+      if fValue1.Contains('.') then value1.AsTValue := TRTTI.GetPathValue(aValue.AsObject,fValue1)
+        else value1.AsTValue := TRTTI.GetPropertyValueEx(aValue.AsObject,fValue1);
+    end
+    else value1.AsTValue := aValue;
+  end;
   case fOperator of
     TOperator.opEqual : Result := IsEqual(value1,fValue2);
     TOperator.opNotEqual : Result := not IsEqual(value1,fValue2);

+ 18 - 9
Quick.FileMonitor.pas

@@ -1,13 +1,13 @@
 { ***************************************************************************
 
-  Copyright (c) 2015-2019 Kike Pérez
+  Copyright (c) 2015-2021 Kike Pérez
 
   Unit        : Quick.FileMonitor
   Description : Watch for single file changes
   Author      : Kike Pérez
   Version     : 1.2
   Created     : 11/09/2017
-  Modified    : 29/01/2019
+  Modified    : 10/05/2021
 
   This file is part of QuickLib: https://github.com/exilon/QuickLib
 
@@ -65,6 +65,7 @@ type
     fModifedDate : TDateTime;
     fCurrentMonitorNotify : TMonitorNotify;
     fOnChangeNotify : TFileChangeNotify;
+    fIsThreadStarted : Boolean;
     procedure SetEnabled(Status : Boolean);
     procedure NotifyEvent;
   protected
@@ -86,6 +87,8 @@ implementation
 constructor TFileMonitor.Create;
 begin
   inherited Create(True);
+  fIsThreadStarted := False;
+  fEnabled := False;
   Self.FreeOnTerminate := False;
   fInterval := 1000;
   fExists := False;
@@ -166,17 +169,23 @@ end;
 
 procedure TFileMonitor.SetEnabled(Status : Boolean);
 begin
-  if (Status) and {$IFNDEF FPC}(not Started){$ELSE}(Suspended){$ENDIF} then Start;
-
   if fEnabled <> Status then
   begin
-    fEnabled := Status;
-    //gets current values
-    if TFile.Exists(fFileName) then
+    if Status then
     begin
-      fExists := True;
-      fModifedDate := TFile.GetLastWriteTime(fFileName);
+      //gets current values
+      if TFile.Exists(fFileName) then
+      begin
+        fExists := True;
+        fModifedDate := TFile.GetLastWriteTime(fFileName);
+      end;
     end;
+    if not fIsThreadStarted then
+    begin
+      fIsThreadStarted := True;
+      if (Status) and {$IFNDEF FPC}(Started = False){$ELSE}(Suspended){$ENDIF} then Start;
+    end;
+    fEnabled := Status;
   end;
 end;
 

+ 105 - 5
Quick.Files.pas

@@ -7,7 +7,7 @@
   Author      : Kike Pérez
   Version     : 1.5
   Created     : 09/03/2018
-  Modified    : 23/05/2019
+  Modified    : 16/11/2020
 
   This file is part of QuickLib: https://github.com/exilon/QuickLib
 
@@ -239,6 +239,12 @@ type
     property LastModified : TDateTime read fLastModified write fLastModified;
   end;
 
+  {$IFNDEF FPC}
+  TDirItemAddProc = reference to procedure(const diritem : TDirItem);
+  {$ELSE}
+  TDirItemAddProc = procedure(const diritem : TDirItem);
+  {$ENDIF}
+
   function CreateDummyFile(const aFilename : string; const aSize : Int64) : Boolean;
   procedure SplitFile(const aFileName : string; aSplitByteSize : Int64);
   procedure MergeFiles(const aFirstSplitFileName, aOutFileName : string); overload;
@@ -259,9 +265,11 @@ type
   function ConvertDateTimeToFileTime(const DateTime: TDateTime; const UseLocalTimeZone: Boolean): TFileTime;
   function ConvertFileTimeToDateTime(const FileTime : TFileTime; const UseLocalTimeZone : Boolean) : TDateTime;
   procedure SetDateTimeInfo(const Path: string; const CreationTime, LastAccessTime, LastWriteTime: PDateTime; const UseLocalTimeZone: Boolean);
-  function GetFiles(const Path : string; Recursive : Boolean) : TArray<TDirItem>;
+  function GetFiles(const Path : string; Recursive : Boolean) : TArray<TDirItem>; overload;
+  procedure GetFiles(const Path : string; aAddToList : TDirItemAddProc; Recursive : Boolean); overload;
   function GetDirectories(const Path : string; Recursive : Boolean) : TArray<TDirItem>;
-  function GetFilesAndDirectories(const Path : string; Recursive : Boolean) : TArray<TDirItem>;
+  function GetFilesAndDirectories(const Path : string; Recursive : Boolean) : TArray<TDirItem>; overload;
+  procedure GetFilesAndDirectories(const Path : string; aAddToList : TDirItemAddProc; Recursive : Boolean); overload;
 
 implementation
 
@@ -1315,6 +1323,33 @@ begin
   end;
 end;
 
+procedure GetFiles(const Path : string; aAddToList : TDirItemAddProc; Recursive : Boolean);
+var
+  rec : TSearchRec;
+  diritem : TDirItem;
+begin
+  if FindFirst(IncludeTrailingPathDelimiter(Path) + '*', faAnyFile, rec) = 0 then
+  try
+    repeat
+      if (rec.Attr and faDirectory) <> faDirectory then
+      begin
+        diritem.Name := rec.Name;
+        diritem.IsDirectory := False;
+        diritem.Size := rec.Size;
+        diritem.CreationDate := ConvertFileTimeToDateTime(rec.FindData.ftCreationTime,True);
+        diritem.LastModified := ConvertFileTimeToDateTime(rec.FindData.ftLastWriteTime,True);
+        aAddToList(diritem);
+      end
+      else
+      begin
+        if Recursive then GetFiles(IncludeTrailingPathDelimiter(Path) + diritem.Name,aAddToList,Recursive);
+      end;
+    until FindNext(rec) <> 0;
+  finally
+    SysUtils.FindClose(rec);
+  end;
+end;
+
 function GetDirectories(const Path : string; Recursive : Boolean) : TArray<TDirItem>;
 var
   rec : TSearchRec;
@@ -1343,8 +1378,23 @@ function GetFilesAndDirectories(const Path : string; Recursive : Boolean) : TArr
 var
   rec : TSearchRec;
   diritem : TDirItem;
+  dirpath : string;
+  wildcard : string;
 begin
-  if FindFirst(IncludeTrailingPathDelimiter(Path) + '*', faAnyFile, rec) = 0 then
+  if Path.Contains('*') then
+  begin
+    dirpath := ExtractFilePath(Path);
+    wildcard := ExtractFileName(Path);
+  end
+  else
+  begin
+    dirpath := Path;
+    wildcard := '*';
+  end;
+  dirpath := IncludeTrailingPathDelimiter(dirpath);
+
+
+  if FindFirst(dirpath + wildcard, faAnyFile, rec) = 0 then
   try
     repeat
       if (rec.Attr and faDirectory) <> faDirectory then
@@ -1364,7 +1414,57 @@ begin
         diritem.CreationDate := ConvertFileTimeToDateTime(rec.FindData.ftCreationTime,True);
         diritem.LastModified := ConvertFileTimeToDateTime(rec.FindData.ftLastWriteTime,True);
         Result := Result + [diritem];
-        if Recursive then Result := Result + GetFiles(IncludeTrailingPathDelimiter(Path) + diritem.Name,Recursive);
+        if Recursive then Result := Result + GetFilesAndDirectories(dirpath + diritem.Name,Recursive);
+      end;
+    until FindNext(rec) <> 0;
+  finally
+    SysUtils.FindClose(rec);
+  end;
+end;
+
+procedure GetFilesAndDirectories(const Path : string; aAddToList : TDirItemAddProc; Recursive : Boolean);
+var
+  rec : TSearchRec;
+  diritem : TDirItem;
+  dirpath : string;
+  wildcard : string;
+begin
+  if not Assigned(aAddToList) then raise Exception.Create('GetFilesAndDirecties: AddToList cannot be nil!');
+
+  if Path.Contains('*') then
+  begin
+    dirpath := ExtractFilePath(Path);
+    wildcard := ExtractFileName(Path);
+  end
+  else
+  begin
+    dirpath := Path;
+    wildcard := '*';
+  end;
+  dirpath := IncludeTrailingPathDelimiter(dirpath);
+
+
+  if FindFirst(dirpath + wildcard, faAnyFile, rec) = 0 then
+  try
+    repeat
+      if (rec.Attr and faDirectory) <> faDirectory then
+      begin
+        diritem.Name := rec.Name;
+        diritem.IsDirectory := False;
+        diritem.Size := rec.Size;
+        diritem.CreationDate := ConvertFileTimeToDateTime(rec.FindData.ftCreationTime,True);
+        diritem.LastModified := ConvertFileTimeToDateTime(rec.FindData.ftLastWriteTime,True);
+        aAddToList(diritem);
+      end
+      else if (rec.Name <> '.') and (rec.Name <> '..') then
+      begin
+        diritem.Name := rec.Name;
+        diritem.IsDirectory := True;
+        diritem.Size := rec.Size;
+        diritem.CreationDate := ConvertFileTimeToDateTime(rec.FindData.ftCreationTime,True);
+        diritem.LastModified := ConvertFileTimeToDateTime(rec.FindData.ftLastWriteTime,True);
+        aAddToList(diritem);
+        if Recursive then GetFilesAndDirectories(dirpath + diritem.Name,aAddToList,Recursive);
       end;
     until FindNext(rec) <> 0;
   finally

+ 8 - 4
Quick.HttpClient.pas

@@ -1,13 +1,13 @@
 { ***************************************************************************
 
-  Copyright (c) 2016-2018 Kike Pérez
+  Copyright (c) 2016-2021 Kike Pérez
 
   Unit        : Quick.HttpClient
   Description : Json Http Client
   Author      : Kike Pérez
   Version     : 1.1
   Created     : 22/05/2018
-  Modified    : 02/05/2020
+  Modified    : 02/08/2021
 
   This file is part of QuickLib: https://github.com/exilon/QuickLib
 
@@ -323,7 +323,9 @@ procedure TJsonHttpClient.SetConnectionTimeout(const aValue: Integer);
 begin
   fConnectionTimeout := aValue;
   {$IFDEF DELPHIXE8_UP}
-  fHTTPClient.ConnectionTimeout := aValue;
+    {$IFDEF DELPHIRX102_UP} //in previous versions don't exists ConnectionTimeout property
+    fHTTPClient.ConnectionTimeout := aValue;
+    {$ENDIF}
   {$ELSE}
   fHTTPClient.ConnectTimeout := aValue;
   {$ENDIF}
@@ -353,7 +355,9 @@ procedure TJsonHttpClient.SetResponseTimeout(const aValue: Integer);
 begin
   fResponseTimeout := aValue;
   {$IFDEF DELPHIXE8_UP}
-  fHTTPClient.ResponseTimeout := aValue;
+    {$IFDEF DELPHIRX102_UP} //in previous versions don't exist ResponseTimeout property
+    fHTTPClient.ResponseTimeout := aValue;
+    {$ENDIF}
   {$ELSE}
   fHTTPClient.ReadTimeout := aValue;
   {$ENDIF}

+ 9 - 3
Quick.HttpServer.Request.pas

@@ -1,13 +1,13 @@
 { ***************************************************************************
 
-  Copyright (c) 2016-2019 Kike Pérez
+  Copyright (c) 2016-2021 Kike Pérez
 
   Unit        : Quick.HttpServer.Request
   Description : Http Server Request
   Author      : Kike Pérez
   Version     : 1.8
   Created     : 30/08/2019
-  Modified    : 31/08/2019
+  Modified    : 07/02/2021
 
   This file is part of QuickLib: https://github.com/exilon/QuickLib
 
@@ -34,6 +34,9 @@ unit Quick.HttpServer.Request;
 interface
 
 uses
+  {$IFDEF DEBUG_HTTPSERVER}
+  Quick.Debug.Utils,
+  {$ENDIF}
   Classes,
   SysUtils,
   Quick.Commons,
@@ -143,7 +146,10 @@ implementation
 
 function THttpRequest.ContentAsString: string;
 begin
-  if fContent <> nil then Result := StreamToString2(fContent,TEncoding.UTF8);
+  {$IFDEF DEBUG_HTTPSERVER}
+  TDebugger.Trace(Self,'ContentAsString Encode: %s',[ContentEncoding]);
+  {$ENDIF}
+  if fContent <> nil then Result := StreamToString(fContent,TEncoding.UTF8);
 end;
 
 constructor THttpRequest.Create;

+ 2 - 0
Quick.HttpServer.Response.pas

@@ -62,6 +62,7 @@ type
     property ContentType : string read GetContentType write SetContentType;
   end;
 
+  {$M+}
   THttpResponse = class(TInterfacedObject,IHttpResponse)
   private
     fHeaders : TPairList;
@@ -94,6 +95,7 @@ type
     property ContentText : string read GetContentText write SetContentText;
     property ContentType : string read GetContentType write SetContentType;
   end;
+  {$M-}
 
 implementation
 

+ 50 - 10
Quick.HttpServer.pas

@@ -7,7 +7,7 @@
   Author      : Kike Pérez
   Version     : 1.8
   Created     : 30/08/2019
-  Modified    : 11/06/2020
+  Modified    : 12/06/2020
 
   This file is part of QuickLib: https://github.com/exilon/QuickLib
 
@@ -74,9 +74,15 @@ type
     function GetOnRequest : TRequestEvent;
     function GetCustomErrorPages: TCustomErrorPages;
     procedure SetCustomErrorPages(const Value: TCustomErrorPages);
+    function GetLogger : ILogger;
+    procedure SetLogger(const aLogger : ILogger);
+    function GetHost: string;
+    function GetPort: Integer;
     property OnNewRequest : TRequestEvent read GetOnRequest write SetOnRequest;
     property CustomErrorPages : TCustomErrorPages read GetCustomErrorPages write SetCustomErrorPages;
-    function Logger : ILogger;
+    property Host : string read GetHost;
+    property Port : Integer read GetPort;
+    property Logger : ILogger read GetLogger write SetLogger;
     procedure Start;
     procedure Stop;
   end;
@@ -91,6 +97,10 @@ type
     function GetOnRequest : TRequestEvent;
     function GetCustomErrorPages: TCustomErrorPages;
     procedure SetCustomErrorPages(const Value: TCustomErrorPages);
+    function GetLogger : ILogger;
+    procedure SetLogger(const aLogger : ILogger);
+    function GetHost: string;
+    function GetPort: Integer;
   protected
     fOnRequest : TRequestEvent;
     fHost : string;
@@ -100,13 +110,13 @@ type
   public
     constructor Create(const aHost : string; aPort : Integer; aSSLEnabled : Boolean; aLogger : ILogger = nil); virtual;
     destructor Destroy; override;
-    property Host : string read fHost;
-    property Port : Integer read fPort;
+    property Host : string read GetHost;
+    property Port : Integer read GetPort;
     property CustomErrorPages : TCustomErrorPages read GetCustomErrorPages write SetCustomErrorPages;
     property OnNewRequest : TRequestEvent read GetOnRequest write SetOnRequest;
     property OnConnect : TOnConnectEvent read fOnConnect write fOnConnect;
     property OnDisconnect : TOnDisconnectEvent read fOnDisconnect write fOnDisconnect;
-    function Logger : ILogger;
+    property Logger : ILogger read GetLogger write SetLogger;
     procedure Start; virtual; abstract;
     procedure Stop; virtual; abstract;
   end;
@@ -226,24 +236,39 @@ begin
   else aResponse.ContentText := content;
 end;
 
+function TCustomHttpServer.GetHost: string;
+begin
+  Result := fHost;
+end;
+
+function TCustomHttpServer.GetLogger: ILogger;
+begin
+  Result := fLogger;
+end;
+
 function TCustomHttpServer.GetOnRequest: TRequestEvent;
 begin
   Result := fOnRequest;
 end;
 
+function TCustomHttpServer.GetPort: Integer;
+begin
+  Result := fPort;
+end;
+
 procedure TCustomHttpServer.SetCustomErrorPages(const Value: TCustomErrorPages);
 begin
   fCustomErrorPages := Value;
 end;
 
-procedure TCustomHttpServer.SetOnRequest(aRequestEvent: TRequestEvent);
+procedure TCustomHttpServer.SetLogger(const aLogger: ILogger);
 begin
-  fOnRequest := aRequestEvent;
+  fLogger := aLogger;
 end;
 
-function TCustomHttpServer.Logger: ILogger;
+procedure TCustomHttpServer.SetOnRequest(aRequestEvent: TRequestEvent);
 begin
-  Result := fLogger;
+  fOnRequest := aRequestEvent;
 end;
 
 { THTTPServer }
@@ -267,6 +292,11 @@ begin
   //fHTTPServer.OnExecute := DoConnect;
   fHTTPServer.OnQuerySSLPort := DoOnQuerySSLPort;
   fHTTPServer.ServerSoftware := 'Quick.HttpServer';
+  fHTTPServer.MaxConnections := 0;
+  fHTTPServer.AutoStartSession := False;
+  fHTTPServer.KeepAlive := True;
+  fHTTPServer.SessionState := False;
+  fHTTPServer.ParseParams := False;
 end;
 
 destructor THTTPServer.Destroy;
@@ -319,6 +349,9 @@ begin
   Result.ContentType := aRequestInfo.ContentType;
   Result.ContentEncoding := aRequestInfo.ContentEncoding;
   Result.ContentLength := aRequestInfo.ContentLength;
+  {$IFDEF DEBUG_HTTPSERVER}
+  TDebugger.Trace(Self,'Request: Headers (%s)',[aRequestInfo.RawHeaders.Text]);
+  {$ENDIF}
   for i := 0 to aRequestInfo.RawHeaders.Count -1 do
   begin
     if not StrInArray(aRequestInfo.RawHeaders.Names[i],['Host','Accept-Encoding','Accept','User-Agent','Connection','Cache-Control']) then
@@ -391,7 +424,11 @@ begin
     on E : Exception do
     begin
       //get unexpected exception
-      if E.InheritsFrom(EControlledException) then response.ContentText := response.ContentText + '<BR>' + e.Message
+      if E.InheritsFrom(EControlledException) then
+      begin
+        Logger.Error('Request: %s %s [%d %s] %s',[request.GetMethodAsString,request.URL, response.StatusCode, response.StatusText,e.Message]);
+        response.ContentText := response.ContentText + '<BR>' + e.Message;
+      end
       else
       begin
         if response.StatusCode = 200 then
@@ -400,6 +437,9 @@ begin
           response.StatusText := 'Internal server error';
         end;
         response.ContentText := e.Message;
+        //log error
+        if response.StatusCode = 404 then Logger.Warn('Request: %s %s [%d %s] %s',[request.GetMethodAsString,request.URL, response.StatusCode, response.StatusText,e.Message])
+          else Logger.Error('Request: %s %s [%d %s] %s',[request.GetMethodAsString,request.URL, response.StatusCode, response.StatusText,e.Message]);
       end;
     end;
   end;

+ 95 - 31
Quick.IOC.pas

@@ -1,13 +1,13 @@
 { ***************************************************************************
 
-  Copyright (c) 2016-2020 Kike Pérez
+  Copyright (c) 2016-2022 Kike Pérez
 
   Unit        : Quick.IoC
   Description : IoC Dependency Injector
   Author      : Kike Pérez
   Version     : 1.0
   Created     : 19/10/2019
-  Modified    : 06/04/2020
+  Modified    : 19/01/2022
 
   This file is part of QuickLib: https://github.com/exilon/QuickLib
 
@@ -157,13 +157,34 @@ type
     procedure DoInvoke(Method: TRttiMethod;  const Args: TArray<TValue>; out Result: TValue);
   end;
 
+  IFactory<T> = interface
+  ['{92D7AB4F-4C0A-4069-A821-B057E193DE65}']
+    function New : T;
+  end;
+
+  TSimpleFactory<T : class, constructor> = class(TInterfacedObject,IFactory<T>)
+  private
+    fResolver : TIocResolver;
+  public
+    constructor Create(aResolver : TIocResolver);
+    function New : T;
+  end;
+
+  TSimpleFactory<TInterface : IInterface; TImplementation : class, constructor> = class(TInterfacedObject,IFactory<TInterface>)
+  private
+    fResolver : TIocResolver;
+  public
+    constructor Create(aResolver : TIocResolver);
+    function New : TInterface;
+  end;
+
+
   TIocContainer = class(TInterfacedObject,IIocContainer)
   private
     fRegistrator : TIocRegistrator;
     fResolver : TIocResolver;
     fInjector : TIocInjector;
     fLogger : ILogger;
-    function InterfaceTypeInfo(const AGUID : TGUID) : PTypeInfo;
   class var
     GlobalInstance: TIocContainer;
   protected
@@ -187,15 +208,24 @@ type
     function AbstractFactory<T : class, constructor>(aClass : TClass) : T; overload;
     function AbstractFactory<T : class, constructor> : T; overload;
     function RegisterTypedFactory<TFactoryInterface : IInterface; TFactoryType : class, constructor>(const aName : string = '') : TIocRegistration<TTypedFactory<TFactoryType>>;
+    function RegisterSimpleFactory<TInterface : IInterface; TImplementation : class, constructor>(const aName : string = '') : TIocRegistration;
     procedure Build;
   end;
 
+  TIocServiceLocator = class
+  public
+    class function GetService<T> : T;
+    class function TryToGetService<T: IInterface>(aService : T) : Boolean;
+  end;
+
   EIocRegisterError = class(Exception);
   EIocResolverError = class(Exception);
   EIocBuildError = class(Exception);
 
   //singleton global instance
-  function GlobalContainer: TIocContainer;
+  function GlobalContainer : TIocContainer;
+
+  function ServiceLocator : TIocServiceLocator;
 
 implementation
 
@@ -204,6 +234,11 @@ begin
   Result := TIocContainer.GlobalInstance;
 end;
 
+function ServiceLocator : TIocServiceLocator;
+begin
+  Result := TIocServiceLocator.Create;
+end;
+
 { TIocRegistration }
 
 constructor TIocRegistration.Create;
@@ -298,23 +333,6 @@ begin
   inherited;
 end;
 
-function TIocContainer.InterfaceTypeInfo(const AGUID : TGUID) : PTypeInfo;
-var
-  ctx : TRttiContext;
-  rtype : TRttiType;
-  rtypei : TRttiInterfaceType;
-begin
-  for rtype in ctx.GetTypes do
-  begin
-    if rtype.TypeKind = TTypeKind.tkInterface then
-    begin
-      rtypei := (rtype as TRttiInterfaceType);
-      if IsEqualGUID(rtypei.GUID,AGUID) then Exit(rtypei.Handle);
-    end;
-  end;
-  Result := nil;
-end;
-
 function TIocContainer.IsRegistered<TInterface, TImplementation>(const aName: string): Boolean;
 begin
   Result := fRegistrator.IsRegistered<TInterface,TImplementation>(aName);
@@ -372,6 +390,11 @@ begin
   Result := Self.RegisterOptions<T>(options);
 end;
 
+function TIocContainer.RegisterSimpleFactory<TInterface, TImplementation>(const aName: string): TIocRegistration;
+begin
+  Result := fRegistrator.RegisterInstance<IFactory<TInterface>>(TSimpleFactory<TInterface,TImplementation>.Create(fResolver),aName).AsSingleton;
+end;
+
 function TIocContainer.Resolve(aServiceType: PTypeInfo; const aName: string): TValue;
 begin
   Result := fResolver.Resolve(aServiceType,aName);
@@ -396,15 +419,18 @@ end;
 
 destructor TIocRegistrator.Destroy;
 var
-  reg : TIocRegistration;
+  i : Integer;
+  regs : TArray<TIocRegistration>;
 begin
-  for reg in fDependencies.Values do
+  //for reg in fDependencies.Values do
+  regs := fDependencies.Values.ToArray;
+  for i := High(regs) downto Low(regs) do
   begin
-    if reg <> nil then
+    if regs[i]<> nil then
     begin
       //free singleton instances not interfaced
-      if (reg is TIocRegistrationInstance) and (TIocRegistrationInstance(reg).IsSingleton) then TIocRegistrationInstance(reg).Instance.Free;
-      reg.Free;
+      if (regs[i] is TIocRegistrationInstance) and (TIocRegistrationInstance(regs[i]).IsSingleton) then TIocRegistrationInstance(regs[i]).Instance.Free;
+      regs[i].Free;
     end;
   end;
   fDependencies.Free;
@@ -414,7 +440,11 @@ end;
 function TIocRegistrator.GetKey(aPInfo : PTypeInfo; const aName : string = ''): string;
 begin
   {$IFDEF NEXTGEN}
-  Result := aPInfo.Name.ToString;
+    {$IFDEF DELPHISYDNEY_UP}
+    Result := string(aPInfo.Name);
+    {$ELSE}
+    Result := aPInfo .Name.ToString;
+    {$ENDIF}
   {$ELSE}
   Result := string(aPInfo.Name);
   {$ENDIF}
@@ -653,15 +683,12 @@ function TIocResolver.ResolveAll<T>(const aName : string = '') : TList<T>;
 var
   pInfo : PTypeInfo;
   reg : TIocRegistration;
-  pair : TPair<string,TIocRegistration>;
 begin
   Result := TList<T>.Create;
   pInfo := TypeInfo(T);
 
-  for pair in fRegistrator.Dependencies.ToArray do
+  for reg in fRegistrator.Dependencies.Values do
   begin
-    reg := pair.Value;
-    //var a := pair.Key;
     if reg.IntfInfo = pInfo then Self.Resolve(pInfo,aName);
   end;
 end;
@@ -714,4 +741,41 @@ begin
   Result := fResolver.CreateInstance(TClass(T)).AsType<T>;
 end;
 
+{ TIocServiceLocator }
+
+class function TIocServiceLocator.GetService<T> : T;
+begin
+  Result := GlobalContainer.Resolve<T>;
+end;
+
+class function TIocServiceLocator.TryToGetService<T>(aService : T) : Boolean;
+begin
+  Result := GlobalContainer.IsRegistered<T>('');
+  if Result then aService := GlobalContainer.Resolve<T>;
+end;
+
+{ TSimpleFactory<T> }
+
+constructor TSimpleFactory<T>.Create(aResolver: TIocResolver);
+begin
+  fResolver := aResolver;
+end;
+
+function TSimpleFactory<T>.New: T;
+begin
+  Result := fResolver.CreateInstance(TClass(T)).AsType<T>;
+end;
+
+{ TSimpleFactory<TInterface, TImplementation> }
+
+constructor TSimpleFactory<TInterface, TImplementation>.Create(aResolver: TIocResolver);
+begin
+  fResolver := aResolver;
+end;
+
+function TSimpleFactory<TInterface, TImplementation>.New: TInterface;
+begin
+  Result := fResolver.CreateInstance(TClass(TImplementation)).AsType<TInterface>;
+end;
+
 end.

+ 13 - 10
Quick.JSON.Utils.pas

@@ -1,13 +1,13 @@
 { ***************************************************************************
 
-  Copyright (c) 2015-2018 Kike Pérez
+  Copyright (c) 2015-2021 Kike Pérez
 
   Unit        : Quick.JSON.Utils
   Description : Json utils
   Author      : Kike Pérez
   Version     : 1.4
   Created     : 21/09/2018
-  Modified    : 24/09/2018
+  Modified    : 09/03/2021
 
   This file is part of QuickLib: https://github.com/exilon/QuickLib
 
@@ -62,7 +62,10 @@ end;
 
 class function TJsonUtils.JsonFormat(const json : string) : string;
 const
-  EOL = #13#10;
+  {$IFNDEF DELPHIRX10_UP}
+    sLineBreak  = {$IFDEF LINUX} AnsiChar(#10) {$ENDIF}
+                  {$IFDEF MSWINDOWS} AnsiString(#13#10) {$ENDIF};
+  {$ENDIF}
   INDENT = '    ';
   SPACE = ' ';
 var
@@ -96,22 +99,22 @@ begin
         '{','[' :
           begin
             LIndent := LIndent + INDENT;
-            if json[i+1] in ['}',']'] then Result := Result + c
-              else Result := Result + c + EOL + LIndent;
+            if (json[i+1] = '}') or (json[i+1] = ']') then Result := Result + c
+              else Result := Result + c + sLineBreak  + LIndent;
             isEOL := True;
           end;
         ',' :
           begin
             isEOL := False;
-            Result := Result + c + EOL + LIndent;
+            Result := Result + c + sLineBreak  + LIndent;
           end;
         '}',']' :
           begin
             Delete(LIndent, 1, Length(INDENT));
-            if not isEOL then Result := Result + EOL;
-            if json[i+1] = ',' then Result := Result + LIndent + c
-              else if json[i-1] in ['{','['] then Result := Result + c + EOL
-                else Result := Result + LIndent + c + EOL;
+            if not isEOL then Result := Result + sLineBreak ;
+            if (i<json.Length) and (json[i+1] = ',') then Result := Result + LIndent + c
+              else if (json[i-1] = '}') or (json[i-1] = ']') then Result := Result + c + sLineBreak
+                else Result := Result + LIndent + c + sLineBreak ;
             isEOL := True;
           end;
         else

+ 206 - 66
Quick.Json.Serializer.pas

@@ -1,13 +1,13 @@
 { ***************************************************************************
 
-  Copyright (c) 2015-2020 Kike Pérez
+  Copyright (c) 2015-2022 Kike Pérez
 
   Unit        : Quick.JSON.Serializer
   Description : Json Serializer
   Author      : Kike Pérez
   Version     : 1.12
   Created     : 21/05/2018
-  Modified    : 16/06/2020
+  Modified    : 26/01/2022
 
   This file is part of QuickLib: https://github.com/exilon/QuickLib
 
@@ -42,6 +42,7 @@ uses
   Rtti,
   TypInfo,
   Quick.Serializer.Intf,
+  Quick.Base64,
   {$IFDEF FPC}
    rttiutils,
    fpjson,
@@ -127,17 +128,21 @@ type
     fSerializeLevel : TSerializeLevel;
     fUseEnumNames : Boolean;
     fUseJsonCaseSense : Boolean;
+    fUseBase64Stream : Boolean;
+    fUseNullStringsAsEmpty : Boolean;
     function GetValue(aAddr: Pointer; aType: TRTTIType): TValue; overload;
+    {$IFDEF FPC}
     function GetValue(aAddr: Pointer; aTypeInfo: PTypeInfo): TValue; overload;
+    {$ENDIF}
     function IsAllowedProperty(aObject : TObject; const aPropertyName : string) : Boolean;
-    function GetPropertyValue(Instance : TObject; const PropertyName : string) : TValue;
+    //function GetPropertyValue(Instance : TObject; const PropertyName : string) : TValue;
     function GetPropertyValueFromObject(Instance : TObject; const PropertyName : string) : TValue;
     {$IFNDEF FPC}
     function GetFieldValueFromRecord(const aValue : TValue; const FieldName : string) : TValue;
     {$ENDIF}
+    {$IFDEF FPC}
     procedure SetPropertyValue(Instance : TObject; aPropInfo : PPropInfo; aValue : TValue); overload;
     procedure SetPropertyValue(Instance : TObject; const PropertyName : string; aValue : TValue); overload;
-    {$IFDEF FPC}
     function FloatProperty(aObject : TObject; aPropInfo: PPropInfo): string;
     function GetPropType(aPropInfo: PPropInfo): PTypeInfo;
     procedure LoadSetProperty(aInstance : TObject; aPropInfo: PPropInfo; const aValue: string);
@@ -150,14 +155,18 @@ type
     constructor Create(aSerializeLevel : TSerializeLevel; aUseEnumNames : Boolean = True);
     property UseEnumNames : Boolean read fUseEnumNames write fUseEnumNames;
     property UseJsonCaseSense : Boolean read fUseJsonCaseSense write fUseJsonCaseSense;
+    property UseBase64Stream : Boolean read fUseBase64Stream write fUseBase64Stream;
+    property UseNullStringsAsEmpty : Boolean read fUseNullStringsAsEmpty write fUseNullStringsAsEmpty;
     function GetJsonPairValueByName(aJson : TJSONObject; const aName : string) : TJsonValue;
     function GetJsonPairByName(aJson : TJSONObject; const aName : string) : TJSONPair;
     function IsGenericList(aObject : TObject) : Boolean;
+    function IsStream(aObject : TObject) : Boolean;
     function IsGenericXArray(const aClassName : string) : Boolean;
     function GetGenericListType(aObject : TObject) : TGenericListType;
     //serialize methods
     function SerializeValue(const aValue : TValue) : TJSONValue;
     function SerializeObject(aObject : TObject) : TJSONObject; overload;
+    function SerializeStream(aObject : TObject) : TJSONValue;
     {$IFNDEF FPC}
     function SerializeDynArray(const aValue: TValue; aMaxElements : Integer = -1) : TJsonArray;
     function SerializeRecord(const aValue : TValue) : TJSONValue;
@@ -168,6 +177,7 @@ type
     function DeserializeClass(aType : TClass; const aJson : TJSONObject) : TObject;
     function DeserializeObject(aObject : TObject; const aJson : TJSONObject) : TObject; overload;
     function DeserializeProperty(aObject : TObject; const aName : string; aProperty : TRttiProperty; const aJson : TJSONObject) : TObject; overload;
+    function DeserializeStream(aObject : TObject; const aJson : TJSONValue) : TObject;
     {$IFNDEF FPC}
     function DeserializeType(aObject : TObject; aType : TTypeKind; aTypeInfo : PTypeInfo; const aValue: string) : TValue;
     function DeserializeDynArray(aTypeInfo : PTypeInfo; aObject : TObject; const aJsonArray: TJSONArray) : TValue;
@@ -185,21 +195,30 @@ type
     fSerializeLevel : TSerializeLevel;
     fUseEnumNames : Boolean;
     fUseJsonCaseSense : Boolean;
+    fUseBase64Stream : Boolean;
+    fUseNullStringsAsEmpty : Boolean;
     fRTTIJson : TRTTIJson;
   private
     procedure SetUseEnumNames(const Value: Boolean);
     procedure SetUseJsonCaseSense(const Value: Boolean);
     procedure SetSerializeLevel(const Value: TSerializeLevel);
+    procedure SetUseBase64Stream(const Value: Boolean);
+    //Only Delphi -> Workaround, use this when something passes : {Test : "Null"} but we expect : {Test : ""}
+    procedure SetUseNullStringsAsEmpty(const Value : Boolean);
   public
-    constructor Create(aSerializeLevel: TSerializeLevel; aUseEnumNames : Boolean = True);
+    constructor Create(aSerializeLevel: TSerializeLevel; aUseEnumNames : Boolean = True; aUseNullStringsAsEmpty : Boolean = False);
     destructor Destroy; override;
     property SerializeLevel : TSerializeLevel read fSerializeLevel write SetSerializeLevel;
     property UseEnumNames : Boolean read fUseEnumNames write SetUseEnumNames;
     property UseJsonCaseSense : Boolean read fUseJsonCaseSense write SetUseJsonCaseSense;
+    property UseBase64Stream : Boolean read fUseBase64Stream write SetUseBase64Stream;
+    property UseNullStringsAsEmpty : Boolean read fUseNullStringsAsEmpty write SetUseNullStringsAsEmpty;
     function JsonToObject(aType : TClass; const aJson: string) : TObject; overload;
     function JsonToObject(aObject : TObject; const aJson: string) : TObject; overload;
+    function JsonStreamToObject(aObject : TObject; aJsonStream : TStream) : TObject;
     function ObjectToJson(aObject : TObject; aIndent : Boolean = False): string;
     function ObjectToJsonString(aObject : TObject; aIndent : Boolean = False): string;
+    procedure ObjectToJsonStream(aObject : TObject; aStream : TStream);
     function ValueToJson(const aValue : TValue; aIndent : Boolean = False) : string;
     function ValueToJsonString(const aValue : TValue; aIndent : Boolean = False) : string;
     function ArrayToJson<T>(aArray : TArray<T>; aIndent : Boolean = False) : string;
@@ -435,11 +454,26 @@ begin
 end;
 {$ENDIF}
 
+function TRTTIJson.DeserializeStream(aObject: TObject; const aJson: TJSONValue): TObject;
+var
+ stream : TStringStream;
+begin
+  if fUseBase64Stream then stream := TStringStream.Create(Base64Decode(aJson.Value),TEncoding.Ansi)
+    else stream := TStringStream.Create({$IFNDEF FPC}aJson.Value{$ELSE}string(aJson.Value){$ENDIF},TEncoding.Ansi);
+  try
+    TStream(aObject).CopyFrom(stream,stream.Size);
+  finally
+    stream.Free;
+  end;
+  Result := aObject;
+end;
+
 constructor TRTTIJson.Create(aSerializeLevel : TSerializeLevel; aUseEnumNames : Boolean = True);
 begin
   fSerializeLevel := aSerializeLevel;
   fUseEnumNames := aUseEnumNames;
   fUseJsonCaseSense := False;
+  fUseBase64Stream := True;
 end;
 
 {$IFNDEF FPC}
@@ -519,8 +553,14 @@ begin
     begin
       DeserializeList(aObject,'List',aJson);
       Exit;
-    end;
+    end
+    else
     {$ENDIF}
+    if IsStream(aObject) then
+    begin
+      DeserializeStream(aObject,aJson);
+      Exit;
+    end;
     //if  standard object
     rType := ctx.GetType(aObject.ClassInfo);
     for rProp in rType.GetProperties do
@@ -548,9 +588,9 @@ begin
               rProp.SetValue(aObject,propvalue);
             end;
             if IsGenericList(propvalue.AsObject) then DeserializeList(propvalue.AsObject,'List',TJSONObject(aJson.GetValue(propertyname)))
-              else Result := DeserializeProperty(Result,propertyname,rProp,aJson);
+            else Result := DeserializeProperty(Result,propertyname,rProp,aJson);
           end
-          else if IsGenericXArray(propvalue{$IFNDEF NEXTGEN}.TypeInfo.Name{$ELSE}.TypeInfo.NameFld.ToString{$ENDIF}) then
+          else if IsGenericXArray(string(propvalue{$IFNDEF NEXTGEN}.TypeInfo.Name{$ELSE}.TypeInfo.NameFld.ToString{$ENDIF})) then
           begin
             DeserializeXArray(Result,propvalue,rProp,propertyname,aJson);
           end
@@ -679,6 +719,12 @@ begin
 end;
 {$ENDIF}
 
+function StringToGUIDEx(const aGUID : string) : TGUID;
+begin
+  if not aGUID.StartsWith('{') then Result := System.SysUtils.StringToGUID('{' + aGUID + '}')
+    else Result := System.SysUtils.StringToGUID(aGUID);
+end;
+
 function TRTTIJson.DeserializeProperty(aObject : TObject; const aName : string; aProperty : TRttiProperty; const aJson : TJSONObject) : TObject;
 var
   rValue : TValue;
@@ -704,10 +750,11 @@ begin
       case aProperty.PropertyType.TypeKind of
         tkDynArray :
           begin
-            if member is TJSONNull then Exit;
             {$IFNDEF FPC}
+            if member is TJSONNull then Exit;
             jArray := TJSONObject.ParseJSONValue(member.ToJSON) as TJSONArray;
             {$ELSE}
+            if member.ClassType = TJSONNull.ClassType then Exit;
             jArray := TJSONArray(TJSONObject.ParseJSONValue(member.ToJSON));
             {$ENDIF}
             try
@@ -755,7 +802,7 @@ begin
           begin
             if aProperty.GetValue(aObject).TypeInfo = System.TypeInfo(TGUID) then
             begin
-              rValue:=TValue.From<TGUID>(StringToGUID(member.ToJSON.DeQuotedString('"')));
+              rValue:=TValue.From<TGUID>(StringToGUID(UnQuotedStr(member.ToJSON,'"')));
             end
             else
             begin
@@ -799,11 +846,14 @@ var
   fsettings : TFormatSettings;
 begin
   try
-    value := AnsiDequotedStr(aValue,'"');
+    value := UnQuotedStr(aValue,'"');
     case aType of
       tkString, tkLString, tkWString, tkUString :
         begin
-          Result := value;
+          if fUseNullStringsAsEmpty and (CompareText(value, 'null') = 0) then
+            Result := ''
+          else
+            Result := value;
         end;
       tkChar, tkWChar :
         begin
@@ -811,11 +861,13 @@ begin
         end;
       tkInteger :
         begin
-          Result := StrToInt(value);
+          if CompareText(value,'null') <> 0 then Result := StrToIntDef(value,0)
+            else Result := 0;
         end;
       tkInt64 :
         begin
-          Result := StrToInt64(value);
+          if CompareText(value,'null') <> 0 then Result := StrToInt64Def(value,0)
+           else Result := 0;
         end;
       tkFloat :
         begin
@@ -876,7 +928,7 @@ var
   fsettings : TFormatSettings;
 begin
   try
-    value := AnsiDequotedStr(aValue,'"');
+    value := UnQuotedStr(aValue,'"');
 
     if value = '' then
     begin
@@ -897,11 +949,13 @@ begin
         end;
       tkInteger :
         begin
-          Result := StrToInt(value);
+          if CompareText(value,'null') <> 0 then Result := StrToInt(value)
+            else Result := 0;
         end;
       tkInt64 :
         begin
-          Result := StrToInt64(value);
+          if CompareText(value,'null') <> 0 then Result := StrToInt64(value)
+            else Result := 0;
         end;
       tkFloat :
         begin
@@ -973,6 +1027,12 @@ begin
   Result := (cname.StartsWith('TObjectList')) or (cname.StartsWith('TList'));
 end;
 
+function TRTTIJson.IsStream(aObject : TObject) : Boolean;
+begin
+  if aObject = nil then Exit(False);
+  Result := aObject.InheritsFrom(TStream);
+end;
+
 function TRTTIJson.GetGenericListType(aObject : TObject) : TGenericListType;
 var
   cname : string;
@@ -1036,49 +1096,49 @@ begin
   Result := nil;
 end;
 
-function TRTTIJson.GetPropertyValue(Instance : TObject; const PropertyName : string) : TValue;
-var
-  pinfo : PPropInfo;
-begin
-  Result := nil;
-  pinfo := GetPropInfo(Instance,PropertyName);
-  if pinfo = nil then raise EJsonSerializeError.CreateFmt('Property "%s" not found!',[PropertyName]);
-  case pinfo.PropType^.Kind of
-    tkInteger : Result := GetOrdProp(Instance,pinfo);
-    tkInt64 : Result := GetInt64Prop(Instance,PropertyName);
-    tkFloat : Result := GetFloatProp(Instance,PropertyName);
-    tkChar : Result := Char(GetOrdProp(Instance,PropertyName));
-    {$IFDEF FPC}
-    tkWString : Result := GetWideStrProp(Instance,PropertyName);
-    tkSString,
-    tkAString,
-    {$ELSE}
-    tkWString,
-    {$ENDIF}
-    tkLString : Result := GetStrProp(Instance,pinfo);
-    {$IFDEF FPC}
-    tkEnumeration :
-      begin
-        if fUseEnumNames then Result := GetEnumName(pinfo.PropType,GetOrdProp(Instance,PropertyName))
-          else Result := GetOrdProp(Instance,PropertyName);
-      end;
-    {$ELSE}
-    tkEnumeration :
-      begin
-        if fUseEnumNames then Result := GetEnumName(@pinfo.PropType,GetOrdProp(Instance,PropertyName))
-          else Result := GetOrdProp(Instance,PropertyName);
-      end;
-    {$ENDIF}
-    tkSet : Result := GetSetProp(Instance,pinfo,True);
-    {$IFNDEF FPC}
-    tkClass :
-    {$ELSE}
-    tkBool : Result := Boolean(GetOrdProp(Instance,pinfo));
-    tkObject :
-    {$ENDIF} Result := GetObjectProp(Instance,pinfo);
-    tkDynArray : Result := GetDynArrayProp(Instance,pinfo);
-  end;
-end;
+//function TRTTIJson.GetPropertyValue(Instance : TObject; const PropertyName : string) : TValue;
+//var
+//  pinfo : PPropInfo;
+//begin
+//  Result := nil;
+//  pinfo := GetPropInfo(Instance,PropertyName);
+//  if pinfo = nil then raise EJsonSerializeError.CreateFmt('Property "%s" not found!',[PropertyName]);
+//  case pinfo.PropType^.Kind of
+//    tkInteger : Result := GetOrdProp(Instance,pinfo);
+//    tkInt64 : Result := GetInt64Prop(Instance,PropertyName);
+//    tkFloat : Result := GetFloatProp(Instance,PropertyName);
+//    tkChar : Result := Char(GetOrdProp(Instance,PropertyName));
+//    {$IFDEF FPC}
+//    tkWString : Result := GetWideStrProp(Instance,PropertyName);
+//    tkSString,
+//    tkAString,
+//    {$ELSE}
+//    tkWString,
+//    {$ENDIF}
+//    tkLString : Result := GetStrProp(Instance,pinfo);
+//    {$IFDEF FPC}
+//    tkEnumeration :
+//      begin
+//        if fUseEnumNames then Result := GetEnumName(pinfo.PropType,GetOrdProp(Instance,PropertyName))
+//          else Result := GetOrdProp(Instance,PropertyName);
+//      end;
+//    {$ELSE}
+//    tkEnumeration :
+//      begin
+//        if fUseEnumNames then Result := GetEnumName(@pinfo.PropType,GetOrdProp(Instance,PropertyName))
+//          else Result := GetOrdProp(Instance,PropertyName);
+//      end;
+//    {$ENDIF}
+//    tkSet : Result := GetSetProp(Instance,pinfo,True);
+//    {$IFNDEF FPC}
+//    tkClass :
+//    {$ELSE}
+//    tkBool : Result := Boolean(GetOrdProp(Instance,pinfo));
+//    tkObject :
+//    {$ENDIF} Result := GetObjectProp(Instance,pinfo);
+//    tkDynArray : Result := GetDynArrayProp(Instance,pinfo);
+//  end;
+//end;
 
 function TRTTIJson.GetPropertyValueFromObject(Instance : TObject; const PropertyName : string) : TValue;
 var
@@ -1103,6 +1163,7 @@ begin
 end;
 {$ENDIF}
 
+{$IFDEF FPC}
 procedure TRTTIJson.SetPropertyValue(Instance : TObject; const PropertyName : string; aValue : TValue);
 var
   pinfo : PPropInfo;
@@ -1139,7 +1200,6 @@ begin
   end;
 end;
 
-{$IFDEF FPC}
 procedure TRTTIJson.LoadSetProperty(aInstance : TObject; aPropInfo: PPropInfo; const aValue: string);
 type
   TCardinalSet = set of 0..SizeOf(Cardinal) * 8 - 1;
@@ -1188,7 +1248,7 @@ begin
     Exit;
   end;
 
-  Result := TJSONObject.Create;
+  Result := nil;
   try
     //if is GenericList
     if IsGenericList(aObject) then
@@ -1201,7 +1261,15 @@ begin
       Result := TJSONObject(SerializeValue(propvalue));
       {$ENDIF}
       Exit;
-    end;
+    end
+    {$IFNDEF FPC}
+    else if IsStream(aObject) then
+    begin
+      Result := TJSONObject(SerializeStream(aObject));
+      Exit;
+    end
+    {$ENDIF}
+    else Result := TJSONObject.Create;
     //if is standard object
     propertyname := '';
     rType := ctx.GetType(aObject.ClassInfo);
@@ -1237,7 +1305,7 @@ begin
 //            end
             if propvalue.IsObject then jpair.JsonValue := SerializeObject(propvalue.AsObject)
             {$IFNDEF FPC}
-            else if (not propvalue.IsObject) and (IsGenericXArray(propvalue{$IFNDEF NEXTGEN}.TypeInfo.Name{$ELSE}.TypeInfo.NameFld.ToString{$ENDIF})) then
+            else if (not propvalue.IsObject) and (IsGenericXArray(string(propvalue{$IFNDEF NEXTGEN}.TypeInfo.Name{$ELSE}.TypeInfo.NameFld.ToString{$ENDIF}))) then
             begin
               jpair.JsonValue := SerializeValue(GetFieldValueFromRecord(propvalue,'fArray'));
             end
@@ -1263,7 +1331,7 @@ begin
   except
     on E : Exception do
     begin
-      Result.Free;
+      if Result <> nil then Result.Free;
       if not propertyname.IsEmpty then raise EJsonSerializeError.CreateFmt('Serialize Error -> Object property: "%s" (%s)',[propertyname,e.Message])
        else raise EJsonSerializeError.CreateFmt('Serialize Error -> Object (%s)',[e.Message]);
     end;
@@ -1275,10 +1343,12 @@ begin
   TValue.Make(aAddr,aType.Handle,Result);
 end;
 
+{$IFDEF FPC}
 function TRTTIJson.GetValue(aAddr: Pointer; aTypeInfo: PTypeInfo): TValue;
 begin
   TValue.Make(aAddr,aTypeInfo,Result);
 end;
+{$ENDIF}
 
 function TRTTIJson.SerializeValue(const aValue : TValue) : TJSONValue;
 begin
@@ -1389,6 +1459,23 @@ begin
   if Result = nil then Result := TJSONNull.Create;
 end;
 
+function TRTTIJson.SerializeStream(aObject: TObject): TJSONValue;
+var
+  stream : TStream;
+begin
+  Result := nil;
+  try
+     stream := TStream(aObject);
+    if fUseBase64Stream then Result := TJSONString.Create(Base64Encode(StreamToString(stream,TEncoding.Ansi)))
+      else Result := TJSONString.Create(StreamToString(stream,TEncoding.Ansi));
+  except
+    on E : Exception do
+    begin
+      EJsonSerializeError.CreateFmt('Serialize Error -> Stream (%s)',[e.Message]);
+    end;
+  end;
+end;
+
 {$IFNDEF FPC}
 function TRTTIJson.SerializeDynArray(const aValue: TValue; aMaxElements : Integer = -1) : TJsonArray;
 var
@@ -1612,7 +1699,7 @@ end;
 
 { TJsonSerializer}
 
-constructor TJsonSerializer.Create(aSerializeLevel: TSerializeLevel; aUseEnumNames : Boolean = True);
+constructor TJsonSerializer.Create(aSerializeLevel: TSerializeLevel; aUseEnumNames : Boolean = True; aUseNullStringsAsEmpty : Boolean = False);
 begin
   {$IFDEF FPC}
   if aSerializeLevel = TSerializeLevel.slPublicProperty then raise EJsonSerializeError.Create('FreePascal RTTI only supports published properties');
@@ -1620,8 +1707,12 @@ begin
   fSerializeLevel := aSerializeLevel;
   fUseEnumNames := aUseEnumNames;
   fUseJsonCaseSense := False;
+  fUseBase64Stream := True;
+  fUseNullStringsAsEmpty := aUseNullStringsAsEmpty;
   fRTTIJson := TRTTIJson.Create(aSerializeLevel,aUseEnumNames);
   fRTTIJson.UseJsonCaseSense := fUseJsonCaseSense;
+  fRTTIJson.UseBase64Stream := fUseBase64Stream;
+  fRTTIJson.UseNullStringsAsEmpty := fUseNullStringsAsEmpty;
 end;
 
 destructor TJsonSerializer.Destroy;
@@ -1707,6 +1798,29 @@ begin
   end;
 end;
 
+procedure TJsonSerializer.ObjectToJsonStream(aObject: TObject; aStream: TStream);
+var
+  json : TJsonObject;
+  ss : TStringStream;
+begin
+  {$IFDEF DEBUG_SERIALIZER}
+    TDebugger.TimeIt(Self,'ObjectToJsonStream',aObject.ClassName);
+  {$ENDIF}
+  if aStream = nil then raise EJsonSerializeError.Create('stream parameter cannot be nil!');
+
+  json := fRTTIJson.SerializeObject(aObject);
+  try
+    ss := TStringStream.Create(json.ToString,TEncoding.UTF8);
+    try
+      aStream.CopyFrom(ss,ss.Size);
+    finally
+      ss.Free;
+    end;
+  finally
+    json.Free;
+  end;
+end;
+
 function TJsonSerializer.ObjectToJsonString(aObject : TObject; aIndent : Boolean = False): string;
 var
   json: TJSONObject;
@@ -1791,7 +1905,21 @@ begin
   end;
 end;
 
+function TJsonSerializer.JsonStreamToObject(aObject: TObject; aJsonStream: TStream): TObject;
+var
+  json : string;
+begin
+  {$IFDEF DEBUG_SERIALIZER}
+    TDebugger.TimeIt(Self,'JsonStreamToObject','');
+  {$ENDIF}
+  if aJsonStream = nil then raise EJsonDeserializeError.Create('JsonStream param cannot be nil!');
+
+  json := StreamToString(aJsonStream,TEncoding.UTF8);
+  Result := JsonToObject(aObject,json);
+end;
+
 {$IFNDEF FPC}
+
 function TJsonSerializer.JsonToArray<T>(const aJson: string): TArray<T>;
 var
   jarray: TJSONArray;
@@ -1849,6 +1977,12 @@ begin
   if Assigned(fRTTIJson) then fRTTIJson.fSerializeLevel := Value;
 end;
 
+procedure TJsonSerializer.SetUseBase64Stream(const Value: Boolean);
+begin
+  fUseBase64Stream := Value;
+  if Assigned(fRTTIJson) then fRTTIJson.UseBase64Stream := Value;
+end;
+
 procedure TJsonSerializer.SetUseEnumNames(const Value: Boolean);
 begin
   fUseEnumNames := Value;
@@ -1861,6 +1995,12 @@ begin
   if Assigned(fRTTIJson) then fRTTIJson.UseJsonCaseSense := Value;
 end;
 
+procedure TJsonSerializer.SetUseNullStringsAsEmpty(const Value: Boolean);
+begin
+  fUseNullStringsAsEmpty := Value;
+  if Assigned(fRTTIJson) then fRTTIJson.fUseNullStringsAsEmpty := Value;
+end;
+
 {$IFNDEF FPC}
 { TCommentProperty }
 

+ 56 - 11
Quick.Linq.pas

@@ -1,13 +1,13 @@
 { ***************************************************************************
 
-  Copyright (c) 2016-2019 Kike Pérez
+  Copyright (c) 2016-2022 Kike Pérez
 
   Unit        : Quick.Linq
   Description : Arrays and Generic Lists Linq functions
   Author      : Kike Pérez
   Version     : 1.0
   Created     : 04/04/2019
-  Modified    : 22/03/20120
+  Modified    : 27/01/2022
 
   This file is part of QuickLib: https://github.com/exilon/QuickLib
 
@@ -145,12 +145,14 @@ type
   TLinqQuery<T : class> = class(TInterfacedObject,ILinqQuery<T>)
   private type
     arrayOfT = array of T;
+    TArrType = (atArray, atXArray, atList, atObjectList);
   private
     fWhereClause : TExpression;
     fOrderBy : TArray<string>;
     fOrderDirection : TOrderDirection;
-    //fPList : Pointer;
+    fPList : Pointer;
     fList : arrayOfT;
+    fArrType : TArrType;
     function FormatParams(const aWhereClause : string; aWhereParams : array of const) : string;
     procedure DoOrderBy(vArray : ArrayOfT);
     function Compare(const aPropertyName : string; L, R : T) : Integer;
@@ -205,30 +207,43 @@ end;
 constructor TLinqQuery<T>.Create(aArray: TArray<T>);
 begin
   Clear;
+  fPList := Pointer(aArray);
   fList := aArray;
+  fArrType := TArrType.atArray;
 end;
 
 {$IFNDEF FPC}
 constructor TLinqQuery<T>.Create(aObjectList: TObjectList<T>);
 begin
   Clear;
-  //Create(aObjectList.List);
-  //fPList := Pointer(aObjectList.List);
-  //fList := arrayOfT(fPList);
+  fPList := Pointer(aObjectList);
+  {$IFDEF DELPHIRX104_UP}
+  fList := aObjectList.PList^;
+  {$ELSE}
   fList := aObjectList.List;
+  {$ENDIF}
+  fArrType := TArrType.atObjectList;
 end;
 {$ENDIF}
 
 constructor TLinqQuery<T>.Create(aXArray: TxArray<T>);
 begin
   Clear;
-  fList := aXArray;
+  fPList := Pointer(aXArray);
+  fList := aXArray.PArray^;
+  fArrType := TArrType.atXArray;
 end;
 
 constructor TLinqQuery<T>.Create(aList: TList<T>);
 begin
   Clear;
+  fPList := Pointer(aList);
+  {$IFDEF DELPHIRX104_UP}
+  fList := aList.PList^;
+  {$ELSE}
   fList := aList.ToArray;
+  {$ENDIF}
+  fArrType := TArrType.atList;
 end;
 
 function TLinqQuery<T>.Compare(const aPropertyName: string; L, R: T): Integer;
@@ -285,8 +300,22 @@ begin
   begin
     if fWhereClause.Validate(fList[i]) then
     begin
-      TObject(fList[i]).Free;
-      //System.Delete(fList,i,1);
+      case fArrType of
+        TArrType.atArray, TArrType.atXArray :
+          begin
+            TObject(fList[i]).Free;
+            System.Delete(fList,i,1);
+            //fPList := Pointer(fList);
+          end;
+        TArrType.atList :
+          begin
+            TList<T>(fPList).Delete(i);
+          end;
+        TArrType.atObjectList :
+          begin
+            TObjectList<T>(fPList).Delete(i);
+          end;
+      end;
       Inc(Result);
     end;
   end;
@@ -359,6 +388,11 @@ function TLinqQuery<T>.Select: TxArray<T>;
 var
   obj : T;
 begin
+  {$If Defined(FPC) OR Defined(DELPHIRX102_UP)}
+  Result := [];
+  {$ELSE}
+  Result := nil;
+  {$ENDIF}
   if fWhereClause = nil then raise ELinqNotValidExpression.Create('Not valid expression defined!');
   for obj in fList do
   begin
@@ -402,6 +436,11 @@ var
   obj : T;
   i : Integer;
 begin
+  {$If Defined(FPC) OR Defined(DELPHIRX102_UP)}
+  Result := [];
+  {$ELSE}
+  Result := nil;
+  {$ENDIF}
   DoOrderBy(fList);
   if fWhereClause = nil then raise ELinqNotValidExpression.Create('Not valid expression defined!');
   i := 0;
@@ -489,9 +528,9 @@ begin
       vtAnsiString : Result := StringReplace(Result,'?',string(aWhereParams[i].VAnsiString),[]);
       vtWideString : Result := StringReplace(Result,'?',string(aWhereParams[i].VWideString^),[]);
       {$IFNDEF NEXTGEN}
-      vtString : Result := StringReplace(Result,'?',aWhereParams[i].VString^,[]);
+      vtString : Result := StringReplace(Result,'?',string(aWhereParams[i].VString^),[]);
       {$ENDIF}
-      vtChar : Result := StringReplace(Result,'?',aWhereParams[i].VChar,[]);
+      vtChar : Result := StringReplace(Result,'?',string(aWhereParams[i].VChar),[]);
       vtPChar : Result := StringReplace(Result,'?',string(aWhereParams[i].VPChar),[]);
     else Result := StringReplace(Result,'?', DbQuotedStr(string(aWhereParams[i].VUnicodeString)),[]);
     end;
@@ -578,7 +617,11 @@ end;
 
 constructor TLinqArray<T>.Create(aArray: TArray<T>);
 begin
+  {$IFDEF DELPHIRX104_UP}
+  Pointer(fArray) := aArray;
+  {$ELSE}
   fArray := aArray;
+  {$ENDIF}
 end;
 
 function TLinqArray<T>.Delete: Integer;
@@ -631,6 +674,7 @@ function TLinqArray<T>.Select: TArray<T>;
 var
   value : T;
 begin
+  Result := [];
   //DoOrderBy(fList);
   if fMatchString.IsEmpty then raise ELinqNotValidExpression.Create('Not valid expression defined!');
   for value in fArray do
@@ -670,6 +714,7 @@ var
   i : Integer;
   limit : Integer;
 begin
+  Result := [];
   if aLimit > High(fArray) then limit := High(fArray)
     else limit := aLimit;
   SetLength(Result,limit);

+ 1 - 0
Quick.Log.pas

@@ -49,6 +49,7 @@ uses
   {$ENDIF}
   {$IF Defined(NEXTGEN) OR Defined(LINUX) or Defined(MACOS)}
   syncObjs,
+  Posix.Unistd,
   {$ENDIF}
   SysUtils;
 

+ 6 - 0
Quick.Logger.Intf.pas

@@ -84,6 +84,7 @@ type
     procedure &Except(const aMsg : string; aValues : array of const); overload;
     procedure &Except(const aMsg, aException, aStackTrace : string); overload;
     procedure &Except(const aMsg : string; aValues: array of const; const aException, aStackTrace: string); overload;
+    procedure &Except(MsgObject : TObject); overload;
   end;
 
 implementation
@@ -151,6 +152,11 @@ begin
 
 end;
 
+procedure TNullLogger.&Except(MsgObject: TObject);
+begin
+
+end;
+
 procedure TNullLogger.Critical(const aMsg: string; aParams: array of const);
 begin
 

+ 5 - 14
Quick.MemoryCache.pas

@@ -1,13 +1,13 @@
 { ***************************************************************************
 
-  Copyright (c) 2016-2019 Kike Pérez
+  Copyright (c) 2016-2021 Kike Pérez
 
   Unit        : Quick.MemoryCache
   Description : Cache objects with expiration control
   Author      : Kike Pérez
   Version     : 1.0
   Created     : 14/07/2019
-  Modified    : 02/11/2019
+  Modified    : 17/05/2021
 
   This file is part of QuickLib: https://github.com/exilon/QuickLib
 
@@ -479,15 +479,8 @@ begin
 end;
 
 function TMemoryCache<T>.GetValue(const aKey: string): T;
-var
-  cacheitem : ICacheEntry;
 begin
-  fLock.BeginRead;
-  try
-    fItems.TryGetValue(aKey,cacheitem);
-  finally
-    fLock.EndRead;
-  end;
+  TryGetValue(aKey,Result);
 end;
 
 procedure TMemoryCache<T>.RemoveValue(const aKey: string);
@@ -595,10 +588,8 @@ end;
 { TMemoryCache }
 
 function TMemoryCache.GetValue(const aKey: string): string;
-var
-  cacheitem : ICacheEntry;
 begin
-  if fItems.TryGetValue(aKey,cacheitem) then Result := cacheitem.Data;
+  TryGetValue(aKey,Result);
 end;
 
 procedure TMemoryCache.SetValue(const aKey, aValue: string; aExpirationMilliseconds: Integer);
@@ -701,7 +692,7 @@ begin
   try
     Result := fItems.TryGetValue(aKey,cacheitem);
     //check if cacheitem already expired
-    if Result and  cacheitem.IsExpired then Exit(False);
+    if Result and cacheitem.IsExpired then Exit(False);
   finally
     fLock.EndRead;
   end;

+ 83 - 1
Quick.Network.pas

@@ -36,7 +36,23 @@ interface
 uses
   Classes,
   SysUtils,
-  Math;
+  Math,
+  IdDNSResolver;
+
+type
+  TDNSResolve = class
+  private
+    fHost : string;
+    fPort : Integer;
+    function ResolveDNS(const aDNS : string; aRegType: TQueryRecordTypes): string;
+  public
+    constructor Create(const aNameServer : string = '8.8.8.8'; aServerPort : Integer = 53);
+    function ResolveA(const aDNS : string): string;
+    function ResolveAAAA(const aDNS : string): string;
+    function ResolveCNAME(const aDNS : string): string;
+    function ResolveNS(const aDNS : string): string;
+    function ResolveTXT(const aDNS : string): string;
+  end;
 
   function IntToIPv4(IPv4: LongWord): string;
   function IPv4ToInt(const IPv4: string) : LongWord;
@@ -130,4 +146,70 @@ begin
   end;
 end;
 
+{ TDNSResolve }
+
+constructor TDNSResolve.Create(const aNameServer : string = '8.8.8.8'; aServerPort : Integer = 53);
+begin
+  fHost := aNameServer;
+  fPort := aServerPort;
+end;
+
+function TDNSResolve.ResolveDNS(const aDNS : string; aRegType: TQueryRecordTypes): string;
+var
+  dnsresolver : TIdDNSResolver;
+begin
+  Result := '';
+  dnsresolver := TIdDNSResolver.Create(nil);
+  try
+    dnsresolver.Host := fHost;
+    dnsresolver.Port := fPort;
+    dnsresolver.QueryResult.Clear;
+    dnsresolver.QueryType := [aRegType];
+    dnsresolver.Resolve(aDNS);
+    if dnsresolver.QueryResult.Count > 0 then
+    begin
+      if dnsresolver.QueryResult[0].RecType = aRegType then
+      begin
+        case aRegType of
+          qtNS : Result := TNSRecord(dnsresolver.QueryResult.Items[0]).HostName;
+          qtA : Result := TARecord(dnsresolver.QueryResult.Items[0]).IPAddress;
+          qtAAAA : Result := TAAAARecord(dnsresolver.QueryResult.Items[0]).Address;
+          qtNAME : Result := TCNRecord(dnsresolver.QueryResult.Items[0]).HostName;
+          qtTXT : Result := TTextRecord(dnsresolver.QueryResult.Items[0]).Text.Text;
+          else raise Exception.Create('Not implemented yet!');
+        end;
+
+      end;
+    end;
+  finally
+    dnsresolver.Free;
+  end;
+end;
+
+function TDNSResolve.ResolveNS(const aDNS : string): string;
+begin
+  Result := ResolveDNS(aDNS,qtNS);
+end;
+
+function TDNSResolve.ResolveA(const aDNS : string): string;
+begin
+  Result := ResolveDNS(aDNS,qtA);
+end;
+
+function TDNSResolve.ResolveAAAA(const aDNS : string): string;
+begin
+  Result := ResolveDNS(aDNS,qtAAAA);
+end;
+
+
+function TDNSResolve.ResolveCNAME(const aDNS : string): string;
+begin
+  Result := ResolveDNS(aDNS,qtName);
+end;
+
+function TDNSResolve.ResolveTXT(const aDNS : string): string;
+begin
+  Result := ResolveDNS(aDNS,qtTXT);
+end;
+
 end.

+ 33 - 22
Quick.Options.Serializer.Json.pas

@@ -1,13 +1,13 @@
 { ***************************************************************************
 
-  Copyright (c) 2015-2020 Kike Pérez
+  Copyright (c) 2015-2021 Kike Pérez
 
   Unit        : Quick.Options.Serializer.Json
   Description : Configuration groups Json Serializer
   Author      : Kike Pérez
   Version     : 1.0
   Created     : 18/10/2019
-  Modified    : 15/04/2020
+  Modified    : 15/12/2021
 
   This file is part of QuickLib: https://github.com/exilon/QuickLib
 
@@ -45,25 +45,32 @@ uses
 
 type
 
-  TJsonOptionsSerializer = class(TOptionsSerializer)
+  TJsonOptionsSerializer = class(TOptionsFileSerializer)
   private
     fSerializer : TRTTIJson;
-    function ParseFile(const aFilename : string; out aJsonObj : TJsonObject) : Boolean;
+    function ParseFile(out aJsonObj : TJsonObject) : Boolean;
   public
-    constructor Create;
+    constructor Create(const aFilename : string);
     destructor Destroy; override;
-    function Load(const aFilename : string; aSections : TSectionList; aFailOnSectionNotExists : Boolean) : Boolean; override;
-    function LoadSection(const aFilename : string; aSections : TSectionList; aOptions: TOptions) : Boolean; override;
-    procedure Save(const aFilename : string; aSections : TSectionList); override;
-    function GetFileSectionNames(const aFilename : string; out oSections : TArray<string>) : Boolean; override;
+    function Load(aSections : TSectionList; aFailOnSectionNotExists : Boolean) : Boolean; override;
+    function LoadSection(aSections : TSectionList; aOptions: TOptions) : Boolean; override;
+    procedure Save(aSections : TSectionList); override;
+    function GetFileSectionNames(out oSections : TArray<string>) : Boolean; override;
+    function ConfigExists : Boolean; override;
   end;
 
 implementation
 
 { TJsonOptionsSerializer }
 
-constructor TJsonOptionsSerializer.Create;
+function TJsonOptionsSerializer.ConfigExists: Boolean;
 begin
+  Result := FileExists(Filename);
+end;
+
+constructor TJsonOptionsSerializer.Create(const aFilename : string);
+begin
+  Filename := aFilename;
   fSerializer := TRTTIJson.Create(TSerializeLevel.slPublishedProperty,True);
 end;
 
@@ -73,14 +80,14 @@ begin
   inherited;
 end;
 
-function TJsonOptionsSerializer.GetFileSectionNames(const aFilename: string; out oSections: TArray<string>): Boolean;
+function TJsonOptionsSerializer.GetFileSectionNames(out oSections: TArray<string>): Boolean;
 var
   json : TJsonObject;
   i : Integer;
 begin
   Result := False;
   json := nil;
-  if ParseFile(aFilename,json) then
+  if ParseFile(json) then
   begin
     try
       for i := 0 to json.Count - 1 do
@@ -94,21 +101,25 @@ begin
   end;
 end;
 
-function TJsonOptionsSerializer.ParseFile(const aFilename : string; out aJsonObj : TJsonObject) : Boolean;
+function TJsonOptionsSerializer.ParseFile(out aJsonObj : TJsonObject) : Boolean;
 var
   fileoptions : string;
 begin
   aJsonObj := nil;
-  if FileExists(aFilename) then
+  if FileExists(Filename) then
   begin
-    fileoptions := TFile.ReadAllText(aFilename,TEncoding.UTF8);
+    {$IFDEF DELPHIRX102_UP}
+    fileoptions := TFile.ReadAllText(Filename,TEncoding.UTF8);
+    {$ELSE}
+    fileoptions := TFile.ReadAllText(fFilename);
+    {$ENDIF}
     aJsonObj := TJsonObject.ParseJSONValue(fileoptions) as TJsonObject;
-    if aJsonObj = nil then raise EOptionLoadError.CreateFmt('Config file "%s" is damaged or not well-formed Json format!',[ExtractFileName(aFilename)]);
+    if aJsonObj = nil then raise EOptionLoadError.CreateFmt('Config file "%s" is damaged or not well-formed Json format!',[ExtractFileName(Filename)]);
   end;
   Result := aJsonObj <> nil;
 end;
 
-function TJsonOptionsSerializer.Load(const aFilename : string; aSections : TSectionList; aFailOnSectionNotExists : Boolean) : Boolean;
+function TJsonOptionsSerializer.Load(aSections : TSectionList; aFailOnSectionNotExists : Boolean) : Boolean;
 var
   option : TOptions;
   json : TJsonObject;
@@ -116,7 +127,7 @@ var
   found : Integer;
 begin
   Result := False;
-  if ParseFile(aFilename,json) then
+  if ParseFile(json) then
   begin
     found := 0;
     try
@@ -150,14 +161,14 @@ begin
   end;
 end;
 
-function TJsonOptionsSerializer.LoadSection(const aFilename : string; aSections : TSectionList; aOptions: TOptions) : Boolean;
+function TJsonOptionsSerializer.LoadSection(aSections : TSectionList; aOptions: TOptions) : Boolean;
 var
   json : TJsonObject;
   jpair : TJSONPair;
 begin
   Result := False;
   //read option file
-  if ParseFile(aFilename,json) then
+  if ParseFile(json) then
   begin
     try
       jpair := fSerializer.GetJsonPairByName(json,aOptions.Name);
@@ -175,7 +186,7 @@ begin
   end;
 end;
 
-procedure TJsonOptionsSerializer.Save(const aFilename : string; aSections : TSectionList);
+procedure TJsonOptionsSerializer.Save(aSections : TSectionList);
 var
   option : TOptions;
   fileoptions : string;
@@ -196,7 +207,7 @@ begin
       end;
     end;
     fileoptions := TJsonUtils.JsonFormat(json.ToJSON);
-    if not fileoptions.IsEmpty then TFile.WriteAllText(aFilename,fileoptions);
+    if not fileoptions.IsEmpty then TFile.WriteAllText(Filename,fileoptions);
   finally
     json.Free;
   end;

+ 30 - 21
Quick.Options.Serializer.Yaml.pas

@@ -7,7 +7,7 @@
   Author      : Kike Pérez
   Version     : 1.0
   Created     : 18/10/2019
-  Modified    : 05/04/2020
+  Modified    : 15/12/2021
 
   This file is part of QuickLib: https://github.com/exilon/QuickLib
 
@@ -44,25 +44,32 @@ uses
 
 type
 
-  TYamlOptionsSerializer = class(TOptionsSerializer)
+  TYamlOptionsSerializer = class(TOptionsFileSerializer)
   private
     fSerializer : TRTTIYaml;
-    function ParseFile(const aFilename : string; out aYamlObj : TYamlObject) : Boolean;
+    function ParseFile(out aYamlObj : TYamlObject) : Boolean;
   public
-    constructor Create;
+    constructor Create(const aFilename : string);
     destructor Destroy; override;
-    function Load(const aFilename : string; aSections : TSectionList; aFailOnSectionNotExists : Boolean) : Boolean; override;
-    function LoadSection(const aFilename : string; aSections : TSectionList; aOptions: TOptions) : Boolean; override;
-    procedure Save(const aFilename : string; aSections : TSectionList); override;
-    function GetFileSectionNames(const aFilename : string; out oSections : TArray<string>) : Boolean; override;
+    function Load(aSections : TSectionList; aFailOnSectionNotExists : Boolean) : Boolean; override;
+    function LoadSection(aSections : TSectionList; aOptions: TOptions) : Boolean; override;
+    procedure Save(aSections : TSectionList); override;
+    function GetFileSectionNames(out oSections : TArray<string>) : Boolean; override;
+    function ConfigExists : Boolean; override;
   end;
 
 implementation
 
 { TYamlOptionsSerializer }
 
-constructor TYamlOptionsSerializer.Create;
+function TYamlOptionsSerializer.ConfigExists: Boolean;
 begin
+  Result := FileExists(Filename);
+end;
+
+constructor TYamlOptionsSerializer.Create(const aFilename : string);
+begin
+  Filename := aFilename;
   fSerializer := TRTTIYaml.Create(TSerializeLevel.slPublishedProperty,True);
 end;
 
@@ -72,14 +79,14 @@ begin
   inherited;
 end;
 
-function TYamlOptionsSerializer.GetFileSectionNames(const aFilename : string; out oSections : TArray<string>) : Boolean;
+function TYamlOptionsSerializer.GetFileSectionNames(out oSections : TArray<string>) : Boolean;
 var
   yaml : TYamlObject;
   i : Integer;
 begin
   Result := False;
   yaml := nil;
-  if ParseFile(aFilename,yaml) then
+  if ParseFile(yaml) then
   begin
     try
       for i := 0 to yaml.Count - 1 do
@@ -93,21 +100,23 @@ begin
   end;
 end;
 
-function TYamlOptionsSerializer.ParseFile(const aFilename : string; out aYamlObj : TYamlObject) : Boolean;
+function TYamlOptionsSerializer.ParseFile(out aYamlObj : TYamlObject) : Boolean;
 var
   fileoptions : string;
 begin
   aYamlObj := nil;
-  if FileExists(aFilename) then
+  if FileExists(Filename) then
   begin
-    fileoptions := TFile.ReadAllText(aFilename,TEncoding.UTF8);
+    fileoptions := TFile.ReadAllText(Filename,TEncoding.UTF8);
+    if fileoptions.IsEmpty then EOptionLoadError.CreateFmt('Config file "%s" is empty!',[ExtractFileName(Filename)]);
+
     aYamlObj := TYamlObject.ParseYAMLValue(fileoptions) as TYamlObject;
-    if aYamlObj = nil then raise EOptionLoadError.CreateFmt('Config file "%s" is damaged or not well-formed Yaml format!',[ExtractFileName(aFilename)]);
+    if aYamlObj = nil then raise EOptionLoadError.CreateFmt('Config file "%s" is damaged or not well-formed Yaml format!',[ExtractFileName(Filename)]);
   end;
   Result := aYamlObj <> nil;
 end;
 
-function TYamlOptionsSerializer.Load(const aFilename : string; aSections : TSectionList; aFailOnSectionNotExists : Boolean) : Boolean;
+function TYamlOptionsSerializer.Load(aSections : TSectionList; aFailOnSectionNotExists : Boolean) : Boolean;
 var
   option : TOptions;
   yaml : TYamlObject;
@@ -116,7 +125,7 @@ var
 begin
   Result := False;
   //read option file
-  if ParseFile(aFilename,yaml) then
+  if ParseFile(yaml) then
   begin
     found := 0;
     try
@@ -150,14 +159,14 @@ begin
   end;
 end;
 
-function TYamlOptionsSerializer.LoadSection(const aFilename : string; aSections : TSectionList; aOptions: TOptions) : Boolean;
+function TYamlOptionsSerializer.LoadSection(aSections : TSectionList; aOptions: TOptions) : Boolean;
 var
   yaml : TYamlObject;
   ypair : TYamlPair;
 begin
   Result := False;
   //read option file
-  if ParseFile(aFilename,yaml) then
+  if ParseFile(yaml) then
   begin
     try
       ypair := fSerializer.GetYamlPairByName(yaml,aOptions.Name);
@@ -175,7 +184,7 @@ begin
   end;
 end;
 
-procedure TYamlOptionsSerializer.Save(const aFilename : string; aSections : TSectionList);
+procedure TYamlOptionsSerializer.Save(aSections : TSectionList);
 var
   option : TOptions;
   fileoptions : string;
@@ -196,7 +205,7 @@ begin
       end;
     end;
     fileoptions := yaml.ToYaml;
-    if not fileoptions.IsEmpty then TFile.WriteAllText(aFilename,fileoptions);
+    if not fileoptions.IsEmpty then TFile.WriteAllText(Filename,fileoptions);
   finally
     yaml.Free;
   end;

+ 159 - 83
Quick.Options.pas

@@ -1,13 +1,13 @@
 { ***************************************************************************
 
-  Copyright (c) 2015-2020 Kike Pérez
+  Copyright (c) 2015-2021 Kike Pérez
 
   Unit        : Quick.Options
   Description : Configuration group settings
   Author      : Kike Pérez
   Version     : 1.0
   Created     : 18/10/2019
-  Modified    : 27/02/2020
+  Modified    : 15/12/2021
 
   This file is part of QuickLib: https://github.com/exilon/QuickLib
 
@@ -72,15 +72,26 @@ type
     property MaxLength : Integer read fMaxLength write fMaxLength;
   end;
 
+  TOptionsBase = class(TInterfacedObject)
+
+  end;
+
+  {$IFDEF DELPHIRX102_UP}
+  {$M+}
   TOptions = class;
+  {$M-}
 
   TConfigureOptionsProc<T : TOptions> = reference to procedure(aOptions : T);
+  {$ELSE}
+  TConfigureOptionsProc<T> = reference to procedure(aOptions : T);
+  {$ENDIF}
 
   IOptionsValidator = interface
   ['{C6A09F78-8E34-4689-B943-83620437B9EF}']
     procedure ValidateOptions;
   end;
 
+  {$M+}
   TOptions = class(TInterfacedObject,IOptionsValidator)
   private
     fName : string;
@@ -91,9 +102,14 @@ type
     property Name : string read fName write fName;
     property HideOptions : Boolean read fHideOptions write fHideOptions;
     procedure DefaultValues; virtual;
+    {$IFDEF DELPHIRX102_UP}
     function ConfigureOptions<T : TOptions>(aOptionsFunc : TConfigureOptionsProc<T>) : IOptionsValidator;
+    {$ELSE}
+    function ConfigureOptions<T>(aOptionsFunc : TConfigureOptionsProc<T>) : IOptionsValidator;
+    {$ENDIF}
     procedure ValidateOptions;
   end;
+  {$M-}
 
   TOptionsValidator = class(TInterfacedObject,IOptionsValidator)
   private
@@ -137,18 +153,36 @@ type
 
   IOptionsSerializer = interface
   ['{7DECE203-4AAE-4C9D-86C8-B3D583DF7C8B}']
-    function Load(const aFilename : string; aSections : TSectionList; aFailOnSectionNotExists : Boolean) : Boolean;
-    function LoadSection(const aFilename : string; aSections : TSectionList; aOptions: TOptions) : Boolean;
-    procedure Save(const aFilename : string; aSections : TSectionList);
-    function GetFileSectionNames(const aFilename : string; out oSections : TArray<string>) : Boolean;
+    function Load(aSections : TSectionList; aFailOnSectionNotExists : Boolean) : Boolean;
+    function LoadSection(aSections : TSectionList; aOptions: TOptions) : Boolean;
+    procedure Save(aSections : TSectionList);
+    function GetFileSectionNames(out oSections : TArray<string>) : Boolean;
+    function ConfigExists : Boolean;
+  end;
+
+  IFileOptionsSerializer = interface(IOptionsSerializer)
+  ['{3417B142-2879-4DA6-86CA-19F0F427A92C}']
+    function GetFileName : string;
+    procedure SetFileName(const aFilename : string);
+    property Filename : string read GetFilename write SetFilename;
   end;
 
   TOptionsSerializer = class(TInterfacedObject,IOptionsSerializer)
   public
-    function Load(const aFilename : string; aSections : TSectionList; aFailOnSectionNotExists : Boolean) : Boolean; virtual; abstract;
-    function LoadSection(const aFilename : string; aSections : TSectionList; aOptions: TOptions) : Boolean; virtual; abstract;
-    procedure Save(const aFilename : string; aSections : TSectionList); virtual; abstract;
-    function GetFileSectionNames(const aFilename : string; out oSections : TArray<string>) : Boolean; virtual; abstract;
+    function Load(aSections : TSectionList; aFailOnSectionNotExists : Boolean) : Boolean; virtual; abstract;
+    function LoadSection(aSections : TSectionList; aOptions: TOptions) : Boolean; virtual; abstract;
+    procedure Save(aSections : TSectionList); virtual; abstract;
+    function GetFileSectionNames(out oSections : TArray<string>) : Boolean; virtual; abstract;
+    function ConfigExists : Boolean; virtual; abstract;
+  end;
+
+  TOptionsFileSerializer = class(TOptionsSerializer,IFileOptionsSerializer)
+  private
+    fFilename : string;
+    function GetFileName : string;
+    procedure SetFileName(const aFilename : string);
+  public
+    property Filename : string read GetFilename write SetFilename;
   end;
 
   TFileModifiedEvent = reference to procedure;
@@ -165,34 +199,24 @@ type
 
   TOptionsContainer = class(TInterfacedObject,IOptionsContainer)
   private
-    fFilename : string;
     fSerializer : IOptionsSerializer;
     fSections : TSectionList;
-    fFileMonitor : TFileMonitor;
-    fOnFileModified : TFileModifiedEvent;
     fLoaded : Boolean;
-    fReloadIfFileChanged : Boolean;
     fOnConfigLoaded : TLoadConfigEvent;
     fOnConfigReloaded : TLoadConfigEvent;
-    procedure CreateFileMonitor;
-    procedure FileModifiedNotify(MonitorNotify : TMonitorNotify);
-    procedure SetReloadIfFileChanged(const Value: Boolean);
     function GetOptions(aOptionClass : TOptionsClass): TOptions; overload;
     function GetOptions(aIndex : Integer) : TOptions; overload;
     function GetSection(aOptionsSection : TOptionsClass; var vOptions : TOptions) : Boolean; overload;
   public
-    constructor Create(const aFilename : string; aOptionsSerializer : IOptionsSerializer; aReloadIfFileChanged : Boolean = False);
+    constructor Create(aOptionsSerializer : IOptionsSerializer);
     destructor Destroy; override;
-    property FileName : string read fFilename write fFilename;
-    property ReloadIfFileChanged : Boolean read fReloadIfFileChanged write SetReloadIfFileChanged;
     property IsLoaded : Boolean read fLoaded;
     function ExistsSection(aOption : TOptionsClass; const aSectionName : string = '') : Boolean; overload;
     function ExistsSection<T : TOptions>(const aSectionName : string = '') : Boolean; overload;
-    property OnFileModified : TFileModifiedEvent read fOnFileModified write fOnFileModified;
-    property OnConfigLoaded : TLoadConfigEvent read fOnConfigLoaded write fOnConfigLoaded;
-    property OnConfigReloaded : TLoadConfigEvent read fOnConfigReloaded write fOnConfigReloaded;
     property Items[aOptionClass : TOptionsClass] : TOptions read GetOptions; default;
     property Items[aIndex : Integer] : TOptions read GetOptions; default;
+    property OnConfigLoaded : TLoadConfigEvent read fOnConfigLoaded write fOnConfigLoaded;
+    property OnConfigReloaded : TLoadConfigEvent read fOnConfigReloaded write fOnConfigReloaded;
     function AddSection(aOption : TOptionsClass; const aSectionName : string = '') : TOptions; overload;
     function AddSection<T : TOptions>(const aSectionName : string = '') : TOptions<T>; overload;
     procedure AddOption(aOption : TOptions);
@@ -200,9 +224,28 @@ type
     function GetSection<T : TOptions>(const aSectionName : string = '') : T; overload;
     function GetFileSectionNames(out oSections : TArray<string>) : Boolean;
     function Count : Integer;
-    procedure Load(aFailOnSectionNotExists : Boolean = False);
+    procedure Load(aFailOnSectionNotExists : Boolean = False); virtual;
     procedure LoadSection(aOptions : TOptions);
-    procedure Save;
+    procedure Save; virtual;
+  end;
+
+  TFileOptionsContainer = class(TOptionsContainer)
+  private
+    fFilename : string;
+    fFileMonitor : TFileMonitor;
+    fOnFileModified : TFileModifiedEvent;
+    fReloadIfFileChanged : Boolean;
+    procedure CreateFileMonitor;
+    procedure FileModifiedNotify(MonitorNotify : TMonitorNotify);
+    procedure SetReloadIfFileChanged(const Value: Boolean);
+  public
+    constructor Create(aOptionsSerializer : IFileOptionsSerializer; aReloadIfFileChanged : Boolean = False);
+    destructor Destroy; override;
+    property FileName : string read fFilename;
+    property ReloadIfFileChanged : Boolean read fReloadIfFileChanged write SetReloadIfFileChanged;
+    property OnFileModified : TFileModifiedEvent read fOnFileModified write fOnFileModified;
+    procedure Save; override;
+    function GetFileSectionNames(out oSections: TArray<string>): Boolean;
   end;
 
   IOptionsBuilder<T : TOptions> = interface
@@ -225,41 +268,7 @@ type
 
 implementation
 
-{ TOptionsContainer }
-
-constructor TOptionsContainer.Create(const aFilename : string; aOptionsSerializer : IOptionsSerializer; aReloadIfFileChanged : Boolean = False);
-begin
-  fSerializer := aOptionsSerializer;
-  fSections := TSectionList.Create(False);
-  fFilename := aFilename;
-  fLoaded := False;
-  fReloadIfFileChanged := aReloadIfFileChanged;
-  if aReloadIfFileChanged then CreateFileMonitor;
-end;
-
-procedure TOptionsContainer.CreateFileMonitor;
-begin
-  fFileMonitor := TQuickFileMonitor.Create;
-  fFileMonitor.FileName := fFilename;
-  fFileMonitor.Interval := 2000;
-  fFileMonitor.Notifies := [TMonitorNotify.mnFileModified];
-  fFileMonitor.OnFileChange := FileModifiedNotify;
-  fFileMonitor.Enabled := True;
-end;
-
-destructor TOptionsContainer.Destroy;
-var
-  option : TOptions;
-begin
-  if Assigned(fFileMonitor) then fFileMonitor.Free;
-  fSerializer := nil;
-  for option in fSections do
-  begin
-    if option.RefCount = 0 then option.Free;
-  end;
-  fSections.Free;
-  inherited;
-end;
+{ TCustomOptionsContainer}
 
 function TOptionsContainer.ExistsSection(aOption: TOptionsClass;const aSectionName: string): Boolean;
 var
@@ -280,18 +289,6 @@ begin
   Result := GetSection<T>(aSectionName) <> nil;
 end;
 
-procedure TOptionsContainer.FileModifiedNotify(MonitorNotify: TMonitorNotify);
-begin
-  if MonitorNotify = TMonitorNotify.mnFileModified then
-  begin
-    if Assigned(fOnFileModified) then fOnFileModified;
-    if fReloadIfFileChanged then
-    begin
-      Load(False);
-    end;
-  end;
-end;
-
 procedure TOptionsContainer.AddOption(aOption: TOptions);
 begin
   if aOption.Name.IsEmpty then aOption.Name := Copy(aOption.ClassName,2,aOption.ClassName.Length);
@@ -332,9 +329,29 @@ begin
   Result := fSections.Count;
 end;
 
-function TOptionsContainer.GetFileSectionNames(out oSections : TArray<string>) : Boolean;
+constructor TOptionsContainer.Create(aOptionsSerializer: IOptionsSerializer);
+begin
+  fSerializer := aOptionsSerializer;
+  fSections := TSectionList.Create(False);
+  fLoaded := False;
+end;
+
+destructor TOptionsContainer.Destroy;
+var
+  option : TOptions;
+begin
+  fSerializer := nil;
+  for option in fSections do
+  begin
+    if option.RefCount = 0 then option.Free;
+  end;
+  fSections.Free;
+  inherited;
+end;
+
+function TOptionsContainer.GetFileSectionNames(out oSections: TArray<string>): Boolean;
 begin
-  Result := fSerializer.GetFileSectionNames(fFilename,oSections);
+  Result := fSerializer.GetFileSectionNames(oSections);
 end;
 
 function TOptionsContainer.GetOptions(aIndex: Integer): TOptions;
@@ -395,9 +412,9 @@ procedure TOptionsContainer.Load(aFailOnSectionNotExists : Boolean = False);
 var
   option : TOptions;
 begin
-  if FileExists(fFilename) then
+  if fSerializer.ConfigExists then
   begin
-    if not fSerializer.Load(fFilename,fSections,aFailOnSectionNotExists) then Save;
+    if not fSerializer.Load(fSections,aFailOnSectionNotExists) then Save;
     if not fLoaded then
     begin
       fLoaded := True;
@@ -407,22 +424,36 @@ begin
   end
   else
   begin
-    //if not exists file get default values
+    //if config not exists get default values
     for option in fSections do option.DefaultValues;
-    //creates default file
+    //saves default
     Save;
   end;
 end;
 
 procedure TOptionsContainer.LoadSection(aOptions : TOptions);
 begin
-  if FileExists(fFilename) then
+  if fSerializer.ConfigExists then
   begin
-    if not fSerializer.LoadSection(fFilename,fSections,aOptions) then Save;
+    if not fSerializer.LoadSection(fSections,aOptions) then Save;
   end;
 end;
 
 procedure TOptionsContainer.Save;
+begin
+  fSerializer.Save(fSections);
+end;
+
+{ TOptionsContainer }
+
+constructor TFileOptionsContainer.Create(aOptionsSerializer : IFileOptionsSerializer; aReloadIfFileChanged : Boolean = False);
+begin
+  inherited Create(aOptionsSerializer);
+  fFilename := aOptionsSerializer.Filename;
+  if aReloadIfFileChanged then CreateFileMonitor;
+end;
+
+procedure TFileOptionsContainer.Save;
 var
   laststate : Boolean;
 begin
@@ -433,17 +464,17 @@ begin
     fFileMonitor.Enabled := False;
     try
       //save config file
-      fSerializer.Save(fFilename,fSections);
+      inherited;
     finally
       //set last state
       Sleep(0);
       fFileMonitor.Enabled := laststate;
     end;
   end
-  else fSerializer.Save(fFilename,fSections);
+  else inherited;
 end;
 
-procedure TOptionsContainer.SetReloadIfFileChanged(const Value: Boolean);
+procedure TFileOptionsContainer.SetReloadIfFileChanged(const Value: Boolean);
 begin
   if Value = fReloadIfFileChanged then Exit;
   fReloadIfFileChanged := Value;
@@ -451,6 +482,39 @@ begin
   if fReloadIfFileChanged then CreateFileMonitor;
 end;
 
+procedure TFileOptionsContainer.CreateFileMonitor;
+begin
+  fFileMonitor := TQuickFileMonitor.Create;
+  fFileMonitor.FileName := fFilename;
+  fFileMonitor.Interval := 2000;
+  fFileMonitor.Notifies := [TMonitorNotify.mnFileModified];
+  fFileMonitor.OnFileChange := FileModifiedNotify;
+  fFileMonitor.Enabled := True;
+end;
+
+destructor TFileOptionsContainer.Destroy;
+begin
+  if Assigned(fFileMonitor) then fFileMonitor.Free;
+  inherited;
+end;
+
+procedure TFileOptionsContainer.FileModifiedNotify(MonitorNotify: TMonitorNotify);
+begin
+  if MonitorNotify = TMonitorNotify.mnFileModified then
+  begin
+    if Assigned(fOnFileModified) then fOnFileModified;
+    if fReloadIfFileChanged then
+    begin
+      Load(False);
+    end;
+  end;
+end;
+
+function TFileOptionsContainer.GetFileSectionNames(out oSections : TArray<string>) : Boolean;
+begin
+  Result := fSerializer.GetFileSectionNames(oSections);
+end;
+
 { TOptions }
 
 function TOptions.ConfigureOptions<T>(aOptionsFunc: TConfigureOptionsProc<T>): IOptionsValidator;
@@ -675,4 +739,16 @@ begin
   Result := fOptions;
 end;
 
+{ TOptionsFileSerializer }
+
+function TOptionsFileSerializer.GetFileName: string;
+begin
+  Result := fFilename;
+end;
+
+procedure TOptionsFileSerializer.SetFileName(const aFilename: string);
+begin
+  fFilename := aFilename;
+end;
+
 end.

+ 33 - 8
Quick.Parameters.pas

@@ -1,13 +1,13 @@
 { ***************************************************************************
 
-  Copyright (c) 2016-2020 Kike Pérez
+  Copyright (c) 2016-2021 Kike Pérez
 
   Unit        : Quick.Parameters
   Description : Map comandline to class
   Author      : Kike Pérez
   Version     : 1.4
   Created     : 12/07/2020
-  Modified    : 29/07/2020
+  Modified    : 01/08/2021
 
   This file is part of QuickLib: https://github.com/exilon/QuickLib
 
@@ -123,6 +123,7 @@ type
   end;
   {$ENDIF}
 
+  {$M+}
   TParameters = class
   type
     TValueType = (vtString, vtInteger, vtFloat, vtBoolean, vtEnumeration);
@@ -156,6 +157,7 @@ type
       property IsPresent : Boolean read fIsPresent write fIsPresent;
       function IsSwitch : Boolean;
       function IsCommand : Boolean;
+      function ValueIsSwitch : Boolean;
     end;
   private
     fParams : TObjectList<TParam>;
@@ -164,7 +166,7 @@ type
     {$IFDEF CONSOLE}
     fColorizeHelp: TColorizeHelp;
     {$ENDIF}
-    function ExistParam(aParameter : TParam; const aParam : string) : Boolean;
+    function ExistParam(aParameter : TParam; const aParam : string) : Boolean; overload;
     function GetParamName(aParameter : TParam; const aParam : string) : string;
     function GetParamValue(aParameter : TParam; const aParam : string) : string;
     function ValueType(const aProp : TRttiProperty) : TValueType;
@@ -176,7 +178,7 @@ type
   {$ENDIF}
     procedure Validate; virtual;
   public
-    constructor Create; virtual;
+    constructor Create(aAutoHelp : Boolean = True); virtual;
     destructor Destroy; override;
     property Description : string read fDescription write fDescription;
     {$IFDEF CONSOLE}
@@ -185,7 +187,9 @@ type
     {$ENDIF}
     function GetHelp : TStringList;
     property Help : Boolean read fHelp write fHelp;
+    function ExistsParam(const aParam : string): Boolean; overload;
   end;
+  {$M-}
 
   TServiceParameters = class(TParameters)
   private
@@ -216,7 +220,7 @@ implementation
 
 { TParameter }
 
-constructor TParameters.Create;
+constructor TParameters.Create(aAutoHelp : Boolean = True);
 begin
   {$IFDEF CONSOLE}
   fColorizeHelp := TColorizeHelp.Create;
@@ -225,7 +229,7 @@ begin
   fParams := TObjectList<TParam>.Create(True);
   ParseParams;
   {$IFDEF CONSOLE}
-  if fHelp then
+  if (aAutoHelp) and (fHelp) then
   begin
     ShowHelp;
     Halt;
@@ -238,7 +242,8 @@ destructor TParameters.Destroy;
 begin
   fParams.Free;
   {$IFDEF CONSOLE}
-  fColorizeHelp.Free;
+  if Assigned(fColorizeHelp) then fColorizeHelp.Free;
+  fColorizeHelp := nil;
   {$ENDIF}
   inherited;
 end;
@@ -310,6 +315,20 @@ begin
   end;
 end;
 
+function TParameters.ExistsParam(const aParam : string): Boolean;
+var
+  param : TParam;
+begin
+  param := TParam.Create;
+  param.Name := aParam;
+  param.Alias := '';
+  try
+    Result := ExistParam(param,param.Name);
+  finally
+    param.Free;
+  end;
+end;
+
 procedure TParameters.ParseParams;
 var
   param : TParam;
@@ -360,10 +379,11 @@ begin
     begin
       found := ParamCount >= param.PrecisePosition;
       param.SwitchChar := '  ';
+      if param.ValueIsSwitch then found := False;
     end
     else found := (ExistParam(param,param.Name)) or (ExistParam(param,param.Alias));
     value := nil;
-    if found then    
+    if found then
     begin
       if param.IsSwitch then
       begin
@@ -681,6 +701,11 @@ begin
   Result := fParamType = TValueType.vtBoolean;
 end;
 
+function TParameters.TParam.ValueIsSwitch: Boolean;
+begin
+  Result := (fValue.StartsWith('/')) or (fValue.StartsWith('-')) or (fValue.StartsWith(fSwitchChar));
+end;
+
 { ParamSwitchChar }
 
 constructor ParamSwitchChar.Create(const aSwitchChar: string);

+ 26 - 5
Quick.Pooling.pas

@@ -34,6 +34,9 @@ unit Quick.Pooling;
 interface
 
 uses
+  {$IFDEF DEBUG_OBJPOOL}
+  Quick.Debug.Utils,
+  {$ENDIF}
   System.SysUtils,
   System.SyncObjs,
   System.DateUtils,
@@ -116,6 +119,7 @@ implementation
 
 function TObjectPool<T>.AutoFreeIdleItemTimeMs(aIdleTimeMs: Integer): IObjectPool<T>;
 begin
+  Result := Self;
   fAutoFreeIdleItemTimeMs := aIdleTimeMs;
 end;
 
@@ -162,6 +166,7 @@ end;
 
 function TObjectPool<T>.CreateDelegate(aCreateProc: TCreateDelegator<T>): IObjectPool<T>;
 begin
+  Result := Self;
   fDelegate := aCreateProc;
 end;
 
@@ -189,6 +194,9 @@ var
   waitResult: TWaitResult;
 begin
   Result := nil;
+  {$IFDEF DEBUG_OBJPOOL}
+  TDebugger.Trace(Self,'Waiting for get idle Pool Item...');
+  {$ENDIF}
   waitResult := fSemaphore.WaitFor(fWaitTimeoutMs);
   if waitResult <> TWaitResult.wrSignaled then raise Exception.Create('Connection Pool Timeout: Cannot obtain a connection');
   fLock.Enter;
@@ -199,14 +207,23 @@ begin
       if fPool[i] = nil then
       begin
         fPool[i] := TPoolItem<T>.Create(fSemaphore,fLock,i,fDelegate);
-        //writeln('create ' + i.ToString);
+        {$IFDEF DEBUG_OBJPOOL}
+        TDebugger.Trace(Self,'Create Pool Item: %d',[i]);
+        {$ENDIF}
         Exit(fPool[i]);
       end;
       if fPool[i].RefCount = 1 then
       begin
         //writeln('get ' + i.ToString);
+        {$IFDEF DEBUG_OBJPOOL}
+        TDebugger.Trace(Self,'Get Idle Pool Item: %d',[i]);
+        {$ENDIF}
         Exit(fPool[i]);
-      end;
+      end
+      {$IFDEF DEBUG_OBJPOOL}
+      else
+      TDebugger.Trace(Self,'Pool Item: %d is busy (RefCount: %d)',[i,fPool[i].RefCount]);
+      {$ENDIF}
     end;
   finally
     fLock.Leave;
@@ -265,7 +282,9 @@ end;
 function TPoolItem<T>._AddRef: Integer;
 begin
   fLock.Enter;
-  //writeln('enter');
+  {$IFDEF DEBUG_OBJPOOL}
+  TDebugger.Trace(Self,'Got Pool item');
+  {$ENDIF}
   try
     Inc(FRefCount);
     Result := FRefCount;
@@ -277,7 +296,9 @@ end;
 function TPoolItem<T>._Release: Integer;
 begin
   fLock.Enter;
-  //writeln('exit');
+  {$IFDEF DEBUG_OBJPOOL}
+  TDebugger.Trace(Self,'Released Pool item');
+  {$ENDIF}
   try
     Dec(fRefCount);
     Result := fRefCount;
@@ -288,8 +309,8 @@ begin
     end
     else fLastAccess := Now;
   finally
-    fLock.Leave;
     if fRefCount = 1 then fSemaphore.Release;
+    fLock.Leave;
   end;
 end;
 

+ 119 - 9
Quick.Process.pas

@@ -1,13 +1,13 @@
 { ***************************************************************************
 
-  Copyright (c) 2016-2018 Kike Pérez
+  Copyright (c) 2016-2021 Kike Pérez
 
   Unit        : Quick.Process
   Description : Process functions
   Author      : Kike Pérez
   Version     : 1.5
   Created     : 14/07/2017
-  Modified    : 04/07/2018
+  Modified    : 08/07/2021
 
   This file is part of QuickLib: https://github.com/exilon/QuickLib
 
@@ -34,8 +34,10 @@ unit Quick.Process;
 interface
 
 uses
+  {$IFDEF MSWINDOWS}
   Windows,
-  Classes,
+  ShellAPI,
+  Quick.Console,
   {$IFNDEF CONSOLE}
   Controls,
     {$IFNDEF FPC}
@@ -43,24 +45,45 @@ uses
     Winapi.Messages,
     {$ENDIF}
   {$ENDIF}
-  DateUtils,
   {$IFNDEF FPC}
-  TlHelp32,
-  psapi,
+    TlHelp32,
+    psapi,
+    {$ELSE}
+    JwaTlHelp32,
+    Process,
+    {$ENDIF}
   {$ELSE}
-  JwaTlHelp32,
-  Process,
+  Posix.Base,
+  Posix.Fcntl,
   {$ENDIF}
+  Classes,
+  DateUtils,
   SysUtils,
-  ShellAPI,
   Quick.Commons;
 
+  {$IFDEF DELPHILINUX}
+  type
+    TStreamHandle = pointer;
+  function popen(const command: PAnsiChar; const _type: PAnsiChar): TStreamHandle; cdecl; external libc name _PU + 'popen';
+  function pclose(filehandle: TStreamHandle): int32; cdecl; external libc name _PU + 'pclose';
+  function fgets(buffer: pointer; size: int32; Stream: TStreamHAndle): pointer; cdecl; external libc name _PU + 'fgets';
+  {$ENDIF}
+
 
   //stop a running process
+  {$IFDEF MSWINDOWS}
   function KillProcess(const aFileName : string) : Integer; overload;
+  {$ELSE}
+  function KillProcess(const aProcessName : string) : Integer; overload;
+  {$ENDIF}
   function KillProcess(aProcessId : Cardinal) : Boolean; overload;
   //run process as Admin privilegies
+  {$IFDEF MSWINDOWS}
   function RunAsAdmin(hWnd: HWND; const aFilename, aParameters: string): Boolean;
+  //impersonate logon
+  function Impersonate(const aDomain, aUser, aPassword : string): Boolean;
+  //revert logon to real logged user
+  procedure RevertToSelf;
   //remove dead icons from taskbar tray
   procedure RemoveDeadIcons;
   //get a process of running processes
@@ -75,6 +98,10 @@ uses
   //executes an aplication and wait for terminate
   function ExecuteAndWait(const aFilename, aCommandLine: string): Boolean;
   function ShellExecuteAndWait(const aOperation, aFileName, aParameter, aDirectory : string; aShowMode : Word; aWaitForTerminate: Boolean) : LongInt;
+  {$ENDIF}
+  //runs a command and gets console output
+  function RunCommand(const aFilename, aParameters : string) : TStringList;
+  {$IFDEF MSWINDOWS}
   {$IFNDEF FPC}
   //execute an application and return handle
   function ShellExecuteReturnHandle(const aOperation, aFileName, aParameters, aWorkingDir : string; aShowMode: Integer) : THandle;
@@ -89,10 +116,12 @@ uses
   //capture a window handle and show it into a wincontrol
   procedure CaptureWindowIntoControl(aWindowHandle: THandle; aContainer: TWinControl);
   {$ENDIF}
+  {$ENDIF}
 
 
 implementation
 
+{$IFDEF MSWINDOWS}
 const
   DNLEN = 15;
   UNLEN = 256;
@@ -198,7 +227,9 @@ begin
   end;
 end;
 {$ENDIF}
+{$ENDIF}
 
+{$IFDEF MSWINDOWS}
 function KillProcess(const aFileName: string): Integer;
 const
   PROCESS_TERMINATE = $0001;
@@ -226,8 +257,22 @@ begin
   end;
   CloseHandle(FSnapshotHandle);
 end;
+{$ELSE}
+function KillProcess(const aProcessName: string): Integer;
+var
+  sl : TStringList;
+begin
+  sl := RunCommand('pkill',aProcessName);
+  try
+    Result := 1;
+  finally
+    sl.Free;
+  end;
+end;
+{$ENDIF}
 
 function KillProcess(aProcessId : Cardinal) : Boolean;
+{$IFDEF MSWINDOWS}
 var
   hProcess : THandle;
 begin
@@ -240,7 +285,20 @@ begin
     CloseHandle(hProcess);
   end;
 end;
+{$ELSE}
+var
+  sl : TStringList;
+begin
+  sl := RunCommand('kill',aProcessId.ToString);
+  try
+    Result := True;
+  finally
+    sl.Free;
+  end;
+end;
+{$ENDIF}
 
+{$IFDEF MSWINDOWS}
 function RunAsAdmin(hWnd: HWND; const aFilename, aParameters: string): Boolean;
 var
   shinfo: TShellExecuteInfo;
@@ -260,6 +318,22 @@ begin
   {$ENDIF}
 end;
 
+function Impersonate(const aDomain, aUser, aPassword : string): Boolean;
+var
+  htoken : THandle;
+begin
+  Result := False;
+  if LogonUser(PChar(aUser),PChar(aDomain),PChar(aPassword),LOGON32_LOGON_INTERACTIVE,LOGON32_PROVIDER_DEFAULT,htoken) then
+  begin
+    Result := ImpersonateLoggedOnUser(htoken);
+  end;
+end;
+
+procedure RevertToSelf;
+begin
+  Windows.RevertToSelf;
+end;
+
 procedure RemoveDeadIcons;
 var
   TrayWindow : HWnd;
@@ -415,7 +489,42 @@ begin
     SetLastError(dwExitCode);
   end;
 end;
+{$ENDIF}
+
+function RunCommand(const aFilename, aParameters : string) : TStringList;
+{$IFDEF MSWINDOWS}
+begin
+  Result := TStringList.Create;
+  RunConsoleCommand(aFilename,aParameters,nil,Result);
+end;
+{$ELSE}
+var
+  Handle: TStreamHandle;
+  Data: array[0..511] of uint8;
+  command : PAnsiChar;
+begin
+  Result := TStringList.Create;
+  try
+    if aParameters.IsEmpty then command := PAnsiChar(AnsiString(aFilename))
+      else command := PAnsiChar(AnsiString(aFilename + ' ' + aParameters));
+    Handle := popen(command, 'r');
+    try
+      while fgets(@Data[0], Sizeof(Data), Handle) <> nil do Result.Add(Utf8ToString(@Data[0]));
+    finally
+      pclose(Handle);
+    end;
+  except
+    on E: Exception do
+    begin
+      Result.Free;
+      Exception.CreateFmt('RunCommand: %s',[e.Message]);
+    end;
+  end;
+end;
 
+{$ENDIF}
+
+{$IFDEF MSWINDOWS}
 function ShellExecuteAndWait(const aOperation, aFileName, aParameter, aDirectory: string; aShowMode : Word; aWaitForTerminate: Boolean) : LongInt;
 var
   done: Boolean;
@@ -542,5 +651,6 @@ begin
   SetForegroundWindow(aWindowHandle);
 end;
 {$ENDIF}
+{$ENDIF}
 
 end.

+ 680 - 726
Quick.RTTI.Utils.pas

@@ -1,726 +1,680 @@
-{ ***************************************************************************
-
-  Copyright (c) 2016-2020 Kike Pérez
-
-  Unit        : Quick.RTTI.Utils
-  Description : Files functions
-  Author      : Kike Pérez
-  Version     : 1.4
-  Created     : 09/03/2018
-  Modified    : 14/07/2020
-
-  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.RTTI.Utils;
-
-{$i QuickLib.inc}
-
-interface
-
-uses
-  SysUtils,
-  Quick.Commons,
-  TypInfo,
-  Rtti;
-
-type
-
-  TRttiPropertyOrder = (roFirstBase, roFirstInherited);
-
-  TRTTI = class
-  private class var
-    fCtx : TRttiContext;
-  public
-    {$IFNDEF FPC}
-    class constructor Create;
-    class destructor Destroy;
-    class function GetField(aInstance : TObject; const aFieldName : string) : TRttiField; overload;
-    class function GetField(aTypeInfo : Pointer; const aFieldName : string) : TRttiField; overload;
-    class function FieldExists(aTypeInfo : Pointer; const aFieldName : string) : Boolean;
-    class function GetFieldValue(aInstance : TObject; const aFieldName : string) : TValue; overload;
-    class function GetFieldValue(aTypeInfo : Pointer; const aFieldName: string) : TValue; overload;
-    {$ENDIF}
-    class function GetProperties(aType : TRttiType; aOrder : TRttiPropertyOrder = roFirstBase) : TArray<TRttiProperty>;
-    class function GetType(aTypeInfo : Pointer) : TRttiType;
-    class function GetProperty(aInstance : TObject; const aPropertyName : string) : TRttiProperty; overload;
-    class function GetProperty(aTypeInfo : Pointer; const aPropertyName : string) : TRttiProperty; overload;
-    class function GetPropertyPath(aInstance : TObject; const aPropertyPath : string) : TRttiProperty;
-    {$IFNDEF FPC}
-    class function GetMemberPath(aInstance: TObject; const aPropertyPath: string): TRttiMember;
-    {$ENDIF}
-    class function PathExists(aInstance: TObject; const aPropertyPath: string) : Boolean;
-    class function GetPathValue(aInstance : TObject; const aPropertyPath : string) : TValue;
-    class procedure SetPathValue(aInstance: TObject; const aPropertyPath: string; aValue : TValue);
-    class procedure SetPropertyValue(aInstance : TObject; const aPropertyName : string; aValue : TValue);
-    class function PropertyExists(aTypeInfo : Pointer; const aPropertyName : string) : Boolean;
-    class function GetPropertyValue(aInstance : TObject; const aPropertyName : string) : TValue; overload;
-    class function GetPropertyValue(aTypeInfo : Pointer; const aPropertyName : string) : TValue; overload;
-    class function GetPropertyValueEx(aInstance: TObject; const aPropertyName: string): TValue;
-    {$IFNDEF FPC}
-    class function FindClass(const aClassName: string): TClass;
-    class function CreateInstance<T>: T; overload;
-    class function CreateInstance(aBaseClass : TClass): TObject; overload;
-    class function CallMethod(aObject : TObject; const aMethodName : string; aParams : array of TValue) : TValue;
-    {$ENDIF}
-  end;
-
-  ERTTIError = class(Exception);
-
-  TArrayHelper<T> = class
-  public
-    class function Concat(const Args: array of TArray<T>): TArray<T>; static;
-  end;
-
-implementation
-
-{ TRTTIUtils }
-
-{$IFNDEF FPC}
-class constructor TRTTI.Create;
-begin
-  fCtx := TRttiContext.Create;
-end;
-
-class function TRTTI.CreateInstance<T>: T;
-var
-  value: TValue;
-  rtype: TRttiType;
-  rmethod: TRttiMethod;
-  rinstype: TRttiInstanceType;
-begin
-  rtype := fCtx.GetType(TypeInfo(T));
-  for rmethod in rtype.GetMethods do
-  begin
-    if (rmethod.IsConstructor) and (Length(rmethod.GetParameters) = 0) then
-    begin
-      rinstype := rtype.AsInstance;
-      value := rmethod.Invoke(rinstype.MetaclassType,[]);
-      Result := value.AsType<T>;
-      Exit;
-    end;
-  end;
-end;
-
-class function TRTTI.CreateInstance(aBaseClass : TClass): TObject;
-var
-  value: TValue;
-  rtype: TRttiType;
-  rmethod: TRttiMethod;
-  rinstype: TRttiInstanceType;
-begin
-  Result := nil;
-  rtype := fCtx.GetType(aBaseClass);
-  for rmethod in rtype.GetMethods do
-  begin
-    if (rmethod.IsConstructor) and (Length(rmethod.GetParameters) = 0) then
-    begin
-      rinstype := rtype.AsInstance;
-      value := rmethod.Invoke(rinstype.MetaclassType,[]);
-      Result := value.AsType<TObject>;
-      Exit;
-    end;
-  end;
-end;
-
-class function TRTTI.CallMethod(aObject : TObject; const aMethodName : string; aParams : array of TValue) : TValue;
-var
-  rtype : TRttiType;
-  rmethod : TRttiMethod;
-  rinstype: TRttiInstanceType;
-  value : TValue;
-begin
-  rtype := fCtx.GetType(aObject.ClassInfo);
-  for rmethod in rtype.GetMethods do
-  begin
-    if CompareText(rmethod.Name,aMethodName) = 0 then
-    begin
-      rinstype := rtype.AsInstance;
-      value := rmethod.Invoke(rinstype.MetaclassType,aParams);
-    end;
-
-  end;
-end;
-
-class destructor TRTTI.Destroy;
-begin
-  fCtx.Free;
-end;
-
-class function TRTTI.FieldExists(aTypeInfo: Pointer; const aFieldName: string): Boolean;
-var
-  rtype : TRttiType;
-begin
-  rtype := fCtx.GetType(aTypeInfo);
-  Result := rtype.GetField(aFieldName) <> nil;
-end;
-
-class function TRTTI.GetField(aInstance: TObject; const aFieldName: string): TRttiField;
-var
-  rtype : TRttiType;
-begin
-  Result := nil;
-  rtype := fCtx.GetType(aInstance.ClassInfo);
-  if rtype <> nil then
-  begin
-    Result := rtype.GetField(aFieldName);
-  end;
-end;
-
-class function TRTTI.GetField(aTypeInfo: Pointer; const aFieldName: string): TRttiField;
-var
-  rtype : TRttiType;
-begin
-  Result := nil;
-  rtype := fCtx.GetType(aTypeInfo);
-  if rtype <> nil then
-  begin
-    Result := rtype.GetField(aFieldName);
-  end;
-end;
-
-class function TRTTI.GetFieldValue(aInstance : TObject; const aFieldName: string): TValue;
-var
-  rfield: TRttiField;
-begin
-  rfield := GetField(aInstance,aFieldName);
-  if rfield <> nil then Result := rfield.GetValue(aInstance);
-end;
-
-class function TRTTI.GetFieldValue(aTypeInfo : Pointer; const aFieldName: string): TValue;
-var
-  rfield: TRttiField;
-begin
-  rfield := GetField(aTypeInfo,aFieldName);
-  if rfield <> nil then rfield.GetValue(aTypeInfo);
-end;
-{$ENDIF}
-
-class function TRTTI.GetProperty(aInstance: TObject; const aPropertyName: string): TRttiProperty;
-var
-  rtype : TRttiType;
-begin
-  Result := nil;
-  rtype := fCtx.GetType(aInstance.ClassInfo);
-  if rtype <> nil then Result := rtype.GetProperty(aPropertyName);
-end;
-
-class function TArrayHelper<T>.Concat(const Args: array of TArray<T>): TArray<T>;
-var
-  i, j, out, len: Integer;
-begin
-  len := 0;
-  for i := 0 to High(Args) do
-    len := len + Length(Args[i]);
-  SetLength(Result, len);
-  out := 0;
-  for i := 0 to High(Args) do
-    for j := 0 to High(Args[i]) do
-    begin
-      Result[out] := Args[i][j];
-      Inc(out);
-    end;
-end;
-
-class function TRTTI.GetProperties(aType: TRttiType; aOrder: TRttiPropertyOrder = roFirstBase): TArray<TRttiProperty>;
-var
-  flat: TArray<TArray<TRttiProperty>>;
-  t: TRttiType;
-  depth: Integer;
-begin
-  if aOrder = TRttiPropertyOrder.roFirstBase then
-  begin
-    t := aType;
-    depth := 0;
-    while t <> nil do
-    begin
-      Inc(depth);
-      t := t.BaseType;
-    end;
-
-    SetLength(flat, depth);
-    t := aType;
-    while t <> nil do
-    begin
-      Dec(depth);
-      {$IFNDEF FPC}
-      flat[depth] := t.GetDeclaredProperties;
-      {$ELSE}
-      flat[depth] := t.GetProperties;
-      {$ENDIF}
-      t := t.BaseType;
-    end;
-  end
-  else
-  begin
-    t := aType;
-    depth := 0;
-    while t <> nil do
-    begin
-      Inc(depth);
-      t := t.BaseType;
-    end;
-
-    SetLength(flat, depth);
-    t := aType;
-    depth := 0;
-    while t <> nil do
-    begin
-      {$IFNDEF FPC}
-      flat[depth] := t.GetDeclaredProperties;
-      {$ELSE}
-      flat[depth] := t.GetProperties;
-      {$ENDIF}
-      Inc(depth);
-      t := t.BaseType;
-    end;
-  end;
-
-  Result := TArrayHelper<TRttiProperty>.Concat(flat);
-end;
-
-class function TRTTI.GetProperty(aTypeInfo: Pointer; const aPropertyName: string): TRttiProperty;
-var
-  rtype : TRttiType;
-begin
-  Result := nil;
-  rtype := fCtx.GetType(aTypeInfo);
-  if rtype <> nil then  Result := rtype.GetProperty(aPropertyName);
-end;
-
-class function TRTTI.GetPropertyPath(aInstance: TObject; const aPropertyPath: string): TRttiProperty;
-var
-  prop : TRttiProperty;
-  proppath : string;
-  propname : string;
-  i : Integer;
-  value : TValue;
-  rtype : TRttiType;
-  {$IFNDEF FPC}
-  rfield : TRttiField;
-  {$ENDIF}
-  lastsegment : Boolean;
-begin
-  Result := nil;
-  proppath := aPropertyPath;
-  lastsegment := False;
-  rtype := fCtx.GetType(aInstance.ClassType);
-  repeat
-    i := proppath.IndexOf('.');
-    if i > -1 then
-    begin
-      propname := Copy(proppath,1,i);
-      Delete(proppath,1,i+1);
-    end
-    else
-    begin
-      propname := proppath;
-      lastsegment := True;
-    end;
-    if rtype.TypeKind = TTypeKind.tkRecord then
-    begin
-      {$IFNDEF FPC}
-      rfield := rtype.GetField(propname);
-      if rfield <> nil then value := rfield.GetValue(aInstance);
-      {$ELSE}
-      raise ERTTIError.Create('FPC not supports record fields in RTTI');
-      {$ENDIF}
-    end
-    else
-    begin
-      prop := rtype.GetProperty(propname);
-      if prop = nil then Exit;
-      if lastsegment then Exit(prop)
-        else value := prop.GetValue(aInstance);
-    end;
-    if not lastsegment then
-    begin
-      if value.Kind = TTypeKind.tkClass then rType := fCtx.GetType(value.AsObject.ClassType)
-        else if value.Kind = TTypeKind.tkRecord then rtype := fCtx.GetType(value.TypeInfo);
-    end;
-  until lastsegment;
-  Result := nil;
-end;
-
-{$IFNDEF FPC}
-class function TRTTI.GetMemberPath(aInstance: TObject; const aPropertyPath: string): TRttiMember;
-var
-  prop : TRttiProperty;
-  proppath : string;
-  propname : string;
-  i : Integer;
-  value : TValue;
-  rtype : TRttiType;
-  {$IFNDEF FPC}
-  rfield : TRttiField;
-  {$ENDIF}
-  lastsegment : Boolean;
-begin
-  Result := nil;
-  proppath := aPropertyPath;
-  lastsegment := False;
-  rtype := fCtx.GetType(aInstance.ClassType);
-  repeat
-    i := proppath.IndexOf('.');
-    if i > -1 then
-    begin
-      propname := Copy(proppath,1,i);
-      Delete(proppath,1,i+1);
-    end
-    else
-    begin
-      propname := proppath;
-      lastsegment := True;
-    end;
-    if rtype.TypeKind = TTypeKind.tkRecord then
-    begin
-      {$IFNDEF FPC}
-      rfield := rtype.GetField(propname);
-      if rfield <> nil then
-      begin
-        if lastsegment then Exit(rfield)
-          else value := rfield.GetValue(value.GetReferenceToRawData);
-      end;
-      {$ELSE}
-      raise ERTTIError.Create('FPC not supports record fields in RTTI');
-      {$ENDIF}
-    end
-    else
-    begin
-      prop := rtype.GetProperty(propname);
-      if prop = nil then Exit;
-      if lastsegment then Exit(prop)
-        else value := prop.GetValue(aInstance);
-    end;
-    if not lastsegment then
-    begin
-      if value.Kind = TTypeKind.tkClass then rType := fCtx.GetType(value.AsObject.ClassType)
-        else if value.Kind = TTypeKind.tkRecord then rtype := fCtx.GetType(value.TypeInfo);
-    end;
-  until lastsegment;
-end;
-{$ENDIF}
-
-class function TRTTI.PathExists(aInstance: TObject; const aPropertyPath: string) : Boolean;
-var
-  proppath : string;
-  propname : string;
-  i : Integer;
-  value : TValue;
-  rtype : TRttiType;
-  rprop : TRttiProperty;
-  {$IFNDEF FPC}
-  rfield : TRttiField;
-  {$ENDIF}
-  lastsegment : Boolean;
-begin
-  if not Assigned(aInstance) then Exit(False);
-  lastsegment := False;
-  proppath := aPropertyPath;
-  rtype := fCtx.GetType(aInstance.ClassType);
-  repeat
-    Result := False;
-    i := proppath.IndexOf('.');
-    if i > -1 then
-    begin
-      propname := Copy(proppath,1,i);
-      Delete(proppath,1,i+1);
-    end
-    else
-    begin
-      propname := proppath;
-      lastsegment := True;
-    end;
-    if rtype.TypeKind = TTypeKind.tkRecord then
-    begin
-      {$IFNDEF FPC}
-      rfield := rtype.GetField(propname);
-      if rfield = nil then Exit
-      else
-      begin
-        value := rfield.GetValue(value.GetReferenceToRawData);
-        Result := True;
-      end;
-      {$ELSE}
-      raise ERTTIError.Create('FPC not supports record fields in RTTI');
-      {$ENDIF}
-    end
-    else
-    begin
-      rprop := rtype.GetProperty(propname);
-      if rprop = nil then Exit
-      else
-      begin
-        value := rprop.GetValue(aInstance);
-        Result := True;
-      end;
-    end;
-    if not lastsegment then
-    begin
-      if value.Kind = TTypeKind.tkClass then rType := fCtx.GetType(value.AsObject.ClassType)
-        else if value.Kind = TTypeKind.tkRecord then rtype := fCtx.GetType(value.TypeInfo);
-    end;
-  until lastsegment;
-end;
-
-class function TRTTI.GetPathValue(aInstance: TObject; const aPropertyPath: string): TValue;
-var
-  proppath : string;
-  propname : string;
-  i : Integer;
-  value : TValue;
-  rtype : TRttiType;
-  rprop : TRttiProperty;
-  {$IFNDEF FPC}
-  rfield : TRttiField;
-  {$ENDIF}
-  lastsegment : Boolean;
-begin
-  Result := nil;
-  if not Assigned(aInstance) then Exit;
-
-  lastsegment := False;
-  proppath := aPropertyPath;
-  rtype := fCtx.GetType(aInstance.ClassType);
-  {$IFDEF FPC}
-  value := aInstance;
-  {$ENDIF}
-  repeat
-    i := proppath.IndexOf('.');
-    if i > -1 then
-    begin
-      propname := Copy(proppath,1,i);
-      Delete(proppath,1,i+1);
-    end
-    else
-    begin
-      propname := proppath;
-      lastsegment := True;
-    end;
-    if rtype.TypeKind = TTypeKind.tkRecord then
-    begin
-      {$IFNDEF FPC}
-      rfield := rtype.GetField(propname);
-      if rfield = nil then raise ERTTIError.CreateFmt('Field "%s" not found in record',[propname])
-        else value := rfield.GetValue(value.GetReferenceToRawData);
-      {$ELSE}
-      raise ERTTIError.Create('FPC not supports record fields in RTTI');
-      {$ENDIF}
-    end
-    else
-    begin
-      rprop := rtype.GetProperty(propname);
-      if rprop = nil then raise ERTTIError.CreateFmt('Property "%s" not found in object',[propname])
-      {$IFNDEF FPC}
-      else value := rprop.GetValue(aInstance);
-      {$ELSE}
-      else
-      begin
-        if rprop.PropertyType.IsInstance then value := GetObjectProp(value.AsObject,propname)
-           else value := rprop.GetValue(value.AsObject);
-      end;
-      {$ENDIF}
-    end;
-    if not lastsegment then
-    begin
-      if value.Kind = TTypeKind.tkClass then rType := fCtx.GetType(value.AsObject.ClassType)
-        else if value.Kind = TTypeKind.tkRecord then rtype := fCtx.GetType(value.TypeInfo);
-    end;
-  until lastsegment;
-  Result := value;
-end;
-
-class procedure TRTTI.SetPathValue(aInstance: TObject; const aPropertyPath: string; aValue : TValue);
-var
-  proppath : string;
-  propname : string;
-  i : Integer;
-  value : TValue;
-  rtype : TRttiType;
-  rprop : TRttiProperty;
-  {$IFNDEF FPC}
-  rfield : TRttiField;
-  {$ENDIF}
-  lastsegment : Boolean;
-begin
-  if not Assigned(aInstance) then Exit;
-  lastsegment := False;
-  proppath := aPropertyPath;
-  rtype := fCtx.GetType(aInstance.ClassType);
-  repeat
-    i := proppath.IndexOf('.');
-    if i > -1 then
-    begin
-      propname := Copy(proppath,1,i);
-      Delete(proppath,1,i+1);
-    end
-    else
-    begin
-      propname := proppath;
-      lastsegment := True;
-    end;
-    if rtype.TypeKind = TTypeKind.tkRecord then
-    begin
-      {$IFNDEF FPC}
-      rfield := rtype.GetField(propname);
-      if rfield = nil then raise ERTTIError.CreateFmt('Field "%s" not found in record',[propname])
-      else
-      begin
-        if lastsegment then rfield.SetValue(value.GetReferenceToRawData,aValue)
-          else value := rfield.GetValue(value.GetReferenceToRawData);
-      end;
-      {$ELSE}
-      raise ERTTIError.Create('FPC not supports record fields in RTTI');
-      {$ENDIF}
-    end
-    else
-    begin
-      rprop := rtype.GetProperty(propname);
-      if rprop = nil then raise ERTTIError.CreateFmt('Property "%s" not found in object',[propname])
-      else
-      begin
-        if lastsegment then rprop.SetValue(aInstance,aValue)
-          else value := rprop.GetValue(aInstance);
-      end;
-    end;
-    if not lastsegment then
-    begin
-      if value.Kind = TTypeKind.tkClass then rType := fCtx.GetType(value.AsObject.ClassType)
-        else if value.Kind = TTypeKind.tkRecord then rtype := fCtx.GetType(value.TypeInfo);
-    end;
-  until lastsegment;
-end;
-
-class function TRTTI.GetPropertyValue(aInstance: TObject; const aPropertyName: string): TValue;
-var
-  rprop : TRttiProperty;
-begin
-  rprop := GetProperty(aInstance,aPropertyName);
-  if rprop <> nil then
-  begin
-    {$IFNDEF FPC}
-    Result := rprop.GetValue(aInstance);
-    {$ELSE}
-    if rprop.PropertyType.IsInstance then Result := GetObjectProp(aInstance,aPropertyName)
-      else Result := rprop.GetValue(aInstance);
-    {$ENDIF}
-  end;
-end;
-
-class function TRTTI.GetPropertyValue(aTypeInfo: Pointer; const aPropertyName: string): TValue;
-var
-  rprop : TRttiProperty;
-begin
-  rprop := GetProperty(aTypeInfo,aPropertyName);
-  if rprop <> nil then
-  begin
-    {$IFNDEF FPC}
-    Result := rprop.GetValue(aTypeInfo);
-    {$ELSE}
-    if rprop.PropertyType.IsInstance then Result := GetObjectProp(aTypeInfo,aPropertyName)
-      else Result := rprop.GetValue(aTypeInfo);
-    {$ENDIF}
-  end;
-end;
-
-class function TRTTI.GetPropertyValueEx(aInstance: TObject; const aPropertyName: string): TValue;
-var
-  pinfo : PPropInfo;
-begin
-  Result := nil;
-  pinfo := GetPropInfo(aInstance,aPropertyName);
-  if pinfo = nil then
-  begin
-    //if not found can be a public property
-    Result := GetPropertyValue(aInstance,aPropertyName);
-    Exit;
-  end;
-  case pinfo.PropType^.Kind of
-    tkInteger : Result := GetOrdProp(aInstance,pinfo);
-    tkInt64 : Result := GetInt64Prop(aInstance,aPropertyName);
-    tkFloat : Result := GetFloatProp(aInstance,aPropertyName);
-    tkChar : Result := Char(GetOrdProp(aInstance,aPropertyName));
-    {$IFDEF FPC}
-    tkWString : Result := GetWideStrProp(aInstance,aPropertyName);
-    tkSString,
-    tkAString,
-    {$ELSE}
-    tkUString,
-    tkWString,
-    {$ENDIF}
-    tkLString : Result := GetStrProp(aInstance,pinfo);
-    {$IFDEF FPC}
-    tkEnumeration :Result  := GetOrdProp(aInstance,aPropertyName);
-    {$ELSE}
-    tkEnumeration : Result := GetOrdProp(aInstance,aPropertyName);
-    {$ENDIF}
-    tkSet : Result := GetSetProp(aInstance,pinfo,True);
-    {$IFNDEF FPC}
-    tkClass :
-    {$ELSE}
-    tkBool : Result := Boolean(GetOrdProp(aInstance,pinfo));
-    tkObject :
-    {$ENDIF} Result := GetObjectProp(aInstance,pinfo);
-    tkDynArray : Result := GetDynArrayProp(aInstance,pinfo);
-  end;
-end;
-
-
-class function TRTTI.GetType(aTypeInfo: Pointer): TRttiType;
-begin
-  Result := fCtx.GetType(aTypeInfo);
-end;
-
-class function TRTTI.PropertyExists(aTypeInfo: Pointer; const aPropertyName: string) : Boolean;
-var
-  rtype : TRttiType;
-begin
-  Result := False;
-  rtype := fCtx.GetType(aTypeInfo);
-  if rtype <> nil then Result := rtype.GetProperty(aPropertyName) <> nil;
-end;
-
-class procedure TRTTI.SetPropertyValue(aInstance: TObject; const aPropertyName: string; aValue: TValue);
-var
-  rprop : TRttiProperty;
-begin
-  rprop := GetProperty(aInstance,aPropertyName);
-  if rprop <> nil then rprop.SetValue(aInstance,aValue);
-end;
-
-{$IFNDEF FPC}
-class function TRTTI.FindClass(const aClassName: string): TClass;
-var
-  rType : TRttiType;
-  rList : TArray<TRttiType>;
-begin
-  Result := nil;
-  rList := fCtx.GetTypes;
-  for rType in rList do
-  begin
-    if (rType.IsInstance) and (aClassName.EndsWith(rType.Name)) then
-      begin
-        Result := rType.AsInstance.MetaClassType;
-        Break;
-      end;
-  end;
-end;
-{$ENDIF}
-
-
-end.
+{ ***************************************************************************
+  Copyright (c) 2016-2020 Kike Pérez
+  Unit        : Quick.RTTI.Utils
+  Description : Files functions
+  Author      : Kike Pérez
+  Version     : 1.4
+  Created     : 09/03/2018
+  Modified    : 05/11/2020
+  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.RTTI.Utils;
+{$i QuickLib.inc}
+interface
+uses
+  SysUtils,
+  Quick.Commons,
+  TypInfo,
+  Rtti;
+type
+  TRttiPropertyOrder = (roFirstBase, roFirstInherited);
+  TRTTI = class
+  private class var
+    fCtx : TRttiContext;
+  public
+    {$IFNDEF FPC}
+    class constructor Create;
+    class destructor Destroy;
+    class function GetField(aInstance : TObject; const aFieldName : string) : TRttiField; overload;
+    class function GetField(aTypeInfo : Pointer; const aFieldName : string) : TRttiField; overload;
+    class function FieldExists(aTypeInfo : Pointer; const aFieldName : string) : Boolean;
+    class function GetFieldValue(aInstance : TObject; const aFieldName : string) : TValue; overload;
+    class function GetFieldValue(aTypeInfo : Pointer; const aFieldName: string) : TValue; overload;
+    {$ENDIF}
+    class function GetProperties(aType : TRttiType; aOrder : TRttiPropertyOrder = roFirstBase) : TArray<TRttiProperty>;
+    class function GetType(aTypeInfo : Pointer) : TRttiType;
+    class function GetProperty(aInstance : TObject; const aPropertyName : string) : TRttiProperty; overload;
+    class function GetProperty(aTypeInfo : Pointer; const aPropertyName : string) : TRttiProperty; overload;
+    class function GetPropertyPath(aInstance : TObject; const aPropertyPath : string) : TRttiProperty;
+    {$IFNDEF FPC}
+    class function GetMemberPath(aInstance: TObject; const aPropertyPath: string): TRttiMember;
+    {$ENDIF}
+    class function PathExists(aInstance: TObject; const aPropertyPath: string) : Boolean;
+    class function GetPathValue(aInstance : TObject; const aPropertyPath : string) : TValue;
+    class procedure SetPathValue(aInstance: TObject; const aPropertyPath: string; aValue : TValue);
+    class procedure SetPropertyValue(aInstance : TObject; const aPropertyName : string; aValue : TValue);
+    class function PropertyExists(aTypeInfo : Pointer; const aPropertyName : string) : Boolean;
+    class function GetPropertyValue(aInstance : TObject; const aPropertyName : string) : TValue; overload;
+    class function GetPropertyValue(aTypeInfo : Pointer; const aPropertyName : string) : TValue; overload;
+    class function GetPropertyValueEx(aInstance: TObject; const aPropertyName: string): TValue;
+    {$IFNDEF FPC}
+    class function FindClass(const aClassName: string): TClass;
+    class function CreateInstance<T>: T; overload;
+    class function CreateInstance<T>(const Args: array of TValue): T; overload;
+    class function CreateInstance(aBaseClass : TClass): TObject; overload;
+    class function CallMethod(aObject : TObject; const aMethodName : string; aParams : array of TValue) : TValue;
+    {$ENDIF}
+  end;
+  ERTTIError = class(Exception);
+  TArrayHelper<T> = class
+  public
+    class function Concat(const Args: array of TArray<T>): TArray<T>; static;
+  end;
+implementation
+{ TRTTIUtils }
+{$IFNDEF FPC}
+class constructor TRTTI.Create;
+begin
+  fCtx := TRttiContext.Create;
+end;
+class function TRTTI.CreateInstance<T>: T;
+begin
+  Result := CreateInstance<T>([]);
+end;
+class function TRTTI.CreateInstance<T>(const Args: array of TValue): T;
+var
+  value: TValue;
+  rtype: TRttiType;
+  rmethod: TRttiMethod;
+  rinstype: TRttiInstanceType;
+begin
+  rtype := fCtx.GetType(TypeInfo(T));
+  for rmethod in rtype.GetMethods do
+  begin
+    if (rmethod.IsConstructor) and (Length(rmethod.GetParameters) = Length(Args) ) then
+    begin
+      rinstype := rtype.AsInstance;
+      value := rmethod.Invoke(rinstype.MetaclassType,Args);
+      Result := value.AsType<T>;
+      Exit;
+    end;
+  end;
+end;
+class function TRTTI.CreateInstance(aBaseClass : TClass): TObject;
+var
+  value: TValue;
+  rtype: TRttiType;
+  rmethod: TRttiMethod;
+  rinstype: TRttiInstanceType;
+begin
+  Result := nil;
+  rtype := fCtx.GetType(aBaseClass);
+  for rmethod in rtype.GetMethods do
+  begin
+    if (rmethod.IsConstructor) and (Length(rmethod.GetParameters) = 0) then
+    begin
+      rinstype := rtype.AsInstance;
+      value := rmethod.Invoke(rinstype.MetaclassType,[]);
+      Result := value.AsType<TObject>;
+      Exit;
+    end;
+  end;
+end;
+
+class function TRTTI.CallMethod(aObject : TObject; const aMethodName : string; aParams : array of TValue) : TValue;
+var
+  rtype : TRttiType;
+  rmethod : TRttiMethod;
+  rinstype: TRttiInstanceType;
+begin
+  rtype := fCtx.GetType(aObject.ClassInfo);
+  for rmethod in rtype.GetMethods do
+  begin
+    if CompareText(rmethod.Name,aMethodName) = 0 then
+    begin
+      rinstype := rtype.AsInstance;
+      Result := rmethod.Invoke(rinstype.MetaclassType,aParams);
+    end;
+  end;
+end;
+class destructor TRTTI.Destroy;
+begin
+  fCtx.Free;
+end;
+class function TRTTI.FieldExists(aTypeInfo: Pointer; const aFieldName: string): Boolean;
+var
+  rtype : TRttiType;
+begin
+  rtype := fCtx.GetType(aTypeInfo);
+  Result := rtype.GetField(aFieldName) <> nil;
+end;
+class function TRTTI.GetField(aInstance: TObject; const aFieldName: string): TRttiField;
+var
+  rtype : TRttiType;
+begin
+  Result := nil;
+  rtype := fCtx.GetType(aInstance.ClassInfo);
+  if rtype <> nil then
+  begin
+    Result := rtype.GetField(aFieldName);
+  end;
+end;
+class function TRTTI.GetField(aTypeInfo: Pointer; const aFieldName: string): TRttiField;
+var
+  rtype : TRttiType;
+begin
+  Result := nil;
+  rtype := fCtx.GetType(aTypeInfo);
+  if rtype <> nil then
+  begin
+    Result := rtype.GetField(aFieldName);
+  end;
+end;
+class function TRTTI.GetFieldValue(aInstance : TObject; const aFieldName: string): TValue;
+var
+  rfield: TRttiField;
+begin
+  rfield := GetField(aInstance,aFieldName);
+  if rfield <> nil then Result := rfield.GetValue(aInstance);
+end;
+class function TRTTI.GetFieldValue(aTypeInfo : Pointer; const aFieldName: string): TValue;
+var
+  rfield: TRttiField;
+begin
+  rfield := GetField(aTypeInfo,aFieldName);
+  if rfield <> nil then rfield.GetValue(aTypeInfo);
+end;
+{$ENDIF}
+class function TRTTI.GetProperty(aInstance: TObject; const aPropertyName: string): TRttiProperty;
+var
+  rtype : TRttiType;
+begin
+  Result := nil;
+  rtype := fCtx.GetType(aInstance.ClassInfo);
+  if rtype <> nil then Result := rtype.GetProperty(aPropertyName);
+end;
+class function TArrayHelper<T>.Concat(const Args: array of TArray<T>): TArray<T>;
+var
+  i, j, out, len: Integer;
+begin
+  len := 0;
+  for i := 0 to High(Args) do
+    len := len + Length(Args[i]);
+  SetLength(Result, len);
+  out := 0;
+  for i := 0 to High(Args) do
+    for j := 0 to High(Args[i]) do
+    begin
+      Result[out] := Args[i][j];
+      Inc(out);
+    end;
+end;
+class function TRTTI.GetProperties(aType: TRttiType; aOrder: TRttiPropertyOrder = roFirstBase): TArray<TRttiProperty>;
+var
+  flat: TArray<TArray<TRttiProperty>>;
+  t: TRttiType;
+  depth: Integer;
+begin
+  if aOrder = TRttiPropertyOrder.roFirstBase then
+  begin
+    t := aType;
+    depth := 0;
+    while t <> nil do
+    begin
+      Inc(depth);
+      t := t.BaseType;
+    end;
+    SetLength(flat, depth);
+    t := aType;
+    while t <> nil do
+    begin
+      Dec(depth);
+      {$IFNDEF FPC}
+      flat[depth] := t.GetDeclaredProperties;
+      {$ELSE}
+      flat[depth] := t.GetProperties;
+      {$ENDIF}
+      t := t.BaseType;
+    end;
+  end
+  else
+  begin
+    t := aType;
+    depth := 0;
+    while t <> nil do
+    begin
+      Inc(depth);
+      t := t.BaseType;
+    end;
+    SetLength(flat, depth);
+    t := aType;
+    depth := 0;
+    while t <> nil do
+    begin
+      {$IFNDEF FPC}
+      flat[depth] := t.GetDeclaredProperties;
+      {$ELSE}
+      flat[depth] := t.GetProperties;
+      {$ENDIF}
+      Inc(depth);
+      t := t.BaseType;
+    end;
+  end;
+  Result := TArrayHelper<TRttiProperty>.Concat(flat);
+end;
+class function TRTTI.GetProperty(aTypeInfo: Pointer; const aPropertyName: string): TRttiProperty;
+var
+  rtype : TRttiType;
+begin
+  Result := nil;
+  rtype := fCtx.GetType(aTypeInfo);
+  if rtype <> nil then  Result := rtype.GetProperty(aPropertyName);
+end;
+class function TRTTI.GetPropertyPath(aInstance: TObject; const aPropertyPath: string): TRttiProperty;
+var
+  prop : TRttiProperty;
+  proppath : string;
+  propname : string;
+  i : Integer;
+  value : TValue;
+  rtype : TRttiType;
+  {$IFNDEF FPC}
+  rfield : TRttiField;
+  {$ENDIF}
+  lastsegment : Boolean;
+begin
+  Result := nil;
+  proppath := aPropertyPath;
+  lastsegment := False;
+  rtype := fCtx.GetType(aInstance.ClassType);
+  repeat
+    i := proppath.IndexOf('.');
+    if i > -1 then
+    begin
+      propname := Copy(proppath,1,i);
+      Delete(proppath,1,i+1);
+    end
+    else
+    begin
+      propname := proppath;
+      lastsegment := True;
+    end;
+    if rtype.TypeKind = TTypeKind.tkRecord then
+    begin
+      {$IFNDEF FPC}
+      rfield := rtype.GetField(propname);
+      if rfield <> nil then value := rfield.GetValue(aInstance);
+      {$ELSE}
+      raise ERTTIError.Create('FPC not supports record fields in RTTI');
+      {$ENDIF}
+    end
+    else
+    begin
+      prop := rtype.GetProperty(propname);
+      if prop = nil then Exit;
+      if lastsegment then Exit(prop)
+        else value := prop.GetValue(aInstance);
+    end;
+    if not lastsegment then
+    begin
+      if value.Kind = TTypeKind.tkClass then rType := fCtx.GetType(value.AsObject.ClassType)
+        else if value.Kind = TTypeKind.tkRecord then rtype := fCtx.GetType(value.TypeInfo);
+    end;
+  until lastsegment;
+  Result := nil;
+end;
+{$IFNDEF FPC}
+class function TRTTI.GetMemberPath(aInstance: TObject; const aPropertyPath: string): TRttiMember;
+var
+  prop : TRttiProperty;
+  proppath : string;
+  propname : string;
+  i : Integer;
+  value : TValue;
+  rtype : TRttiType;
+  {$IFNDEF FPC}
+  rfield : TRttiField;
+  {$ENDIF}
+  lastsegment : Boolean;
+begin
+  Result := nil;
+  proppath := aPropertyPath;
+  lastsegment := False;
+  rtype := fCtx.GetType(aInstance.ClassType);
+  repeat
+    i := proppath.IndexOf('.');
+    if i > -1 then
+    begin
+      propname := Copy(proppath,1,i);
+      Delete(proppath,1,i+1);
+    end
+    else
+    begin
+      propname := proppath;
+      lastsegment := True;
+    end;
+    if rtype.TypeKind = TTypeKind.tkRecord then
+    begin
+      {$IFNDEF FPC}
+      rfield := rtype.GetField(propname);
+      if rfield <> nil then
+      begin
+        if lastsegment then Exit(rfield)
+          else value := rfield.GetValue(value.GetReferenceToRawData);
+      end;
+      {$ELSE}
+      raise ERTTIError.Create('FPC not supports record fields in RTTI');
+      {$ENDIF}
+    end
+    else
+    begin
+      prop := rtype.GetProperty(propname);
+      if prop = nil then Exit;
+      if lastsegment then Exit(prop)
+        else value := prop.GetValue(aInstance);
+    end;
+    if not lastsegment then
+    begin
+      if value.Kind = TTypeKind.tkClass then rType := fCtx.GetType(value.AsObject.ClassType)
+        else if value.Kind = TTypeKind.tkRecord then rtype := fCtx.GetType(value.TypeInfo);
+    end;
+  until lastsegment;
+end;
+{$ENDIF}
+class function TRTTI.PathExists(aInstance: TObject; const aPropertyPath: string) : Boolean;
+var
+  proppath : string;
+  propname : string;
+  i : Integer;
+  value : TValue;
+  rtype : TRttiType;
+  rprop : TRttiProperty;
+  {$IFNDEF FPC}
+  rfield : TRttiField;
+  {$ENDIF}
+  lastsegment : Boolean;
+begin
+  if not Assigned(aInstance) then Exit(False);
+  lastsegment := False;
+  proppath := aPropertyPath;
+  rtype := fCtx.GetType(aInstance.ClassType);
+  repeat
+    Result := False;
+    i := proppath.IndexOf('.');
+    if i > -1 then
+    begin
+      propname := Copy(proppath,1,i);
+      Delete(proppath,1,i+1);
+    end
+    else
+    begin
+      propname := proppath;
+      lastsegment := True;
+    end;
+    if rtype.TypeKind = TTypeKind.tkRecord then
+    begin
+      {$IFNDEF FPC}
+      rfield := rtype.GetField(propname);
+      if rfield = nil then Exit
+      else
+      begin
+        value := rfield.GetValue(value.GetReferenceToRawData);
+        Result := True;
+      end;
+      {$ELSE}
+      raise ERTTIError.Create('FPC not supports record fields in RTTI');
+      {$ENDIF}
+    end
+    else
+    begin
+      rprop := rtype.GetProperty(propname);
+      if rprop = nil then Exit
+      else
+      begin
+        value := rprop.GetValue(aInstance);
+        Result := True;
+      end;
+    end;
+    if not lastsegment then
+    begin
+      if value.Kind = TTypeKind.tkClass then rType := fCtx.GetType(value.AsObject.ClassType)
+        else if value.Kind = TTypeKind.tkRecord then rtype := fCtx.GetType(value.TypeInfo);
+    end;
+  until lastsegment;
+end;
+class function TRTTI.GetPathValue(aInstance: TObject; const aPropertyPath: string): TValue;
+var
+  proppath : string;
+  propname : string;
+  i : Integer;
+  value : TValue;
+  rtype : TRttiType;
+  rprop : TRttiProperty;
+  {$IFNDEF FPC}
+  rfield : TRttiField;
+  {$ENDIF}
+  lastsegment : Boolean;
+begin
+  Result := nil;
+  if not Assigned(aInstance) then Exit;
+  lastsegment := False;
+  proppath := aPropertyPath;
+  rtype := fCtx.GetType(aInstance.ClassType);
+  {$IFDEF FPC}
+  value := aInstance;
+  {$ENDIF}
+  repeat
+    i := proppath.IndexOf('.');
+    if i > -1 then
+    begin
+      propname := Copy(proppath,1,i);
+      Delete(proppath,1,i+1);
+    end
+    else
+    begin
+      propname := proppath;
+      lastsegment := True;
+    end;
+    if rtype.TypeKind = TTypeKind.tkRecord then
+    begin
+      {$IFNDEF FPC}
+      rfield := rtype.GetField(propname);
+      if rfield = nil then raise ERTTIError.CreateFmt('Field "%s" not found in record',[propname])
+        else value := rfield.GetValue(value.GetReferenceToRawData);
+      {$ELSE}
+      raise ERTTIError.Create('FPC not supports record fields in RTTI');
+      {$ENDIF}
+    end
+    else
+    begin
+      rprop := rtype.GetProperty(propname);
+      if rprop = nil then raise ERTTIError.CreateFmt('Property "%s" not found in object',[propname])
+      {$IFNDEF FPC}
+      else value := rprop.GetValue(aInstance);
+      {$ELSE}
+      else
+      begin
+        if rprop.PropertyType.IsInstance then value := GetObjectProp(value.AsObject,propname)
+           else value := rprop.GetValue(value.AsObject);
+      end;
+      {$ENDIF}
+    end;
+    if not lastsegment then
+    begin
+      if value.Kind = TTypeKind.tkClass then rType := fCtx.GetType(value.AsObject.ClassType)
+        else if value.Kind = TTypeKind.tkRecord then rtype := fCtx.GetType(value.TypeInfo);
+    end;
+  until lastsegment;
+  Result := value;
+end;
+class procedure TRTTI.SetPathValue(aInstance: TObject; const aPropertyPath: string; aValue : TValue);
+var
+  proppath : string;
+  propname : string;
+  i : Integer;
+  value : TValue;
+  rtype : TRttiType;
+  rprop : TRttiProperty;
+  {$IFNDEF FPC}
+  rfield : TRttiField;
+  {$ENDIF}
+  lastsegment : Boolean;
+begin
+  if not Assigned(aInstance) then Exit;
+  lastsegment := False;
+  proppath := aPropertyPath;
+  rtype := fCtx.GetType(aInstance.ClassType);
+  repeat
+    i := proppath.IndexOf('.');
+    if i > -1 then
+    begin
+      propname := Copy(proppath,1,i);
+      Delete(proppath,1,i+1);
+    end
+    else
+    begin
+      propname := proppath;
+      lastsegment := True;
+    end;
+    if rtype.TypeKind = TTypeKind.tkRecord then
+    begin
+      {$IFNDEF FPC}
+      rfield := rtype.GetField(propname);
+      if rfield = nil then raise ERTTIError.CreateFmt('Field "%s" not found in record',[propname])
+      else
+      begin
+        if lastsegment then rfield.SetValue(value.GetReferenceToRawData,aValue)
+          else value := rfield.GetValue(value.GetReferenceToRawData);
+      end;
+      {$ELSE}
+      raise ERTTIError.Create('FPC not supports record fields in RTTI');
+      {$ENDIF}
+    end
+    else
+    begin
+      rprop := rtype.GetProperty(propname);
+      if rprop = nil then raise ERTTIError.CreateFmt('Property "%s" not found in object',[propname])
+      else
+      begin
+        if lastsegment then rprop.SetValue(aInstance,aValue)
+          else value := rprop.GetValue(aInstance);
+      end;
+    end;
+    if not lastsegment then
+    begin
+      if value.Kind = TTypeKind.tkClass then rType := fCtx.GetType(value.AsObject.ClassType)
+        else if value.Kind = TTypeKind.tkRecord then rtype := fCtx.GetType(value.TypeInfo);
+    end;
+  until lastsegment;
+end;
+class function TRTTI.GetPropertyValue(aInstance: TObject; const aPropertyName: string): TValue;
+var
+  rprop : TRttiProperty;
+begin
+  rprop := GetProperty(aInstance,aPropertyName);
+  if rprop <> nil then
+  begin
+    {$IFNDEF FPC}
+    Result := rprop.GetValue(aInstance);
+    {$ELSE}
+    if rprop.PropertyType.IsInstance then Result := GetObjectProp(aInstance,aPropertyName)
+      else Result := rprop.GetValue(aInstance);
+    {$ENDIF}
+  end;
+end;
+class function TRTTI.GetPropertyValue(aTypeInfo: Pointer; const aPropertyName: string): TValue;
+var
+  rprop : TRttiProperty;
+begin
+  rprop := GetProperty(aTypeInfo,aPropertyName);
+  if rprop <> nil then
+  begin
+    {$IFNDEF FPC}
+    Result := rprop.GetValue(aTypeInfo);
+    {$ELSE}
+    if rprop.PropertyType.IsInstance then Result := GetObjectProp(aTypeInfo,aPropertyName)
+      else Result := rprop.GetValue(aTypeInfo);
+    {$ENDIF}
+  end;
+end;
+class function TRTTI.GetPropertyValueEx(aInstance: TObject; const aPropertyName: string): TValue;
+var
+  pinfo : PPropInfo;
+begin
+  Result := nil;
+  pinfo := GetPropInfo(aInstance,aPropertyName);
+  if pinfo = nil then
+  begin
+    //if not found can be a public property
+    Result := GetPropertyValue(aInstance,aPropertyName);
+    Exit;
+  end;
+  case pinfo.PropType^.Kind of
+    tkInteger : Result := GetOrdProp(aInstance,pinfo);
+    tkInt64 : Result := GetInt64Prop(aInstance,aPropertyName);
+    tkFloat : Result := GetFloatProp(aInstance,aPropertyName);
+    tkChar : Result := Char(GetOrdProp(aInstance,aPropertyName));
+    {$IFDEF FPC}
+    tkWString : Result := GetWideStrProp(aInstance,aPropertyName);
+    tkSString,
+    tkAString,
+    {$ELSE}
+    tkUString,
+    tkWString,
+    {$ENDIF}
+    tkLString : Result := GetStrProp(aInstance,pinfo);
+    {$IFDEF FPC}
+    tkEnumeration :Result  := GetOrdProp(aInstance,aPropertyName);
+    {$ELSE}
+    tkEnumeration : Result := GetOrdProp(aInstance,aPropertyName);
+    {$ENDIF}
+    tkSet : Result := GetSetProp(aInstance,pinfo,True);
+    {$IFNDEF FPC}
+    tkClass :
+    {$ELSE}
+    tkBool : Result := Boolean(GetOrdProp(aInstance,pinfo));
+    tkObject :
+    {$ENDIF} Result := GetObjectProp(aInstance,pinfo);
+    tkDynArray : Result := GetDynArrayProp(aInstance,pinfo);
+  end;
+end;
+
+class function TRTTI.GetType(aTypeInfo: Pointer): TRttiType;
+begin
+  Result := fCtx.GetType(aTypeInfo);
+end;
+class function TRTTI.PropertyExists(aTypeInfo: Pointer; const aPropertyName: string) : Boolean;
+var
+  rtype : TRttiType;
+begin
+  Result := False;
+  rtype := fCtx.GetType(aTypeInfo);
+  if rtype <> nil then Result := rtype.GetProperty(aPropertyName) <> nil;
+end;
+class procedure TRTTI.SetPropertyValue(aInstance: TObject; const aPropertyName: string; aValue: TValue);
+var
+  rprop : TRttiProperty;
+begin
+  rprop := GetProperty(aInstance,aPropertyName);
+  if rprop <> nil then rprop.SetValue(aInstance,aValue);
+end;
+{$IFNDEF FPC}
+class function TRTTI.FindClass(const aClassName: string): TClass;
+var
+  rType : TRttiType;
+  rList : TArray<TRttiType>;
+begin
+  Result := nil;
+  rList := fCtx.GetTypes;
+  for rType in rList do
+  begin
+    if (rType.IsInstance) and (aClassName.EndsWith(rType.Name)) then
+      begin
+        Result := rType.AsInstance.MetaClassType;
+        Break;
+      end;
+  end;
+end;
+{$ENDIF}
+
+end.

+ 218 - 0
Quick.RegEx.Utils.pas

@@ -0,0 +1,218 @@
+{ ***************************************************************************
+
+  Copyright (c) 2016-2021 Kike Pérez
+
+  Unit        : Quick.RegEx.Utils
+  Description : Common string validations
+  Author      : Kike Pérez
+  Version     : 2.0
+  Created     : 07/04/2021
+  Modified    : 07/04/2021
+
+  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.RegEx.Utils;
+
+{$i QuickLib.inc}
+
+interface
+
+uses
+  System.SysUtils,
+  System.RegularExpressions;
+
+type
+  TRegExUtils = class
+    /// <summary> Validates if value is Integer or Float number </summary>
+    class function IsNumber(const aValue : string) : Boolean;
+    /// <summary> Validates if value is Integer number </summary>
+    class function IsInteger(const aValue : string) : Boolean;
+    /// <summary> Validates if value is Float number </summary>
+    class function IsFloat(const aValue : string) : Boolean;
+    /// <summary> Validates if value is alphanumeric with optional space char as valid char </summary>
+    class function IsAlphanumeric(const aValue : string; aSpaceCharAsValid : Boolean = True) : Boolean;
+    /// <summary> Validates email address </summary>
+    class function IsValidEmail(const aEmail : string) : Boolean;
+    /// <summary> Validates password complexity (Should have 1 lowercase letter, 1 uppercase letter, 1 number,
+    /// 1 special character and be at least 8 characters long) </summary>
+    class function IsPasswordComplex(const aPassword : string) : Boolean;
+    /// <summary> Validate username (may include _ and – with min and max length restriction) </summary>
+    class function IsValidUsername(const aUsername: string; aMinLength : Integer = 3; aMaxLength : Integer = 18): Boolean;
+    // <summary> Validates Url with optional protocol </summary>
+    class function IsValidUrl(const aUrl: string; aProtocolOptional : Boolean): Boolean;
+    // <summary> Validates Ip v4 </summary>
+    class function IsValidIpv4(const aIp : string) : Boolean;
+    // <summary> Validates Ip v6 </summary>
+    class function IsValidIpv6(const aIp : string) : Boolean;
+    // <summary> Validates date format YYYMMdd with - or . or / </summary>
+    class function IsValidDate_YYYYMMdd(const aDate : string) : Boolean;
+    // <summary> Validates date format ddMMYYYY with - or . or / </summary>
+    class function IsValidDate_ddMMYYY(const aDate : string) : Boolean;
+    // <summary> Validates Httml tag </summary>
+    class function IsValidHtmlTag(const aValue : string) : Boolean;
+    // <summary> Validates for duplicates in a string </summary>
+    class function HasDuplicates(const aValue : string) : Boolean;
+    /// <summary> Validates international number with optional country code/extension </summary>
+    class function IsValidPhoneNumber(const aPhoneNumber : string) : Boolean;
+    /// <summary> Validates Path, filename and extension </summary>
+    class function IsValidFilePath(const aFilePath : string) : Boolean;
+    /// <summary> Validates Visa card number </summary>
+    class function IsValidVisaCard(const aCardNumber : string) : Boolean;
+    /// <summary> Validates Master Card number </summary>
+    class function IsValidMasterCard(const aCardNumber : string) : Boolean;
+    /// <summary> Validates American Express card number /summary>
+    class function IsValidAmericanExpressCard(const aCardNumber : string) : Boolean;
+    /// <summary> Validates Passport number</summary>
+    class function IsValidPassport(const aPassport : string) : Boolean;
+    /// <summary> Validates Spanish Documento Nacional de Identidad </summary>
+    class function IsValidDNI_ES(const aDNI : string) : Boolean;
+    /// <summary> Validates USA Social Security Number document </summary>
+    class function IsValidSSN_US(const aSSN : string) : Boolean;
+  end;
+
+implementation
+
+{ TRegExUtils }
+
+class function TRegExUtils.IsNumber(const aValue: string): Boolean;
+begin
+  Result := TRegEx.IsMatch(aValue,'^\d*(\.\d+)?$');
+end;
+
+class function TRegExUtils.IsFloat(const aValue: string): Boolean;
+begin
+  Result := TRegEx.IsMatch(aValue,'^\d*\.\d+$');
+end;
+
+class function TRegExUtils.IsInteger(const aValue: string): Boolean;
+begin
+  Result := TRegEx.IsMatch(aValue,'^\d+$');
+end;
+
+class function TRegExUtils.IsAlphanumeric(const aValue : string; aSpaceCharAsValid : Boolean) : Boolean;
+begin
+  if aSpaceCharAsValid then Result := TRegEx.IsMatch(aValue,'^[a-zA-Z0-9 ]*$')
+    else Result := TRegEx.IsMatch(aValue,'^[a-zA-Z0-9]*$');
+end;
+
+class function TRegExUtils.IsPasswordComplex(const aPassword : string) : Boolean;
+begin
+  Result := TRegEx.IsMatch(aPassword,'(?=(.*[0-9]))(?=.*[\!@#$%^&*()\\[\]{}\-_+=~`|:;"''<>,./?])(?=.*[a-z])(?=(.*[A-Z]))(?=(.*)).{8,}');
+end;
+
+class function TRegExUtils.IsValidEmail(const aEmail: string): Boolean;
+begin
+  Result := TRegEx.IsMatch(aEmail,'^([a-zA-Z0-9._%-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6})*$');
+end;
+
+class function TRegExUtils.IsValidFilePath(const aFilePath: string): Boolean;
+begin
+  Result := TRegEx.IsMatch(aFilePath,'((\/|\\|\/\/|https?:\\\\|https?:\/\/)[a-z0-9_@\-^!#$%&+={}.\/\\\[\]]+)+\.[a-z]+$');
+end;
+
+class function TRegExUtils.IsValidUsername(const aUsername: string; aMinLength : Integer; aMaxLength : Integer): Boolean;
+begin
+  Result := TRegEx.IsMatch(aUsername,Format('^[A-Za-z0-9_-]{%d,%d}$',[aMinLength,aMaxLength]));
+end;
+
+
+class function TRegExUtils.IsValidUrl(const aUrl: string; aProtocolOptional : Boolean): Boolean;
+begin
+  if aProtocolOptional then Result := TRegEx.IsMatch(aUrl,'(https?:\/\/)?(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)')
+    else Result := TRegEx.IsMatch(aUrl,'https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#()?&//=]*)');
+end;
+
+class function TRegExUtils.IsValidIpv4(const aIp: string): Boolean;
+begin
+  Result := TRegEx.IsMatch(aIp,'^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$');
+end;
+
+class function TRegExUtils.IsValidIpv6(const aIp: string): Boolean;
+begin
+  Result := TRegEx.IsMatch(aIp,'(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]'
+                              +'{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|'
+                              +'([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}'
+                              +'(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}'
+                              +'|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)'
+                              +'|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}'
+                              +'((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9])'
+                              +'{0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.)'
+                              +'{3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))');
+end;
+
+class function TRegExUtils.IsValidDate_ddMMYYY(const aDate: string): Boolean;
+begin
+  Result := TRegEx.IsMatch(aDate,'^(?:(?:31(\/|-|\.)(?:0?[13578]|1[02]))\1|(?:(?:29|30)(\/|-|\.)'
+                                 + '(?:0?[13-9]|1[0-2])\2))(?:(?:1[6-9]|[2-9]\d)?\d{2})$|^(?:29(\/|-'
+                                 +'|\.)0?2\3(?:(?:(?:1[6-9]|[2-9]\d)?(?:0[48]|[2468][048]|[13579][26])|'
+                                 +'(?:(?:16|[2468][048]|[3579][26])00))))$|^(?:0?[1-9]|1\d|2[0-8])(\/|-|\.)'
+                                 +'(?:(?:0?[1-9])|(?:1[0-2]))\4(?:(?:1[6-9]|[2-9]\d)?\d{2})$');
+end;
+
+class function TRegExUtils.IsValidDate_YYYYMMdd(const aDate: string): Boolean;
+begin
+  Result := TRegEx.IsMatch(aDate,'([12]\d{3}(\/|-|\.)(0[1-9]|1[0-2])(\/|-|\.)(0[1-9]|[12]\d|3[01]))');
+end;
+
+class function TRegExUtils.IsValidHtmlTag(const aValue: string): Boolean;
+begin
+  Result := TRegEx.IsMatch(aValue,'<\/?[\w\s]*>|<.+[\W]>');
+end;
+
+class function TRegExUtils.HasDuplicates(const aValue: string): Boolean;
+begin
+  Result := TRegEx.IsMatch(aValue,'(\b\w+\b)(?=.*\b\1\b)');
+end;
+
+class function TRegExUtils.IsValidPhoneNumber(const aPhoneNumber: string): Boolean;
+begin
+  Result := TRegEx.IsMatch(aPhoneNumber,'^(?:(?:\(?(?:00|\+)([1-4]\d\d|[1-9]\d?)\)?)?[\-\.\ \\\/]?)?((?:\(?\d{1,}\)?[\-\.\ \\\/]?){0,})(?:[\-\.\ \\\/]?(?:#|ext\.?|extension|x)[\-\.\ \\\/]?(\d+))?$');
+end;
+
+class function TRegExUtils.IsValidVisaCard(const aCardNumber: string): Boolean;
+begin
+  Result := TRegEx.IsMatch(aCardNumber,'^4[0-9]{12}(?:[0-9]{3})?$');
+end;
+
+class function TRegExUtils.IsValidMasterCard(const aCardNumber: string): Boolean;
+begin
+  Result := TRegEx.IsMatch(aCardNumber,'^(?:5[1-5][0-9]{2}|222[1-9]|22[3-9][0-9]|2[3-6][0-9]{2}|27[01][0-9]|2720)[0-9]{12}$');
+end;
+
+class function TRegExUtils.IsValidAmericanExpressCard(const aCardNumber: string): Boolean;
+begin
+  Result := TRegEx.IsMatch(aCardNumber,'^3[47][0-9]{13}$');
+end;
+
+class function TRegExUtils.IsValidPassport(const aPassport: string): Boolean;
+begin
+  Result := TRegEx.IsMatch(aPassport,'^[A-PR-WY][1-9]\d\s?\d{4}[1-9]$');
+end;
+
+class function TRegExUtils.IsValidDNI_ES(const aDNI: string): Boolean;
+begin
+  Result := TRegEx.IsMatch(aDNI,'((([X-Z])|([LM])){1}([-]?)((\d){7})([-]?)([A-Z]{1}))|((\d{8})([-]?)([A-Z]))');
+end;
+
+class function TRegExUtils.IsValidSSN_US(const aSSN: string): Boolean;
+begin
+  Result := TRegEx.IsMatch(aSSN,'^((?!219-09-9999|078-05-1120)(?!666|000|9\d{2})\d{3}-(?!00)\d{2}-(?!0{4})\d{4})|((?!219 09 9999|078 05 1120)(?!666|000|9\d{2})\d{3} (?!00)\d{2} (?!0{4})\d{4})|((?!219099999|078051120)(?!666|000|9\d{2})\d{3}(?!00)\d{2}(?!0{4})\d{4})$');
+end;
+
+end.

+ 89 - 0
Quick.Registry.pas

@@ -0,0 +1,89 @@
+{ ***************************************************************************
+
+  Copyright (c) 2016-2020 Kike Pérez
+
+  Unit        : Quick.Registry
+  Description : Util registry info
+  Author      : Kike Pérez
+  Version     : 2.0
+  Created     : 22/01/2021
+  Modified    : 25/01/2021
+
+  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.Registry;
+
+{$i QuickLib.inc}
+
+interface
+
+uses
+  System.SysUtils,
+  Winapi.Windows,
+  System.Win.Registry;
+
+type
+  TRegRootKey = (rootCU, rootLM);
+
+  TRegistryUtils = class
+  public
+    class function GetNewReg(aRootKey : TRegRootKey; aReadOnly : Boolean = False) : TRegistry;
+    class function GetUniqueMachineId: TGUID; static;
+    class function IsDarkMode : Boolean;
+  end;
+
+implementation
+
+
+class function TRegistryUtils.GetNewReg(aRootKey : TRegRootKey; aReadOnly : Boolean = False) : TRegistry;
+begin
+  if aReadOnly then Result := TRegistry.Create(KEY_READ)
+    else Result := TRegistry.Create(KEY_ALL_ACCESS);
+  if aRootKey = TRegRootKey.rootCU then Result.RootKey := HKEY_CURRENT_USER
+    else Result.RootKey := HKEY_LOCAL_MACHINE;
+end;
+
+class function TRegistryUtils.IsDarkMode : Boolean;
+var
+  reg : TRegistry;
+begin
+  reg := GetNewReg(TRegRootKey.rootCU,True);
+  try
+    reg.RootKey := HKEY_CURRENT_USER;
+    reg.OpenKeyReadOnly('SOFTWARE\Microsoft\Windows\CurrentVersion\Themes\Personalize');
+    Result := not reg.ReadBool('AppsUseLightTheme');
+  finally
+    reg.Free;
+  end;
+end;
+
+class function TRegistryUtils.GetUniqueMachineId : TGUID;
+var
+  reg : TRegistry;
+begin
+  reg := GetNewReg(TRegRootKey.rootLM,True);
+  try
+    reg.OpenKeyReadOnly('SOFTWARE\Microsoft\Cryptography');
+    Result := StringToGUID(reg.ReadString('MachineGuid'));
+  finally
+    reg.Free;
+  end;
+end;
+
+end.

+ 81 - 8
Quick.SMTP.pas

@@ -1,13 +1,13 @@
-{ ***************************************************************************
+{ ***************************************************************************
 
-  Copyright (c) 2016-2020 Kike P�rez
+  Copyright (c) 2016-2021 Kike P�rez
 
   Unit        : Quick.SMTP
   Description : Send Emails
   Author      : Kike P�rez
-  Version     : 1.4
+  Version     : 1.5
   Created     : 12/10/2017
-  Modified    : 29/07/2020
+  Modified    : 08/09/2021
 
   This file is part of QuickLib: https://github.com/exilon/QuickLib
 
@@ -35,6 +35,7 @@ interface
 
 uses
   Classes,
+  Generics.Collections,
   SysUtils,
   IdGlobal,
   IdSMTP,
@@ -44,10 +45,21 @@ uses
   IdText,
   IdAttachment,
   IdAttachmentFile,
+  IdAttachmentMemory,
   IdExplicitTLSClientServerBase,
   IdHTTP;
 
 type
+  TAttachment = class
+  private
+    fFilename : string;
+    fContent : TStream;
+  public
+    constructor Create(const aFilename : string; const aContent : TStream);
+    destructor Destroy; override;
+    property Filename : string read fFilename;
+    property Content : TStream read fContent;
+  end;
 
   TMailMessage = class
   private
@@ -61,7 +73,9 @@ type
     fReplyTo : string;
     fBodyFromFile : Boolean;
     fAttachments : TStringList;
+    fAttachmentFiles : TObjectList<TAttachment>;
     procedure SetBody(aValue : string);
+    procedure SetAttachments(const Value: TStringList);
   public
     constructor Create;
     destructor Destroy; override;
@@ -73,7 +87,10 @@ type
     property CC : string read fCC write fCC;
     property BCC : string read fBCC write fBCC;
     property ReplyTo : string read fReplyTo write fReplyTo;
-    property Attachments : TStringList read fAttachments write fAttachments;
+    property Attachments : TStringList read fAttachments write SetAttachments;
+    property AttachmentFiles : TObjectList<TAttachment> read fAttachmentFiles;
+    procedure AddAttachment(const aFilename : string; aStream : TStream); overload;
+    procedure AddAttachment(const aFilename, aFilePath : string); overload;
     procedure AddBodyFromFile(const cFileName : string);
   end;
 
@@ -93,6 +110,7 @@ type
     function SendMail(aMail : TMailMessage) : Boolean; overload;
     function SendEmail(const aFromEmail,aFromName,aSubject,aTo,aCC,aBC,aReplyTo,aBody : string) : Boolean; overload;
     function SendEmail(const aFromName,aSubject,aTo,aCC,aBC,aReplyTo,aBody : string) : Boolean; overload;
+    function SendEmail(const aFromName,aSubject,aTo,aCC,aBC,aReplyTo,aBody : string; const aAttachments : TStringList) : Boolean; overload;
   end;
 
 implementation
@@ -106,20 +124,43 @@ begin
   fBCC := '';
   fBody := '';
   fAttachments := TStringList.Create;
+  fAttachmentFiles := TObjectList<TAttachment>.Create(True);
 end;
 
 destructor TMailMessage.Destroy;
 begin
   if Assigned(fAttachments) then fAttachments.Free;
+  if Assigned(fAttachmentFiles) then fAttachmentFiles.Free;
   inherited;
 end;
 
+procedure TMailMessage.AddAttachment(const aFilename, aFilePath : string);
+var
+  fs : TFileStream;
+begin
+  if not FileExists(aFilePath) then raise Exception.CreateFmt('MailMessage: file "%s" not found!',[aFilename]);
+  fs := TFileStream.Create(aFilePath,fmOpenRead);
+  fAttachmentFiles.Add(TAttachment.Create(aFilename,fs));
+end;
+
+procedure TMailMessage.AddAttachment(const aFilename : string; aStream : TStream);
+begin
+  fAttachmentFiles.Add(TAttachment.Create(aFilename,aStream));
+end;
+
 procedure TMailMessage.AddBodyFromFile(const cFileName: string);
 begin
   fBodyFromFile := True;
   fBody := cFileName;
 end;
 
+procedure TMailMessage.SetAttachments(const Value: TStringList);
+begin
+  if Assigned(fAttachments) then fAttachments.Free;
+
+  fAttachments := Value;
+end;
+
 procedure TMailMessage.SetBody(aValue: string);
 begin
   fBodyFromFile := False;
@@ -158,6 +199,11 @@ begin
 end;
 
 function TSMTP.SendEmail(const aFromName,aSubject,aTo,aCC,aBC,aReplyTo,aBody : string) : Boolean;
+begin
+  Result := SendEmail(aFromName,aSubject,aTo,aCC,aBC,aReplyTo,aBody,nil);
+end;
+
+function TSMTP.SendEmail(const aFromName,aSubject,aTo,aCC,aBC,aReplyTo,aBody : string; const aAttachments : TStringList) : Boolean;
 var
   mail : TMailMessage;
 begin
@@ -173,6 +219,7 @@ begin
     Mail.CC := aCC;
     Mail.BCC := aBC;
     Mail.ReplyTo := aReplyTo;
+    if aAttachments <> nil then Mail.Attachments := aAttachments;
     Result := Self.SendMail(mail);
   finally
     mail.Free;
@@ -191,16 +238,17 @@ var
   email : string;
   filename : string;
   mBody : TIdText;
-  idattach : TIdAttachmentFile;
+  idattach : TIdAttachment;
+  attach : TAttachment;
 begin
   Result := False;
   SSLHandler := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
   try
+    idattach := nil;
+    mBody := nil;
     msg := TIdMessage.Create(nil);
     try
       //create mail msg
-      idattach := nil;
-      mBody := nil;
       msg.From.Address := aMail.From;
       if aMail.SenderName <> '' then msg.From.Name := aMail.SenderName;
       msg.Subject := aMail.Subject;
@@ -227,6 +275,17 @@ begin
           idattach := TIdAttachmentFile.Create(msg.MessageParts,filename);
         end;
       end;
+      //add stream attachments if exists
+      if aMail.AttachmentFiles.Count > 0 then
+      begin
+        //mBody.ContentType := 'multipart/mixed';
+        //msg.ContentType := 'multipart/mixed';
+        for attach in aMail.AttachmentFiles do
+        begin
+          idattach := TIdAttachmentMemory.Create(msg.MessageParts,attach.Content);
+          idattach.Filename := attach.Filename;
+        end;
+      end;
 
       //configure smtp SSL
       try
@@ -271,4 +330,18 @@ begin
 end;
 
 
+{ TAttachment }
+
+constructor TAttachment.Create(const aFilename: string; const aContent: TStream);
+begin
+  fFilename := aFilename;
+  fContent := aContent;
+end;
+
+destructor TAttachment.Destroy;
+begin
+  if Assigned(fContent) then fContent.Free;
+  inherited;
+end;
+
 end.

+ 2 - 1
Quick.Serializer.Intf.pas

@@ -3,10 +3,11 @@ unit Quick.Serializer.Intf;
 interface
 
 uses
-  System.SysUtils,
+  SysUtils,
   {$IFNDEF FPC}
   rtti;
   {$ELSE}
+  Rtti,
   rttiutils;
   {$ENDIF}
 

+ 62 - 4
Quick.Service.pas

@@ -34,10 +34,12 @@ interface
 
 uses
   SysUtils,
+  {$IFDEF MSWINDOWS}
   Windows,
-  {$IFNDEF FPC}
   Messages,
   WinSvc,
+  {$ENDIF}
+  {$IFNDEF FPC}
   System.IOUtils,
   {$ELSE}
   Quick.Files,
@@ -45,6 +47,7 @@ uses
   Quick.Commons,
   Quick.Process;
 
+{$IFDEF MSWINDOWS}
 type
   TServiceState = (ssUnknow = -1,
                    ssStopped = SERVICE_STOPPED,
@@ -54,17 +57,63 @@ type
                    ssContinuePending = SERVICE_CONTINUE_PENDING,
                    ssPausePending = SERVICE_PAUSE_PENDING,
                    ssPaused = SERVICE_PAUSED);
+{$ENDIF}
 
-  function ServiceIsPresent(const aMachine, aServiceName : string): Boolean;
+  {$IFDEF MSWINDOWS}
+  function ServiceIsPresent(const aServiceName : string): Boolean; overload;
+  function ServiceIsPresent(const aMachine, aServiceName : string): Boolean; overload;
   function GetServicePath : string;
   function GetServiceState(const aServer, aServiceName : string) : TServiceState;
-  function ServiceStart(const aMachine, aServiceName : string) : Boolean;
-  function ServiceStop(const aMachine, aServiceName : string ) : Boolean;
+  function ServiceStart(const aServiceName : string) : Boolean; overload;
+  function ServiceStop(const aServiceName : string ) : Boolean; overload;
+  function ServiceStart(const aMachine, aServiceName : string) : Boolean; overload;
+  function ServiceStop(const aMachine, aServiceName : string ) : Boolean; overload;
+  {$ELSE}
+  function ServiceIsPresent(const aServiceName : string): Boolean;
+  function ServiceStart(const aServiceName : string) : Boolean;
+  function ServiceStop(const aServiceName : string ) : Boolean;
+  {$ENDIF}
   function ServiceUninstall(const aServiceName : string): Boolean;
+  {$IFDEF MSWINDOWS}
   function DeleteServiceEx(svcName : string) : Boolean;
+  {$ENDIF}
 
 implementation
 
+function ServiceIsPresent(const aServiceName : string) : Boolean;
+{$IFDEF MSWINDOWS}
+begin
+  Result := ServiceIsPresent('localhost',aServiceName);
+end;
+{$ELSE}
+begin
+
+end;
+{$ENDIF}
+
+function ServiceStart(const aServiceName : string) : Boolean;
+{$IFDEF MSWINDOWS}
+begin
+  Result := ServiceStart('localhost',aServiceName);
+end;
+{$ELSE}
+begin
+
+end;
+{$ENDIF}
+
+function ServiceStop(const aServiceName : string) : Boolean;
+{$IFDEF MSWINDOWS}
+begin
+  Result := ServiceStop('localhost',aServiceName);
+end;
+{$ELSE}
+begin
+
+end;
+{$ENDIF}
+
+{$IFDEF MSWINDOWS}
 function ServiceIsPresent(const aMachine, aServiceName : string): Boolean;
 var
   smanHnd : SC_Handle;
@@ -202,8 +251,10 @@ begin
   end;
   Result := SERVICE_STOPPED = svcStatus.dwCurrentState;
 end;
+{$ENDIF}
 
 function ServiceUninstall(const aServiceName : string): Boolean;
+{$IFDEF MSWINDOWS}
 var
   smanHnd : SC_Handle;
   svchnd : SC_Handle;
@@ -236,7 +287,13 @@ begin
     end;
   end;
 end;
+{$ELSE}
+begin
+
+end;
+{$ENDIF}
 
+{$IFDEF MSWINDOWS}
 function DeleteServiceEx(svcName : string) : Boolean;
 begin
   Result := False;
@@ -245,5 +302,6 @@ begin
     Result := ShellExecuteAndWait('open','sc','delete '+svcName,'',0,True) = 0;
   end;
 end;
+{$ENDIF}
 
 end.

+ 10 - 1
Quick.SysInfo.pas

@@ -48,6 +48,11 @@ uses
     System.IOUtils,
       {$IFDEF ANDROID}
       Androidapi.Helpers,
+        {$IFDEF DELPHIRX103_UP}
+        Androidapi.JNI.GraphicsContentViewText,
+        Androidapi.JNI.JavaTypes,
+        Androidapi.JNI.App,
+        {$ENDIF}
       {$ENDIF}
       {$IFDEF IOS}
       Macapi.CoreFoundation,
@@ -96,7 +101,11 @@ begin
     else fAppName := ExtractFilenameWithoutExt(ParamStr(0));
   {$ELSE}
     {$IFDEF ANDROID}
-    fAppName := JStringToString(SharedActivityContext.getPackageName);
+      {$IFDEF DELPHIRX103_UP}
+      fAppName := JStringToString(TAndroidHelper.Context.getPackageName);
+      {$ELSE}
+      fAppName := JStringToString(SharedActivityContext.getPackageName);
+      {$ENDIF}
     {$ELSE}
     fAppName := TNSString.Wrap(CFBundleGetValueForInfoDictionaryKey(CFBundleGetMainBundle, kCFBundleIdentifierKey)).UTF8String;
     {$ENDIF}

+ 323 - 9
Quick.Threads.pas

@@ -1,13 +1,13 @@
 { ***************************************************************************
 
-  Copyright (c) 2016-2020 Kike Pérez
+  Copyright (c) 2016-2021 Kike Pérez
 
   Unit        : Quick.Threads
   Description : Thread safe collections
   Author      : Kike Pérez
   Version     : 1.5
   Created     : 09/03/2018
-  Modified    : 27/06/2020
+  Modified    : 08/09/2021
 
   This file is part of QuickLib: https://github.com/exilon/QuickLib
 
@@ -149,6 +149,17 @@ type
 
   TThreadWorkStatus = (wsRunning, wsDone, wsException);
 
+  TSimpleThread = class(TThread)
+  private
+    fExecuteProc : TProc;
+    fTimeoutFlag : TLightweightEvent;
+  public
+    constructor Create(aProc: TProc; aCreateSuspended, aFreeOnTerminate : Boolean);
+    destructor Destroy; override;
+    procedure Execute; override;
+    function WaitFor(const aTimeout : Cardinal) : TWaitResult; overload;
+  end;
+
   TAdvThread = class(TThread)
   private
     fExecuteProc : TProc;
@@ -233,6 +244,8 @@ type
     procedure DoExecute;
     procedure DoException(aException : Exception);
     procedure DoTerminate;
+    procedure Enable;
+    procedure Disable;
     {$IFNDEF FPC}
     property Param[index : Integer] : TFlexValue read GetParam write SetParam; default;
     property Param[const Name : string] : TFlexValue read GetParam write SetParam; default;
@@ -381,6 +394,8 @@ type
     function MaxRetries : Integer;
     function LastException : Exception;
     function CircuitBreaked : Boolean;
+    procedure Disable;
+    procedure Enable;
   end;
 
   TWorkTask = class(TTask,IWorkTask)
@@ -481,8 +496,10 @@ type
   end;
 
   TSimpleWorker = class(TWorker)
+  private
+    fRunOnce : Boolean;
   public
-    constructor Create(aTask : ITask);
+    constructor Create(aTask : ITask; aRunOnce : Boolean = True);
     procedure Execute; override;
   end;
 
@@ -515,6 +532,42 @@ type
     class function Execute_Sync(aParamArray: array of const; aOwnedParams: Boolean; aTaskProc: TTaskProc): IWorkTask; overload;
   end;
 
+  IAsyncTask = interface
+  ['{90A27D06-6FCD-493C-8AA0-C52C5105ED8B}']
+    procedure Wait; overload;
+    procedure Wait(const aTimeout : Cardinal); overload;
+  end;
+
+  TAsyncTask = class(TInterfacedObject,IAsyncTask)
+  private
+    fProcess : TSimpleThread;
+    constructor Create(aAction : TProc);
+  public
+    class function Run(const aAction : TProc) : IAsyncTask; virtual;
+    procedure Wait; overload;
+    procedure Wait(const aTimeout : Cardinal); overload;
+    destructor Destroy; override;
+  end;
+
+  IAsyncTask<T> = interface
+  ['{8529BBD4-B5AD-4674-8E42-3C74F5156A97}']
+    function Result : T; overload;
+    function Result(const aTimeout : Cardinal) : T; overload;
+  end;
+
+  TAsyncTask<T> = class(TInterfacedObject,IAsyncTask<T>)
+  private
+    fProcess : TSimpleThread;
+    fTaskResult : T;
+    fWaitForResult : Boolean;
+    function Result : T; overload;
+    function Result(const aTimeout : Cardinal) : T; overload;
+    constructor Create(aAction : TFunc<T>);
+  public
+    class function Run(const aAction : TFunc<T>) : IAsyncTask<T>; virtual;
+    destructor Destroy; override;
+  end;
+
   TBackgroundTasks = class
   private
     fMaxQueue : Integer;
@@ -585,6 +638,35 @@ type
     procedure Stop;
   end;
 
+  TBackgroundWorkers = class
+  private
+    fWorkerPool : TWorkerPool;
+    fConcurrentWorkers : Integer;
+    fWorkerInitProc : TTaskProc;
+    fWorkerExecuteProc : TTaskProc;
+    fWorkerRetryProc : TTaskRetryProc;
+    fWorkerExceptionProc : TTaskExceptionProc;
+    fWorkerTerminateProc : TTaskProc;
+    fFaultPolicy : TFaultPolicy;
+    procedure SetRetryPolicy(aMaxRetries, aWaitTimeBetweenRetriesMS : Integer; aWaitTimeMultiplierFactor: Double);
+  public
+    constructor Create(aConcurrentWorkers : Integer; aWorkerProc : TTaskProc);
+    destructor Destroy; override;
+    property ConcurrentWorkers : Integer read fConcurrentWorkers;
+    function OnInitialize(aTaskProc : TTaskProc) : TBackgroundWorkers;
+    function OnException(aTaskProc : TTaskExceptionProc) : TBackgroundWorkers;
+    function OnRetry(aTaskProc : TTaskRetryProc) : TBackgroundWorkers;
+    function OnTerminated(aTaskProc : TTaskProc) : TBackgroundWorkers;
+    function Retry(aMaxRetries : Integer) : TBackgroundWorkers;
+    function RetryForever : TBackgroundWorkers;
+    function WaitAndRetry(aMaxRetries, aWaitTimeBetweenRetriesMS : Integer) : TBackgroundWorkers; overload;
+    function WaitAndRetry(aMaxRetries, aWaitTimeBetweenRetriesMS : Integer; aWaitTimeMultiplierFactor : Double) : TBackgroundWorkers; overload;
+    function WaitAndRetryForever(aWaitTimeBetweenRetriesMS : Integer) : TBackgroundWorkers; overload;
+    function WaitAndRetryForever(aWaitTimeBetweenRetriesMS : Integer; aWaitTimeMultiplierFactor : Double) : TBackgroundWorkers; overload;
+    procedure Start;
+    procedure Stop;
+  end;
+
 implementation
 
 { TThreadedQueueCS<T> }
@@ -789,8 +871,9 @@ end;
 destructor TThreadedQueueList<T>.Destroy;
 begin
   DoShutDown;
-  fQueueLock.Free;
   fQueueCondVar.Free;
+  fQueueLock.Free;
+  //fQueueCondVar.Free;
   fQueue.Free;
   inherited;
 end;
@@ -1133,6 +1216,11 @@ begin
   inherited;
 end;
 
+procedure TTask.Disable;
+begin
+  fEnabled := False;
+end;
+
 procedure TTask.DoException(aException : Exception);
 begin
   fTaskStatus := TWorkTaskStatus.wtsException;
@@ -1221,6 +1309,11 @@ begin
   if Assigned(fTerminateProc) then fTerminateProc(Self);
 end;
 
+procedure TTask.Enable;
+begin
+  fEnabled := True;
+end;
+
 function TTask.GetIdTask: Int64;
 begin
   Result := fIdTask;
@@ -1557,9 +1650,10 @@ end;
 
 { TSimpleWorker }
 
-constructor TSimpleWorker.Create(aTask : ITask);
+constructor TSimpleWorker.Create(aTask : ITask; aRunOnce : Boolean = True);
 begin
   inherited Create;
+  fRunOnce := aRunOnce;
   fCurrentTask := aTask;
   FreeOnTerminate := True;
 end;
@@ -1573,6 +1667,7 @@ begin
     try
       fStatus := TWorkerStatus.wsWorking;
       try
+        SetFaultPolicy(TTask(fCurrentTask));
         if TTask(fCurrentTask).ExecuteWithSync then Synchronize(ExecuteTask)
           else fCurrentTask.DoExecute;
       except
@@ -1583,10 +1678,14 @@ begin
         end;
       end;
     finally
-      if TTask(fCurrentTask).TerminateWithSync then Synchronize(TerminateTask)
-        else fCurrentTask.DoTerminate;
       fStatus := TWorkerStatus.wsIdle;
-      Terminate;
+      try
+        if TTask(fCurrentTask).TerminateWithSync then Synchronize(TerminateTask)
+          else fCurrentTask.DoTerminate;
+      except
+        on E : Exception do if fCurrentTask <> nil then fCurrentTask.DoException(E)
+      end;
+      if fRunOnce then Terminate;
     end;
   end;
   fStatus := TWorkerStatus.wsSuspended
@@ -1826,7 +1925,7 @@ begin
   Result := Self;
   ClearSchedule;
   fScheduleMode := TScheduleMode.smRunOnce;
-  fStartDate := ChangeDateOfADay(Now(),aHour,aMinute,aSecond);
+  fStartDate := ChangeTimeOfADay(Now(),aHour,aMinute,aSecond);
   fNextExecution := fStartDate;
 end;
 
@@ -2260,6 +2359,72 @@ begin
   worker.Start;
 end;
 
+{ TAsyncTask }
+
+constructor TAsyncTask.Create(aAction : TProc);
+begin
+  fProcess := TSimpleThread.Create(aAction,False,True);
+end;
+
+destructor TAsyncTask.Destroy;
+begin
+  inherited;
+end;
+
+class function TAsyncTask.Run(const aAction : TProc) : IAsyncTask;
+begin
+  Result := TAsyncTask.Create(aAction);
+end;
+
+procedure TAsyncTask.Wait(const aTimeout: Cardinal);
+begin
+  if aTimeout = 0 then fProcess.WaitFor
+    else fProcess.WaitFor(aTimeout);
+end;
+
+procedure TAsyncTask.Wait;
+begin
+  fProcess.WaitFor;
+end;
+
+{ TAsyncTask<T> }
+
+constructor TAsyncTask<T>.Create(aAction: TFunc<T>);
+begin
+  fWaitForResult := False;
+  fProcess := TSimpleThread.Create(procedure
+                                begin
+                                  fTaskResult := aAction();
+                                end,False,False);
+end;
+
+destructor TAsyncTask<T>.Destroy;
+begin
+  if not fWaitForResult then fProcess.FreeOnTerminate := True;
+  inherited;
+end;
+
+class function TAsyncTask<T>.Run(const aAction: TFunc<T>): IAsyncTask<T>;
+begin
+  Result := TAsyncTask<T>.Create(aAction);
+end;
+
+function TAsyncTask<T>.Result: T;
+begin
+  fWaitForResult := True;
+  fProcess.WaitFor;
+  Result := fTaskResult;
+  fProcess.Free;
+end;
+
+function TAsyncTask<T>.Result(const aTimeout: Cardinal): T;
+begin
+  fWaitForResult := True;
+  fProcess.WaitFor(aTimeout);
+  Result := fTaskResult;
+  fProcess.Free;
+end;
+
 { TParamValue }
 
 constructor TParamValue.Create(const aName: string; aValue: TFlexValue; aOwnedValue: Boolean);
@@ -2293,4 +2458,153 @@ begin
   inherited;
 end;
 
+{ TBackgroundWorkers }
+
+constructor TBackgroundWorkers.Create(aConcurrentWorkers : Integer; aWorkerProc : TTaskProc);
+begin
+  fConcurrentWorkers := aConcurrentWorkers;
+  fWorkerExecuteProc := aWorkerProc;
+  fWorkerPool := TWorkerPool.Create(True);
+end;
+
+destructor TBackgroundWorkers.Destroy;
+begin
+  fWorkerPool.Free;
+  inherited;
+end;
+
+procedure TBackgroundWorkers.Start;
+var
+  i : Integer;
+  worker : TWorker;
+  task : IWorkTask;
+begin
+  for i := 1 to fConcurrentWorkers do
+  begin
+    task := TWorkTask.Create([],False,fWorkerExecuteProc)
+            .OnInitialize(fWorkerInitProc)
+            .OnRetry(fWorkerRetryProc)
+            .OnException(fWorkerExceptionProc)
+            .OnTerminated(fWorkerTerminateProc);
+    task.NumWorker := i;
+    task.Run;
+    worker := TSimpleWorker.Create(task,False);
+    fWorkerPool.Add(worker);
+    worker.Start;
+  end;
+end;
+
+procedure TBackgroundWorkers.Stop;
+var
+  worker : TWorker;
+begin
+  for worker in fWorkerPool do
+  begin
+    worker.Terminate;
+    worker.WaitFor;
+    fWorkerPool.Remove(worker);
+  end;
+end;
+
+function TBackgroundWorkers.OnException(aTaskProc: TTaskExceptionProc): TBackgroundWorkers;
+begin
+  Result := Self;
+  fWorkerExceptionProc := aTaskProc;
+end;
+
+function TBackgroundWorkers.OnInitialize(aTaskProc: TTaskProc): TBackgroundWorkers;
+begin
+  Result := Self;
+  fWorkerInitProc := aTaskProc;
+end;
+
+function TBackgroundWorkers.OnRetry(aTaskProc: TTaskRetryProc): TBackgroundWorkers;
+begin
+  Result := Self;
+  fWorkerRetryProc := aTaskProc;
+end;
+
+function TBackgroundWorkers.OnTerminated(aTaskProc: TTaskProc): TBackgroundWorkers;
+begin
+  Result := Self;
+  fWorkerTerminateProc := aTaskProc;
+end;
+
+function TBackgroundWorkers.Retry(aMaxRetries: Integer): TBackgroundWorkers;
+begin
+  Result := Self;
+  SetRetryPolicy(aMaxRetries,0,1);
+end;
+
+function TBackgroundWorkers.RetryForever: TBackgroundWorkers;
+begin
+  Result := Self;
+  SetRetryPolicy(-1,0,1);
+end;
+
+procedure TBackgroundWorkers.SetRetryPolicy(aMaxRetries, aWaitTimeBetweenRetriesMS: Integer; aWaitTimeMultiplierFactor: Double);
+begin
+  fFaultPolicy.MaxRetries := aMaxRetries;
+  fFaultPolicy.WaitTimeBetweenRetries := aWaitTimeBetweenRetriesMS;
+  fFaultPolicy.WaitTimeMultiplierFactor := aWaitTimeMultiplierFactor;
+end;
+
+function TBackgroundWorkers.WaitAndRetry(aMaxRetries, aWaitTimeBetweenRetriesMS: Integer; aWaitTimeMultiplierFactor: Double): TBackgroundWorkers;
+begin
+  Result := Self;
+  SetRetryPolicy(aMaxRetries,aWaitTimeBetweenRetriesMS,aWaitTimeMultiplierFactor);
+end;
+
+function TBackgroundWorkers.WaitAndRetry(aMaxRetries, aWaitTimeBetweenRetriesMS: Integer): TBackgroundWorkers;
+begin
+  Result := Self;
+  SetRetryPolicy(aMaxRetries,aWaitTimeBetweenRetriesMS,1);
+end;
+
+function TBackgroundWorkers.WaitAndRetryForever(aWaitTimeBetweenRetriesMS: Integer): TBackgroundWorkers;
+begin
+  Result := Self;
+  SetRetryPolicy(-1,aWaitTimeBetweenRetriesMS,1);
+end;
+
+function TBackgroundWorkers.WaitAndRetryForever(aWaitTimeBetweenRetriesMS: Integer; aWaitTimeMultiplierFactor: Double): TBackgroundWorkers;
+begin
+  Result := Self;
+  SetRetryPolicy(-1,aWaitTimeBetweenRetriesMS,aWaitTimeMultiplierFactor);
+end;
+
+{ TSimpleThread }
+
+constructor TSimpleThread.Create(aProc: TProc; aCreateSuspended, aFreeOnTerminate : Boolean);
+begin
+  if not Assigned(aProc) then raise EArgumentNilException.Create('param cannot be nil!');
+  fTimeoutFlag := TLightweightEvent.Create;
+  fTimeoutFlag.ResetEvent;
+  fExecuteProc := aProc;
+  inherited Create(aCreateSuspended);
+  Self.FreeOnTerminate := aFreeOnTerminate;
+end;
+
+destructor TSimpleThread.Destroy;
+begin
+  if Assigned(fTimeoutFlag) then
+  begin
+    fTimeoutFlag.Release;
+    fTimeoutFlag.Free;
+  end;
+  inherited;
+end;
+
+procedure TSimpleThread.Execute;
+begin
+  fExecuteProc;
+  fTimeoutFlag.SetEvent;
+end;
+
+function TSimpleThread.WaitFor(const aTimeout: Cardinal) : TWaitResult;
+begin
+  Result := fTimeoutFlag.WaitFor(aTimeout);
+  if Result = TWaitResult.wrTimeout then raise Exception.Create('Timeout');
+end;
+
 end.

+ 122 - 0
Quick.Url.Utils.pas

@@ -0,0 +1,122 @@
+{ ***************************************************************************
+
+  Copyright (c) 2016-2021 Kike Pérez
+
+  Unit        : Quick.Url.Utils
+  Description : Common Url utils
+  Author      : Kike Pérez
+  Version     : 2.0
+  Created     : 17/03/2021
+  Modified    : 17/03/2021
+
+  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.Url.Utils;
+
+{$i QuickLib.inc}
+
+interface
+
+uses
+  System.SysUtils,
+  {$IFDEF NOTUSEINDY}
+  System.NetEncoding,
+  {$ELSE}
+  IdURI,
+  {$ENDIF}
+  Quick.Commons;
+
+type
+  TUrlUtils = class
+    class function GetProtocol(const aUrl : string) : string;
+    class function GetHost(const aUrl : string) : string;
+    class function GetPath(const aUrl : string) : string;
+    class function GetQuery(const aUrl : string) : string;
+    class function RemoveProtocol(const aUrl : string) : string;
+    class function RemoveQuery(const aUrl : string) : string;
+    class function EncodeUrl(const aUrl : string) : string;
+  end;
+
+implementation
+
+{ TUrlUtils }
+
+class function TUrlUtils.EncodeUrl(const aUrl: string): string;
+{$IFDEF NOTUSEINDY}
+const
+  RestUnsafeChars: TURLEncoding.TUnsafeChars = [Ord('"'), Ord(''''), Ord(':'), Ord(';'), Ord('<'), Ord('='), Ord('>'),
+    Ord('@'), Ord('['), Ord(']'), Ord('^'), Ord('`'), Ord('{'), Ord('}'), Ord('|'), Ord('\'), Ord('?'), Ord('#'),
+    Ord('&'), Ord('!'), Ord('$'), Ord('('), Ord(')'), Ord(','), Ord('~'), Ord(' '), Ord('*'), Ord('+')];
+{$ENDIF}
+var
+  proto : string;
+  path : string;
+  query : string;
+begin
+  {$IFDEF NOTUSEINDY}
+  Result := TNetEncoding.URL.Encode(aUrl);
+  //Result := StringReplace(aUrl,' ','%20',[rfReplaceAll]);
+  proto := UrlGetProtocol(aUrl);
+  if not proto.IsEmpty then proto := proto + '://';
+
+  path := UrlGetPath(aUrl);
+  path := TNetEncoding.Url.EncodePath(path);
+
+
+  query := UrlGetQuery(aUrl);
+  query := TNetEncoding.Url.EncodeQuery(query);
+  if not query.IsEmpty then query := '?' + query;
+
+  Result := proto + UrlGetHost(aUrl) + path + query;
+  {$ELSE}
+  Result := TIdURI.URLEncode(aUrl);
+  {$ENDIF}
+end;
+
+class function TUrlUtils.GetProtocol(const aUrl: string): string;
+begin
+  Result := UrlGetProtocol(aUrl);
+end;
+
+class function TUrlUtils.GetHost(const aUrl: string): string;
+begin
+  Result := UrlGetHost(aUrl);
+end;
+
+class function TUrlUtils.GetPath(const aUrl: string): string;
+begin
+  Result := UrlGetPath(aUrl);
+end;
+
+class function TUrlUtils.GetQuery(const aUrl: string): string;
+begin
+  Result := UrlGetQuery(aUrl);
+end;
+
+class function TUrlUtils.RemoveProtocol(const aUrl: string): string;
+begin
+  Result := UrlRemoveProtocol(aUrl);
+end;
+
+class function TUrlUtils.RemoveQuery(const aUrl: string): string;
+begin
+  Result := UrlRemoveQuery(aUrl);
+end;
+
+end.

+ 1 - 1
Quick.Value.RTTI.pas

@@ -106,7 +106,7 @@ begin
       dtBoolean : Result := AsBoolean;
       dtString : Result := AsString;
       {$IFDEF MSWINDOWS}
-      dtAnsiString : Result := AsAnsiString;
+      dtAnsiString : Result := string(AsAnsiString);
       dtWideString : Result := AsWideString;
       {$ENDIF}
       dtInteger,

+ 1613 - 1584
Quick.YAML.Serializer.pas

@@ -1,1584 +1,1613 @@
-{ ***************************************************************************
-
-  Copyright (c) 2015-2020 Kike Pérez
-
-  Unit        : Quick.YAML.Serializer
-  Description : YAML Serializer
-  Author      : Kike Pérez
-  Version     : 1.0
-  Created     : 12/04/2019
-  Modified    : 07/04/20120
-
-  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.Serializer;
-
-{$i QuickLib.inc}
-
-interface
-
-uses
-  Classes,
-  SysUtils,
-  Rtti,
-  TypInfo,
-  {$IFDEF FPC}
-   rttiutils,
-   strUtils,
-   Generics.Collections,
-  {$ELSE}
-    {$IFDEF DELPHIRX103_UP}
-    System.Generics.Collections,
-    {$ENDIF}
-  {$ENDIF}
-  DateUtils,
-  Quick.Commons,
-  Quick.RTTI.Utils,
-  Quick.YAML,
-  Quick.Value,
-  Quick.Arrays;
-
-type
-
-  EYamlSerializeError = class(Exception);
-  EYamlDeserializeError = class(Exception);
-
-  {$IFNDEF FPC}
-  TNotSerializableProperty = class(TCustomAttribute);
-
-  TCommentProperty = class(TCustomAttribute)
-  private
-    fComment : string;
-  public
-    constructor Create(const aComment: string);
-    property Comment : string read fComment;
-  end;
-
-  TCustomNameProperty = class(TCustomAttribute)
-  private
-    fName : string;
-  public
-    constructor Create(const aName: string);
-    property Name : string read fName;
-  end;
-  {$ENDIF}
-
-  IYamlSerializer = interface
-  ['{CA26F7AE-F1FE-41BE-9C23-723A687F60D1}']
-    function YamlToObject(aType: TClass; const aYaml: string): TObject; overload;
-    function YamlToObject(aObject: TObject; const aYaml: string): TObject; overload;
-    function ObjectToYaml(aObject : TObject): string;
-  end;
-
-  TSerializeLevel = (slPublicProperty, slPublishedProperty);
-
-  TRTTIYaml = class
-  private
-    fSerializeLevel : TSerializeLevel;
-    fUseEnumNames : Boolean;
-    fUseYamlCaseSense : Boolean;
-    function GetValue(aAddr: Pointer; aType: TRTTIType): TValue; overload;
-    function GetValue(aAddr: Pointer; aTypeInfo: PTypeInfo): TValue; overload;
-    function IsAllowedProperty(aObject : TObject; const aPropertyName : string) : Boolean;
-    function IsGenericList(aObject : TObject) : Boolean;
-    function IsGenericXArray(const aClassName : string) : Boolean;
-    function GetPropertyValue(Instance : TObject; const PropertyName : string) : TValue;
-    function GetPropertyValueFromObject(Instance : TObject; const PropertyName : string) : TValue;
-    {$IFNDEF FPC}
-    function GetFieldValueFromRecord(aValue : TValue; const FieldName : string) : TValue;
-    {$ENDIF}
-    procedure SetPropertyValue(Instance : TObject; aPropInfo : PPropInfo; aValue : TValue); overload;
-    procedure SetPropertyValue(Instance : TObject; const PropertyName : string; aValue : TValue); overload;
-    {$IFDEF FPC}
-    function FloatProperty(aObject : TObject; aPropInfo: PPropInfo): string;
-    function GetPropType(aPropInfo: PPropInfo): PTypeInfo;
-    procedure LoadSetProperty(aInstance : TObject; aPropInfo: PPropInfo; const aValue: string);
-    {$ENDIF}
-  public
-    constructor Create(aSerializeLevel : TSerializeLevel; aUseEnumNames : Boolean = True);
-    property UseEnumNames : Boolean read fUseEnumNames write fUseEnumNames;
-    property UseYamlCaseSense : Boolean read fUseYamlCaseSense write fUseYamlCaseSense;
-    {$IFNDEF FPC}
-    function DeserializeDynArray(aTypeInfo : PTypeInfo; aObject : TObject; const aYamlArray: TYamlArray) : TValue;
-    function DeserializeRecord(aRecord : TValue; aObject : TObject; const aYaml : TYamlObject) : TValue;
-    {$ELSE}
-    procedure DeserializeDynArray(aTypeInfo: PTypeInfo; const aPropertyName : string; aObject: TObject; const aYamlArray: TYamlArray);
-    {$ENDIF}
-    function DeserializeClass(aType : TClass; const aYaml : TYamlObject) : TObject;
-    function DeserializeObject(aObject : TObject; const aYaml : TYamlObject) : TObject; overload;
-    {$IFNDEF FPC}
-    function DeserializeList(aObject: TObject; const aName : string; const aYaml: TYamlObject) : TObject;
-    procedure DeserializeXArray(Instance : TObject; aRecord : TValue; aProperty : TRttiProperty; const aPropertyName : string; aYaml : TYamlObject);
-    {$ENDIF}
-    function DeserializeProperty(aObject : TObject; const aName : string; aProperty : TRttiProperty; const aYaml : TYamlObject) : TObject; overload;
-    {$IFNDEF FPC}
-    function DeserializeType(aObject : TObject; aType : TTypeKind; aTypeInfo : PTypeInfo; const aValue: string) : TValue;
-    {$ELSE}
-    function DeserializeType(aObject : TObject; aType : TTypeKind; const aPropertyName, aValue: string) : TValue;
-    {$ENDIF}
-    {$IFNDEF FPC}
-    function Serialize(const aName : string; aValue : TValue) : TYamlPair; overload;
-    {$ELSE}
-    function Serialize(aObject : TObject; aType : TTypeKind; const aPropertyName : string) : TYamlPair;
-    function Serialize(const aName : string; aValue : TValue) : TYamlPair;
-    {$ENDIF}
-    function Serialize(aObject : TObject) : TYamlObject; overload;
-    function GetYamlPairByName(aYaml : TYamlObject; const aName : string) : TYamlPair;
-  end;
-
-  TYamlSerializer = class(TInterfacedObject,IYamlSerializer)
-  strict private
-    fSerializeLevel : TSerializeLevel;
-    fUseEnumNames : Boolean;
-    fUseYamlCaseSense : Boolean;
-    fRTTIYaml : TRTTIYaml;
-  private
-    procedure SetUseEnumNames(const Value: Boolean);
-    procedure SetUseYamlCaseSense(const Value: Boolean);
-    procedure SetSerializeLevel(const Value: TSerializeLevel);
-  public
-    constructor Create(aSerializeLevel: TSerializeLevel; aUseEnumNames : Boolean = True);
-    destructor Destroy; override;
-    property SerializeLevel : TSerializeLevel read fSerializeLevel write SetSerializeLevel;
-    property UseEnumNames : Boolean read fUseEnumNames write SetUseEnumNames;
-    property UseYamlCaseSense : Boolean read fUseYamlCaseSense write SetUseYamlCaseSense;
-    function YamlToObject(aType : TClass; const aYaml: string) : TObject; overload;
-    function YamlToObject(aObject : TObject; const aYaml: string) : TObject; overload;
-    function ObjectToYaml(aObject : TObject): string;
-  end;
-
-  PPByte = ^PByte;
-
-resourcestring
-  cNotSupportedDataType = 'Not supported "%s" data type "%s"';
-  cNotSerializable = 'Object is not serializable';
-
-implementation
-
-{ TRTTIYaml }
-
-{$IFNDEF FPC}
-function TRTTIYaml.DeserializeDynArray(aTypeInfo: PTypeInfo; aObject: TObject; const aYamlArray: TYamlArray) : TValue;
-var
-  rType: PTypeInfo;
-  len: NativeInt;
-  pArr: Pointer;
-  rItemValue: TValue;
-  i: Integer;
-  objClass: TClass;
-  ctx : TRttiContext;
-  Yaml : TYamlObject;
-  rDynArray : TRttiDynamicArrayType;
-  propObj : TObject;
-begin
-  if GetTypeData(aTypeInfo).DynArrElType = nil then Exit;
-  if not assigned(aYamlArray) then Exit;
-
-  len := aYamlArray.Count;
-  rType := GetTypeData(aTypeInfo).DynArrElType^;
-  pArr := nil;
-  DynArraySetLength(pArr,aTypeInfo, 1, @len);
-  try
-    TValue.Make(@pArr,aTypeInfo, Result);
-    rDynArray := ctx.GetType(Result.TypeInfo) as TRTTIDynamicArrayType;
-
-    for i := 0 to aYamlArray.Count - 1 do
-    begin
-      rItemValue := nil;
-      case rType.Kind of
-        tkClass :
-          begin
-            if TYamlPair(aYamlArray.Items[i]).Value is TYamlObject then
-            begin
-              Yaml := TYamlObject(TYamlPair(aYamlArray.Items[i]).value);
-              propObj := GetValue(PPByte(Result.GetReferenceToRawData)^ +rDynArray.ElementType.TypeSize * i, rDynArray.ElementType).AsObject;
-              if propObj = nil then
-              begin
-                objClass := rType.TypeData.ClassType;
-                rItemValue := DeserializeClass(objClass,yaml);
-              end
-              else
-              begin
-                DeserializeObject(propObj,yaml);
-              end;
-            end;
-          end;
-        tkRecord :
-          begin
-            Yaml := TYamlObject(TYamlPair(aYamlArray.Items[i]).value);
-            rItemValue := DeserializeRecord(GetValue(PPByte(Result.GetReferenceToRawData)^ +rDynArray.ElementType.TypeSize * i,
-                                            rDynArray.ElementType),aObject,Yaml);
-          end;
-        tkMethod, tkPointer, tkClassRef ,tkInterface, tkProcedure :
-          begin
-            //skip these properties
-          end
-      else
-        begin
-          rItemValue := DeserializeType(aObject,rType.Kind,aTypeInfo,aYamlArray.Items[i].Value);
-        end;
-      end;
-      if not rItemValue.IsEmpty then Result.SetArrayElement(i,rItemValue);
-    end;
-    //aProperty.SetValue(aObject,rValue);
-  finally
-    DynArrayClear(pArr,aTypeInfo);
-  end;
-end;
-{$ELSE}
-procedure TRTTIYaml.DeserializeDynArray(aTypeInfo: PTypeInfo; const aPropertyName : string; aObject: TObject; const aYamlArray: TYamlArray);
-var
-  rType: PTypeInfo;
-  len: NativeInt;
-  pArr: Pointer;
-  rItemValue: TValue;
-  i: Integer;
-  objClass: TClass;
-  propObj : TObject;
-  rValue : TValue;
-  yaml : TYamlObject;
-begin
-  if GetTypeData(aTypeInfo).ElType2 = nil then Exit;
-  len := aYamlArray.Count;
-  rType := GetTypeData(aTypeInfo).ElType2;
-  pArr := nil;
-  DynArraySetLength(pArr,aTypeInfo, 1, @len);
-  try
-    TValue.Make(@pArr,aTypeInfo, rValue);
-    for i := 0 to aYamlArray.Count - 1 do
-    begin
-      rItemValue := nil;
-      case rType.Kind of
-        tkClass :
-          begin
-            if TYamlPair(aYamlArray.Items[i]).Value is TYamlObject then
-            begin
-              Yaml := TYamlObject(TYamlPair(aYamlArray.Items[i]).value);
-              propObj := GetValue(PPByte(rValue.GetReferenceToRawData)^ +GetTypeData(aTypeInfo).elSize * i, GetTypeData(aTypeInfo).ElType2).AsObject;
-              if propObj = nil then
-              begin
-                //objClass := GetTypeData(aTypeInfo).ClassType;
-                objClass := GetTypeData(GetTypeData(aTypeInfo).ElType2).ClassType;
-                rItemValue := DeserializeClass(objClass,yaml);
-              end
-              else
-              begin
-                DeserializeObject(propObj,yaml);
-              end;
-            end;
-          end;
-        tkRecord :
-          begin
-            {Yaml := TYamlObject(aYamlArray.Items[i]);
-            rItemValue := DeserializeRecord(GetValue(PPByte(Result.GetReferenceToRawData)^ +rDynArray.ElementType.TypeSize * i,
-                                            rDynArray.ElementType),aObject,Yaml);  }
-          end;
-        tkMethod, tkPointer, tkClassRef ,tkInterface, tkProcedure :
-          begin
-            //skip these properties
-          end
-      else
-        begin
-          rItemValue := DeserializeType(aObject,GetTypeData(aTypeInfo).ElType2.Kind,aPropertyName,aYamlArray.Items[i].Value);
-        end;
-      end;
-      if not rItemValue.IsEmpty then rValue.SetArrayElement(i,rItemValue);
-    end;
-    //aProperty.SetValue(aObject,rValue);
-    SetDynArrayProp(aObject,GetPropInfo(aObject,aPropertyName),pArr);
-  finally
-    DynArrayClear(pArr,aTypeInfo);
-  end;
-end;
-{$ENDIF}
-
-{$IFNDEF FPC}
-function TRTTIYaml.DeserializeRecord(aRecord : TValue; aObject : TObject; const aYaml : TYamlObject) : TValue;
-var
-  ctx : TRttiContext;
-  rRec : TRttiRecordType;
-  rField : TRttiField;
-  rValue : TValue;
-  member : TYamlPair;
-  yArray : TYamlArray;
-  Yaml : TYamlObject;
-  objClass : TClass;
-  propobj : TObject;
-begin
-  rRec := ctx.GetType(aRecord.TypeInfo).AsRecord;
-  try
-    for rField in rRec.GetFields do
-    begin
-      rValue := nil;
-      //member := TYamlPair(aYaml.GetValue(rField.Name));
-      member := GetYamlPairByName(aYaml,rField.Name);
-      if member <> nil then
-      case rField.FieldType.TypeKind of
-        tkDynArray :
-          begin
-            yArray := TYamlObject.ParseYamlValue(member.ToYaml) as TYamlArray;
-            try
-              rValue := DeserializeDynArray(rField.FieldType.Handle,aObject,yArray);
-            finally
-              yArray.Free;
-            end;
-          end;
-        tkClass :
-          begin
-            //if (member.YamlValue is TYamlObject) then
-            begin
-              propobj := rField.GetValue(@aRecord).AsObject;
-              Yaml := TYamlObject.ParseYamlValue(member.ToYaml) as TYamlObject;
-              try
-                if propobj = nil then
-                begin
-                  objClass := rField.FieldType.Handle^.TypeData.ClassType;// aProperty.PropertyType.Handle^.TypeData.ClassType;
-                  rValue := DeserializeClass(objClass,Yaml);
-                end
-                else
-                begin
-                  DeserializeObject(propobj,Yaml);
-                end;
-              finally
-                Yaml.Free;
-              end;
-            end
-          end;
-        tkRecord :
-          begin
-            Yaml := TYamlObject.ParseYamlValue(member.ToYaml) as TYamlObject;
-            try
-              rValue := DeserializeRecord(rField.GetValue(aRecord.GetReferenceToRawData),aObject,Yaml);
-            finally
-              Yaml.Free;
-            end;
-          end
-      else
-        begin
-          //rValue := DeserializeType(aObject,rField.FieldType.TypeKind,rField.FieldType.Handle,member.ToYaml);
-          {$IFNDEF FPC}
-          //avoid return unicode escaped chars if string
-          if rField.FieldType.TypeKind in [tkString, tkLString, tkWString, tkUString] then
-            {$IFDEF DELPHIRX103_UP}
-            rValue := DeserializeType(aObject,rField.FieldType.TypeKind,rField.FieldType.Handle,member.Value.AsString)
-            {$ELSE}
-            rValue := DeserializeType(aObject,rField.FieldType.TypeKind,rField.FieldType.Handle,member.YamlString.ToString)
-            {$ENDIF}
-            else rValue := DeserializeType(aObject,rField.FieldType.TypeKind,rField.FieldType.Handle,member.Value.AsString);
-          {$ELSE}
-          rValue := DeserializeType(aObject,rField.FieldType.TypeKind,aName,member.Value.AsString);
-          {$ENDIF}
-        end;
-      end;
-      if not rValue.IsEmpty then rField.SetValue(aRecord.GetReferenceToRawData,rValue);
-    end;
-    Result := aRecord;
-  finally
-    ctx.Free;
-  end;
-end;
-{$ENDIF}
-
-constructor TRTTIYaml.Create(aSerializeLevel : TSerializeLevel; aUseEnumNames : Boolean = True);
-begin
-  fSerializeLevel := aSerializeLevel;
-  fUseEnumNames := aUseEnumNames;
-  fUseYamlCaseSense := False;
-end;
-
-function TRTTIYaml.DeserializeClass(aType: TClass; const aYaml: TYamlObject): TObject;
-begin
-  Result := nil;
-  if (aYaml = nil) or ((aYaml as TYamlValue) is TYamlNull) or (aYaml.Count = 0) then Exit;
-
-  try
-    Result := aType.Create;
-    Result := DeserializeObject(Result,aYaml);
-  except
-    on E : Exception do
-    begin
-      Result.Free;
-      raise EYamlDeserializeError.CreateFmt('Deserialize error class "%s" : %s',[aType.ClassName,e.Message]);
-    end;
-  end;
-end;
-
-function TRTTIYaml.DeserializeObject(aObject: TObject; const aYaml: TYamlObject): TObject;
-var
-  ctx: TRttiContext;
-  rType: TRttiType;
-  rProp: TRttiProperty;
-  {$IFNDEF FPC}
-  attr: TCustomAttribute;
-  {$ENDIF}
-  propertyname : string;
-begin
-  Result := aObject;
-
-  if (aYaml = nil) or ((aYaml as TYamlValue) is TYamlNull) or (aYaml.Count = 0) or (Result = nil) then Exit;
-
-  try
-    rType := ctx.GetType(aObject.ClassInfo);
-    try
-      for rProp in rType.GetProperties do
-      begin
-        {$IFNDEF FPC}
-        if ((fSerializeLevel = slPublicProperty) and (rProp.PropertyType.IsPublicType))
-            or ((fSerializeLevel = slPublishedProperty) and ((IsPublishedProp(aObject,rProp.Name)) or (rProp.Name = 'List'))) then
-        {$ENDIF}
-        begin
-          if ((rProp.IsWritable) or (rProp.Name = 'List')) and (IsAllowedProperty(aObject,rProp.Name)) then
-          begin
-            propertyname := rProp.Name;
-            {$IFNDEF FPC}
-            for attr in rProp.GetAttributes do if attr is TCustomNameProperty then propertyname := TCustomNameProperty(attr).Name;
-            if rProp.Name = 'List' then
-            begin
-              Result := DeserializeList(Result,propertyname,aYaml);
-            end
-            else if (rProp.GetValue(aObject).IsObject) and (IsGenericList(rProp.GetValue(aObject).AsObject)) then
-            begin
-              DeserializeList(rProp.GetValue(aObject).AsObject,'List',TYamlObject(aYaml.GetValue(propertyname)));
-            end
-            else if (not rProp.GetValue(aObject).IsObject) and (IsGenericXArray(rProp.GetValue(aObject){$IFNDEF NEXTGEN}.TypeInfo.Name{$ELSE}.TypeInfo.NameFld.ToString{$ENDIF})) then
-            begin
-              DeserializeXArray(Result,rProp.GetValue(aObject),rProp,propertyname,aYaml);
-            end
-            else
-            {$ENDIF}
-            Result := DeserializeProperty(Result,propertyname,rProp,aYaml);
-          end;
-        end;
-      end;
-    finally
-      ctx.Free;
-    end;
-  except
-    on E : Exception do
-    begin
-      Result.Free;
-      raise EYamlDeserializeError.CreateFmt('Deserialize error for object "%s" : %s',[aObject.ClassName,e.Message]);
-    end;
-  end;
-end;
-
-{$IFNDEF FPC}
-function TRTTIYaml.DeserializeList(aObject: TObject; const aName : string; const aYaml: TYamlObject) : TObject;
-var
-  ctx : TRttiContext;
-  rType : TRttiType;
-  yArray : TYamlArray;
-  member : TYamlPair;
-  rvalue : TValue;
-  i : Integer;
-  rProp : TRttiProperty;
-  {$IFNDEF DELPHIRX103_UP}
-  rfield : TRttiField;
-  {$ENDIF}
-begin
-  Result := aObject;
-
-  rType := ctx.GetType(aObject.ClassInfo);
-  try
-    rProp := rType.GetProperty('List');
-    if rProp = nil then Exit;
-  finally
-    ctx.Free;
-  end;
-  member := GetYamlPairByName(aYaml,aName);
-  //var a := aYaml.ToYaml;
-  if member = nil then yArray := TYamlArray(aYaml) //TYamlObject.ParseYamlValue(aYaml.ToYaml) as TYamlArray
-    else yArray := TYamlObject.ParseYamlValue(member.ToYaml) as TYamlArray;
-
-  rvalue := DeserializeDynArray(rProp.PropertyType.Handle,Result,yArray);
-
-  if not rValue.IsEmpty then
-  begin
-    {$IFDEF DELPHIRX103_UP}
-    if (TObjectList<TObject>(aObject) <> nil) and (rvalue.IsArray) then
-    begin
-      TObjectList<TObject>(aObject).Clear;
-      TObjectList<TObject>(aObject).Capacity := rvalue.GetArrayLength;
-      for i := 0 to rvalue.GetArrayLength - 1 do
-      begin
-        TObjectList<TObject>(aObject).Add(rvalue.GetArrayElement(i).AsObject);
-      end;
-    end;
-    {$ELSE}
-    for rfield in rType.GetFields do
-    begin
-      if rfield.Name = 'FOwnsObjects' then rfield.SetValue(aObject,True);
-      //if rfield.Name = 'FCount' then rfield.SetValue(aObject,i);
-      if rfield.Name = 'FItems' then
-      begin
-        //if TList(aObject) <> nil then TList(aObject).Clear;
-        //rfield.GetValue(aObject).AsObject.Free;// aValue.GetReferenceToRawData)
-        rfield.SetValue(aObject,rValue);// .SetDynArrayProp(aObject,'fItems',Result);
-        Break;
-      end;
-    end;
-    rProp := rType.GetProperty('Count');
-    rProp.SetValue(aObject,i);
-    {$ENDIF}
-  end;
-end;
-{$ENDIF}
-
-{$IFNDEF FPC}
-procedure TRTTIYaml.DeserializeXArray(Instance : TObject; aRecord : TValue; aProperty : TRttiProperty; const aPropertyName : string; aYaml : TYamlObject);
-var
-  ctx : TRttiContext;
-  rRec : TRttiRecordType;
-  rfield : TRttiField;
-  rValue : TValue;
-  member : TYamlPair;
-  yArray : TYamlArray;
-begin
-  rRec := ctx.GetType(aRecord.TypeInfo).AsRecord;
-  try
-    rfield := rRec.GetField('fArray');
-    if rfield <> nil then
-    begin
-      rValue := nil;
-      //member := TYamlPair(aYaml.GetValue(rField.Name));
-      member := GetYamlPairByName(aYaml,aPropertyName);
-      if (member <> nil) and (rField.FieldType.TypeKind = tkDynArray) then
-      begin
-        yArray := TYamlObject.ParseYamlValue(member.ToYaml) as TYamlArray;
-        try
-          rValue := DeserializeDynArray(rField.FieldType.Handle,nil,yArray);
-        finally
-          yArray.Free;
-        end;
-      end;
-    end;
-    if not rValue.IsEmpty then rField.SetValue(aRecord.GetReferenceToRawData,rValue);
-    aProperty.SetValue(Instance,aRecord);
-  finally
-    ctx.Free;
-  end;
-end;
-{$ENDIF}
-
-function TRTTIYaml.DeserializeProperty(aObject : TObject; const aName : string; aProperty : TRttiProperty; const aYaml : TYamlObject) : TObject;
-var
-  rValue : TValue;
-  member : TYamlPair;
-  objClass: TClass;
-  yArray : TYamlArray;
-  Yaml : TYamlObject;
-begin
-    Result := aObject;
-    rValue := nil;
-    //member := TYamlPair(aYaml.GetValue(aName));
-    member := GetYamlPairByName(aYaml,aName);
-    if member <> nil then
-    begin
-      case aProperty.PropertyType.TypeKind of
-        tkDynArray :
-          begin
-            yArray := member.Value as TYamlArray;
-            {$IFNDEF FPC}
-            aProperty.SetValue(aObject,DeserializeDynArray(aProperty.PropertyType.Handle,Result,yArray));
-            {$ELSE}
-            DeserializeDynArray(aProperty.PropertyType.Handle,aName,Result,yArray);
-            {$ENDIF}
-            Exit;
-          end;
-        tkClass :
-          begin
-            //if (member.YamlValue is TYamlObject) then
-            begin
-              Yaml := TYamlObject(TYamlObject.ParseYamlValue(member.ToYaml));
-              try
-                if aProperty.GetValue(aObject).AsObject = nil then
-                begin
-                  {$IFNDEF FPC}
-                  objClass := aProperty.PropertyType.Handle^.TypeData.ClassType;
-                  rValue := DeserializeClass(objClass,Yaml);
-                  {$ELSE}
-                  objClass := GetObjectPropClass(aObject,aName);
-                  //objClass := GetTypeData(aProperty.PropertyType.Handle)^.ClassType;
-                  rValue := DeserializeClass(objClass,Yaml);
-                  SetObjectProp(aObject,aName,rValue.AsObject);
-                  Exit;
-                  {$ENDIF}
-                end
-                else
-                begin
-                  rValue := DeserializeObject(aProperty.GetValue(aObject).AsObject,Yaml);
-                  Exit;
-                end;
-              finally
-                Yaml.Free;
-              end;
-            end
-          end;
-        {$IFNDEF FPC}
-        tkRecord :
-          begin
-            Yaml := TYamlObject.ParseYamlValue(member.ToYaml) as TYamlObject;
-            try
-              rValue := DeserializeRecord(aProperty.GetValue(aObject),aObject,Yaml);
-            finally
-              Yaml.Free;
-            end;
-          end;
-        tkSet :
-          begin
-            rValue := DeserializeType(aObject,aProperty.PropertyType.TypeKind,aProperty.GetValue(aObject).TypeInfo,member.ToYaml)
-          end
-        {$ENDIF}
-      else
-        begin
-          {$IFNDEF FPC}
-          //avoid return unicode escaped chars if string
-          if aProperty.PropertyType.TypeKind in [tkString, tkLString, tkWString, tkUString] then
-            {$IFDEF DELPHIRX103_UP}
-            rValue := DeserializeType(aObject,aProperty.PropertyType.TypeKind,aProperty.GetValue(aObject).TypeInfo,member.Value.AsString)
-            {$ELSE}
-            rValue := DeserializeType(aObject,aProperty.PropertyType.TypeKind,aProperty.GetValue(aObject).TypeInfo,member.YamlString.ToString)
-            {$ENDIF}
-          else rValue := DeserializeType(aObject,aProperty.PropertyType.TypeKind,aProperty.GetValue(aObject).TypeInfo,member.Value.AsString);
-          {$ELSE}
-          rValue := DeserializeType(aObject,aProperty.PropertyType.TypeKind,aName,member.Value.AsString);
-          if not rValue.IsEmpty then SetPropertyValue(aObject,aName,rValue);
-          {$ENDIF}
-        end;
-      end;
-      {$IFNDEF FPC}
-      if not rValue.IsEmpty then aProperty.SetValue(Result,rValue);
-      {$ENDIF}
-    end;
-end;
-
-{$IFNDEF FPC}
-function TRTTIYaml.DeserializeType(aObject : TObject; aType : TTypeKind; aTypeInfo : PTypeInfo; const aValue: string) : TValue;
-var
-  i : Integer;
-  value : string;
-  fsettings : TFormatSettings;
-begin
-  try
-    value := AnsiDequotedStr(aValue,'"');
-    case aType of
-      tkString, tkLString, tkWString, tkUString :
-        begin
-          Result := value;
-        end;
-      tkChar, tkWChar :
-        begin
-          Result := value;
-        end;
-      tkInteger :
-        begin
-          Result := StrToInt(value);
-        end;
-      tkInt64 :
-        begin
-          Result := StrToInt64(value);
-        end;
-      tkFloat :
-        begin
-          if aTypeInfo = TypeInfo(TDateTime) then
-          begin
-            if CompareText(value,'null') <> 0 then Result := JsonDateToDateTime(value);
-          end
-          else if aTypeInfo = TypeInfo(TDate) then
-          begin
-            if CompareText(value,'null') <> 0 then Result := StrToDate(value);
-          end
-          else if aTypeInfo = TypeInfo(TTime) then
-          begin
-            Result := StrToTime(value);
-          end
-          else
-          begin
-            fsettings := TFormatSettings.Create;
-            Result := StrToFloat(StringReplace(value,'.',fsettings.DecimalSeparator,[]));
-          end;
-        end;
-      tkEnumeration :
-        begin
-          if aTypeInfo = System.TypeInfo(Boolean) then
-          begin
-            Result := StrToBool(value);
-          end
-          else
-          begin
-            //if fUseEnumNames then TValue.Make(GetEnumValue(aTypeInfo,value),aTypeInfo, Result)
-            //  else TValue.Make(StrToInt(value),aTypeInfo, Result);
-            if not TryStrToInt(value,i) then TValue.Make(GetEnumValue(aTypeInfo,value),aTypeInfo, Result)
-              else TValue.Make(StrToInt(value),aTypeInfo, Result);
-          end;
-        end;
-      tkSet :
-        begin
-          i := StringToSet(aTypeInfo,value);
-          TValue.Make(@i,aTypeInfo,Result);
-        end;
-    else
-        begin
-          //raise EclYamlSerializerError.Create('Not supported data type!');
-        end;
-    end;
-  except
-    on E : Exception do
-    begin
-      raise EYamlDeserializeError.CreateFmt('Deserialize error type "%s.%s" : %s',[aObject.ClassName,GetTypeName(aTypeInfo),e.Message]);
-    end;
-  end;
-end;
-{$ELSE}
-function TRTTIYaml.DeserializeType(aObject : TObject; aType : TTypeKind; const aPropertyName, aValue: string) : TValue;
-var
-  value : string;
-  propinfo : PPropInfo;
-  fsettings : TFormatSettings;
-begin
-  try
-    value := AnsiDequotedStr(aValue,'"');
-
-    if value = '' then
-    begin
-      Result := nil;
-      Exit;
-    end;
-    propinfo := GetPropInfo(aObject,aPropertyName);
-    //case propinfo.PropType.Kind of
-    case aType of
-      tkString, tkLString, tkWString, tkUString, tkAString :
-        begin
-          Result := value;
-          //SetStrProp(aObject,propinfo,value);
-        end;
-      tkChar, tkWChar :
-        begin
-          Result := value;
-        end;
-      tkInteger :
-        begin
-          Result := StrToInt(value);
-        end;
-      tkInt64 :
-        begin
-          Result := StrToInt64(value);
-        end;
-      tkFloat :
-        begin
-          if propinfo.PropType = TypeInfo(TDateTime) then
-          begin
-            if CompareText(value,'null') <> 0  then Result := JsonDateToDateTime(value);
-          end
-          else if propinfo.PropType = TypeInfo(TDate) then
-          begin
-            if CompareText(value,'null') <> 0 then Result := StrToDate(value);
-          end
-          else if propinfo.PropType = TypeInfo(TTime) then
-          begin
-            Result := StrToTime(value);
-          end
-          else
-          begin
-            fsettings := DefaultFormatSettings;
-            Result := StrToFloat(StringReplace(value,'.',fsettings.DecimalSeparator,[]));
-          end;
-        end;
-      tkEnumeration:
-        begin
-          Result := value;
-        end;
-      tkBool :
-          begin
-            Result := StrToBool(value);
-          end;
-      tkSet :
-        begin
-          Result := value;
-        end;
-    else
-        begin
-          //raise EclYamlSerializerError.Create('Not supported data type!');
-        end;
-    end;
-    //if not Result.IsEmpty then SetPropertyValue(aObject,propinfo,Result);
-  except
-    on E : Exception do
-    begin
-      raise EYamlDeserializeError.CreateFmt('Deserialize error type "%s" : %s',[aObject.ClassName,e.Message]);
-    end;
-  end;
-end;
-{$ENDIF}
-
-function TRTTIYaml.IsAllowedProperty(aObject : TObject; const aPropertyName : string) : Boolean;
-var
-  propname : string;
-begin
-  Result := True;
-  propname := aPropertyName.ToLower;
-  if IsGenericList(aObject) then
-  begin
-    if (propname = 'capacity') or (propname = 'count') or (propname = 'ownsobjects') then Result := False;
-  end
-  else if (propname = 'refcount') then Result := False;
-end;
-
-function TRTTIYaml.IsGenericList(aObject : TObject) : Boolean;
-var
-  cname : string;
-begin
-  if aObject = nil then Exit(False);
-
-  cname := aObject.ClassName;
-  Result := (cname.StartsWith('TObjectList')) or (cname.StartsWith('TList'));
-end;
-
-function TRTTIYaml.IsGenericXArray(const aClassName : string) : Boolean;
-begin
-  Result := aClassName.StartsWith('TXArray');
-end;
-
-function TRTTIYaml.GetYamlPairByName(aYaml: TYamlObject; const aName: string): TYamlPair;
-var
-  candidate : TYamlPair;
-  yvalue : TYamlValue;
-  i : Integer;
-begin
-  if fUseYamlCaseSense then
-  begin
-    yvalue := aYaml.GetValue(aName);
-    if yvalue <> nil then Result := TYamlPair(yvalue);
-    Exit;
-  end
-  else
-  begin
-    if aYaml <> nil then
-    for i := 0 to aYaml.Count - 1 do
-    begin
-      candidate := aYaml.Pairs[I];
-      if (candidate = nil) or (candidate.Value = nil) then Exit(nil);
-      if CompareText(candidate.Name,aName) = 0 then
-        Exit(candidate);
-    end;
-  end;
-  Result := nil;
-end;
-
-function TRTTIYaml.GetPropertyValue(Instance : TObject; const PropertyName : string) : TValue;
-var
-  pinfo : PPropInfo;
-begin
-  Result := nil;
-  pinfo := GetPropInfo(Instance,PropertyName);
-  case pinfo.PropType^.Kind of
-    tkInteger : Result := GetOrdProp(Instance,pinfo);
-    tkInt64 : Result := GetInt64Prop(Instance,PropertyName);
-    tkFloat : Result := GetFloatProp(Instance,PropertyName);
-    tkChar : Result := Char(GetOrdProp(Instance,PropertyName));
-    {$IFDEF FPC}
-    tkWString : Result := GetWideStrProp(Instance,PropertyName);
-    tkSString,
-    tkAString,
-    {$ELSE}
-    tkWString,
-    {$ENDIF}
-    tkLString : Result := GetStrProp(Instance,pinfo);
-    {$IFDEF FPC}
-    tkEnumeration :
-      begin
-        if fUseEnumNames then Result := GetEnumName(pinfo.PropType,GetOrdProp(Instance,PropertyName))
-          else Result := GetOrdProp(Instance,PropertyName);
-      end;
-    {$ELSE}
-    tkEnumeration :
-      begin
-        if fUseEnumNames then Result := GetEnumName(@pinfo.PropType,GetOrdProp(Instance,PropertyName))
-          else Result := GetOrdProp(Instance,PropertyName);
-      end;
-    {$ENDIF}
-    tkSet : Result := GetSetProp(Instance,pinfo,True);
-    {$IFNDEF FPC}
-    tkClass :
-    {$ELSE}
-    tkBool : Result := Boolean(GetOrdProp(Instance,pinfo));
-    tkObject :
-    {$ENDIF} Result := GetObjectProp(Instance,pinfo);
-    tkDynArray : Result := GetDynArrayProp(Instance,pinfo);
-  end;
-end;
-
-function TRTTIYaml.GetPropertyValueFromObject(Instance : TObject; const PropertyName : string) : TValue;
-var
-  ctx : TRttiContext;
-  rprop : TRttiProperty;
-begin
-  rprop := ctx.GetType(Instance.ClassInfo).GetProperty(PropertyName);
-  Result := rprop.GetValue(Instance);
-end;
-
-{$IFNDEF FPC}
-function TRTTIYaml.GetFieldValueFromRecord(aValue : TValue; const FieldName : string) : TValue;
-var
-  ctx : TRttiContext;
-  rec : TRttiRecordType;
-  rfield : TRttiField;
-begin
-  rec := ctx.GetType(aValue.TypeInfo).AsRecord;
-  rfield := rec.GetField(FieldName);
-  if rfield <> nil then Result := rField.GetValue(aValue.GetReferenceToRawData)
-    else Result := nil;
-end;
-{$ENDIF}
-
-procedure TRTTIYaml.SetPropertyValue(Instance : TObject; const PropertyName : string; aValue : TValue);
-var
-  pinfo : PPropInfo;
-begin
-  pinfo := GetPropInfo(Instance,PropertyName);
-  SetPropertyValue(Instance,pinfo,aValue);
-end;
-
-procedure TRTTIYaml.SetPropertyValue(Instance : TObject; aPropInfo : PPropInfo; aValue : TValue);
-begin
-  case aPropInfo.PropType^.Kind of
-    tkInteger : SetOrdProp(Instance,aPropInfo,aValue.AsInteger);
-    tkInt64 : SetInt64Prop(Instance,aPropInfo,aValue.AsInt64);
-    tkFloat : SetFloatProp(Instance,aPropInfo,aValue.AsExtended);
-    tkChar : SetOrdProp(Instance,aPropInfo,aValue.AsOrdinal);
-    {$IFDEF FPC}
-    tkWString : SetWideStrProp(Instance,aPropInfo,aValue.AsString);
-    tkSString,
-    tkAString,
-    {$ELSE}
-    tkWString,
-    {$ENDIF}
-    tkLString : SetStrProp(Instance,aPropInfo,aValue.AsString);
-    {$IFDEF FPC}
-    tkBool : SetOrdProp(Instance,aPropInfo,aValue.AsOrdinal);
-    tkSet : LoadSetProperty(Instance,aPropInfo,aValue.AsString);
-    {$ENDIF}
-    tkEnumeration : SetEnumProp(Instance,aPropInfo,aValue.AsString);
-    {$IFNDEF FPC}
-    tkClass :
-    {$ELSE}
-    tkObject :
-    {$ENDIF} SetObjectProp(Instance,aPropInfo,aValue.AsObject);
-  end;
-end;
-
-{$IFDEF FPC}
-procedure TRTTIYaml.LoadSetProperty(aInstance : TObject; aPropInfo: PPropInfo; const aValue: string);
-type
-  TCardinalSet = set of 0..SizeOf(Cardinal) * 8 - 1;
-const
-  Delims = [' ', ',', '[', ']'];
-var
-  TypeInfo: PTypeInfo;
-  W: Cardinal;
-  I, N: Integer;
-  Count: Integer;
-  EnumName: string;
-begin
-  W := 0;
-  TypeInfo := GetTypeData(GetPropType(aPropInfo))^.CompType;
-  Count := WordCount(aValue, Delims);
-  for N := 1 to Count do
-  begin
-    EnumName := ExtractWord(N, aValue, Delims);
-    try
-      I := GetEnumValue(TypeInfo, EnumName);
-      if I >= 0 then Include(TCardinalSet(W),I);
-    except
-    end;
-  end;
-  SetOrdProp(aInstance,aPropInfo,W);
-end;
-{$ENDIF}
-
-function TRTTIYaml.Serialize(aObject: TObject): TYamlObject;
-var
-  ctx: TRttiContext;
-  {$IFNDEF FPC}
-  attr : TCustomAttribute;
-  comment : string;
-  {$ENDIF}
-  rType: TRttiType;
-  rProp: TRttiProperty;
-  ypair : TYamlPair;
-  ExcludeSerialize : Boolean;
-  propertyname : string;
-begin
-  if (aObject = nil) then
-  begin
-    Result := nil;
-    Exit;
-  end;
-
-  Result := TYamlObject.Create;
-  try
-    rType := ctx.GetType(aObject.ClassInfo);
-    try
-      //s := rType.ToString;
-      for rProp in TRTTI.GetProperties(rType,roFirstBase) do
-      begin
-        ExcludeSerialize := False;
-        propertyname := rProp.Name;
-        {$IFNDEF FPC}
-        comment := '';
-        for attr in rProp.GetAttributes do
-        begin
-          if attr is TNotSerializableProperty then ExcludeSerialize := True
-          else if attr is TCommentProperty then comment := TCommentProperty(attr).Comment
-          else if  attr is TCustomNameProperty then propertyname := TCustomNameProperty(attr).Name;
-        end;
-        if ((fSerializeLevel = slPublicProperty) and (rProp.PropertyType.IsPublicType))
-            or ((fSerializeLevel = slPublishedProperty) and ((IsPublishedProp(aObject,rProp.Name)) or (rProp.Name = 'List'))) then
-        {$ENDIF}
-        begin
-          if (IsAllowedProperty(aObject,propertyname)) and (not ExcludeSerialize) then
-          begin
-            //add comment as pair
-            {$IFNDEF FPC}
-            if comment <> '' then Result.AddPair(TYamlPair.Create('#',TYamlComment.Create(Comment)));
-            {$ENDIF}
-            begin
-              if (rProp.GetValue(aObject).IsObject) and (IsGenericList(rProp.GetValue(aObject).AsObject)) then
-              begin
-                ypair := Serialize(propertyname,GetPropertyValueFromObject(rProp.GetValue(aObject).AsObject,'List'));
-              end
-              {$IFNDEF FPC}
-              else if (not rProp.GetValue(aObject).IsObject) and (IsGenericXArray(rProp.GetValue(aObject){$IFNDEF NEXTGEN}.TypeInfo.Name{$ELSE}.TypeInfo.NameFld.ToString{$ENDIF})) then
-              begin
-                ypair := Serialize(propertyname,GetFieldValueFromRecord(rProp.GetValue(aObject),'fArray'));
-              end
-              {$ENDIF}
-              else
-              begin
-                {$IFNDEF FPC}
-                ypair := Serialize(propertyname,rProp.GetValue(aObject));
-                {$ELSE}
-                ypair := Serialize(aObject,rProp.PropertyType.TypeKind,propertyname);
-                {$ENDIF}
-              end;
-              //s := jpair.YamlValue.ToString;
-              if ypair <> nil then
-              begin
-                Result.AddPair(ypair);
-              end
-              else ypair.Free;
-            end;
-            //Result.AddPair(Serialize(rProp.Name,rProp.GetValue(aObject)));
-            //s := Result.ToYaml;
-          end;
-        end;
-      end;
-    finally
-      ctx.Free;
-    end;
-  except
-    on E : Exception do
-    begin
-      Result.Free;
-      raise EYamlSerializeError.CreateFmt('Serialize error object "%s" : %s',[aObject.ClassName,e.Message]);
-    end;
-  end;
-end;
-
-function TRTTIYaml.GetValue(aAddr: Pointer; aType: TRTTIType): TValue;
-begin
-  TValue.Make(aAddr,aType.Handle,Result);
-end;
-
-function TRTTIYaml.GetValue(aAddr: Pointer; aTypeInfo: PTypeInfo): TValue;
-begin
-  TValue.Make(aAddr,aTypeInfo,Result);
-end;
-
-{$IFNDEF FPC}
-function TRTTIYaml.Serialize(const aName : string; aValue : TValue) : TYamlPair;
-var
-  ctx: TRttiContext;
-  rRec : TRttiRecordType;
-  rField : TRttiField;
-  rDynArray : TRTTIDynamicArrayType;
-  Yaml : TYamlObject;
-  yArray : TYamlArray;
-  ypair : TYamlPair;
-  yvalue : TYamlValue;
-  i : Integer;
-begin
-  Result := TYamlPair.Create(aName,nil);
-  //Result.YamlString := TYamlString(aName);
-  try
-    case avalue.Kind of
-      tkDynArray :
-        begin
-          yArray := TYamlArray.Create;
-          rDynArray := ctx.GetType(aValue.TypeInfo) as TRTTIDynamicArrayType;
-          try
-            for i := 0 to aValue.GetArrayLength - 1 do
-            begin
-              if not GetValue(PPByte(aValue.GetReferenceToRawData)^ + rDynArray.ElementType.TypeSize * i, rDynArray.ElementType).IsEmpty then
-              begin
-                yvalue := nil;
-                ypair := Serialize(aName,GetValue(PPByte(aValue.GetReferenceToRawData)^ + rDynArray.ElementType.TypeSize * i, rDynArray.ElementType));
-                try
-                  //jValue := TYamlValue(jPair.YamlValue.Clone);
-                  yvalue := ypair.Value;
-                  if yvalue <> nil then
-                  begin
-                    yArray.AddElement(yvalue);
-                    ypair.Value.Owned := False;
-                  end;
-                finally
-                  ypair.Free;
-                  if yvalue <> nil then yvalue.Owned := True;
-                end;
-              end;
-            end;
-            Result.Value := yArray;
-          finally
-            ctx.Free;
-          end;
-        end;
-      tkClass :
-        begin
-           Result.Value := TYamlValue(Serialize(aValue.AsObject));
-        end;
-      tkString, tkLString, tkWString, tkUString :
-        begin
-          Result.Value := TYamlString.Create(aValue.AsString);
-        end;
-      tkChar, tkWChar :
-        begin
-          Result.Value := TYamlString.Create(aValue.AsString);
-        end;
-      tkInteger :
-        begin
-          Result.Value := TYamlInteger.Create(aValue.AsInteger);
-        end;
-      tkInt64 :
-        begin
-          Result.Value := TYamlInteger.Create(aValue.AsInt64);
-        end;
-      tkFloat :
-        begin
-          if aValue.TypeInfo = TypeInfo(TDateTime) then
-          begin
-            if aValue.AsExtended <> 0.0 then Result.Value := TYamlString.Create(DateTimeToJsonDate(aValue.AsExtended));
-          end
-          else if aValue.TypeInfo = TypeInfo(TDate) then
-          begin
-            if aValue.AsExtended <> 0.0 then Result.Value := TYamlString.Create(DateToStr(aValue.AsExtended));
-          end
-          else if aValue.TypeInfo = TypeInfo(TTime) then
-          begin
-            Result.Value := TYamlString.Create(TimeToStr(aValue.AsExtended));
-          end
-          else
-          begin
-            Result.Value := TYamlFloat.Create(aValue.AsExtended);
-          end;
-        end;
-      tkEnumeration :
-        begin
-          if (aValue.TypeInfo = System.TypeInfo(Boolean)) then
-          begin
-            Result.Value := TYamlBoolean.Create(aValue.AsBoolean);
-          end
-          else
-          begin
-            //Result.YamlValue := TYamlString.Create(GetEnumName(aValue.TypeInfo,aValue.AsOrdinal));
-            if fUseEnumNames then Result.Value := TYamlString.Create(aValue.ToString)
-              else Result.Value := TYamlInteger.Create(GetEnumValue(aValue.TypeInfo,aValue.ToString));
-          end;
-        end;
-      tkSet :
-        begin
-          Result.Value := TYamlString.Create(aValue.ToString);
-        end;
-      tkRecord :
-        begin
-          rRec := ctx.GetType(aValue.TypeInfo).AsRecord;
-          try
-            Yaml := TYamlObject.Create;
-            for rField in rRec.GetFields do
-            begin
-              Yaml.AddPair(Serialize(rField.name,rField.GetValue(aValue.GetReferenceToRawData)));
-            end;
-            Result.Value := Yaml;
-          finally
-            ctx.Free;
-          end;
-        end;
-      tkMethod, tkPointer, tkClassRef ,tkInterface, tkProcedure :
-        begin
-          //skip these properties
-          //FreeAndNil(Result);
-        end
-    else
-      begin
-        raise EYamlSerializeError.CreateFmt(cNotSupportedDataType,[aName,GetTypeName(aValue.TypeInfo)]);
-      end;
-    end;
-    if Result.Value = nil then Result.Value := TYamlNull.Create;
-  except
-    on E : Exception do
-    begin
-      Result.Free;
-      raise EYamlSerializeError.CreateFmt('Serialize error class "%s.%s" : %s',[aName,aValue.ToString,e.Message]);
-    end;
-  end;
-end;
-{$ELSE}
-function TRTTIYaml.GetPropType(aPropInfo: PPropInfo): PTypeInfo;
-begin
-  Result := aPropInfo^.PropType;
-end;
-
-function TRTTIYaml.FloatProperty(aObject : TObject; aPropInfo: PPropInfo): string;
-const
-  Precisions: array[TFloatType] of Integer = (7, 15, 18, 18, 19);
-var
-  fsettings : TFormatSettings;
-begin
-  fsettings := FormatSettings;
-  Result := StringReplace(FloatToStrF(GetFloatProp(aObject, aPropInfo), ffGeneral,
-    Precisions[GetTypeData(GetPropType(aPropInfo))^.FloatType],0),
-    '.',fsettings.DecimalSeparator,[rfReplaceAll]);
-end;
-
-function TRTTIYaml.Serialize(const aName : string; aValue : TValue) : TYamlPair;
-begin
-  Result := TYamlPair.Create(aName,nil);
-  //Result.YamlString := TYamlString(aName);
-  try
-    case avalue.Kind of
-      tkClass :
-        begin
-           Result.Value := TYamlValue(Serialize(aValue.AsObject));
-        end;
-      tkString, tkLString, tkWString, tkUString :
-        begin
-          Result.Value := TYamlString.Create(aValue.AsString);
-        end;
-      tkChar, tkWChar :
-        begin
-          Result.Value := TYamlString.Create(aValue.AsString);
-        end;
-      tkInteger :
-        begin
-          Result.Value := TYamlInteger.Create(aValue.AsInteger);
-        end;
-      tkInt64 :
-        begin
-          Result.Value := TYamlInteger.Create(aValue.AsInt64);
-        end;
-      tkFloat :
-        begin
-          if aValue.TypeInfo = TypeInfo(TDateTime) then
-          begin
-            if aValue.AsExtended <> 0.0 then Result.Value := TYamlString.Create(DateTimeToJsonDate(aValue.AsExtended));
-          end
-          else if aValue.TypeInfo = TypeInfo(TDate) then
-          begin
-            if aValue.AsExtended <> 0.0 then Result.Value := TYamlString.Create(DateToStr(aValue.AsExtended));
-          end
-          else if aValue.TypeInfo = TypeInfo(TTime) then
-          begin
-            Result.Value := TYamlString.Create(TimeToStr(aValue.AsExtended));
-          end
-          else
-          begin
-            Result.Value := TYamlFloat.Create(aValue.AsExtended);
-          end;
-        end;
-      tkEnumeration :
-        begin
-          if (aValue.TypeInfo = System.TypeInfo(Boolean)) then
-          begin
-            Result.Value := TYamlBoolean.Create(aValue.AsBoolean);
-          end
-          else
-          begin
-            //Result.YamlValue := TYamlString.Create(GetEnumName(aValue.TypeInfo,aValue.AsOrdinal));
-            if fUseEnumNames then Result.Value := TYamlString.Create(aValue.ToString)
-              else Result.Value := TYamlInteger.Create(GetEnumValue(aValue.TypeInfo,aValue.ToString));
-          end;
-        end;
-      tkSet :
-        begin
-          Result.Value := TYamlString.Create(aValue.ToString);
-        end;
-    else
-      begin
-        //raise EYamlDeserializeError.CreateFmt('Not supported type "%s":%d',[aName,Integer(aValue.Kind)]);
-      end;
-    end;
-    if Result.Value = nil then Result.Value := TYamlNull.Create;
-  except
-    Result.Free;
-  end;
-end;
-
-function TRTTIYaml.Serialize(aObject : TObject; aType : TTypeKind; const aPropertyName : string) : TYamlPair;
-var
-  propinfo : PPropInfo;
-  yArray : TYamlArray;
-  ypair : TYamlPair;
-  yvalue : TYamlValue;
-  i : Integer;
-  pArr : Pointer;
-  rValue : TValue;
-  rItemValue : TValue;
-  len : Integer;
-begin
-  try
-    Result := TYamlPair.Create(aPropertyName,nil);
-
-    propinfo := GetPropInfo(aObject,aPropertyName);
-    //case propinfo.PropType.Kind of
-    case aType of
-      tkDynArray :
-        begin
-          len := 0;
-          yArray := TYamlArray.Create;
-          try
-            pArr := GetDynArrayProp(aObject,aPropertyName);
-            TValue.Make(@pArr,propinfo.PropType, rValue);
-            if rValue.IsArray then
-            begin
-              len := rValue.GetArrayLength;
-              for i := 0 to len - 1 do
-              begin
-                rItemValue := rValue.GetArrayElement(i);
-                ypair := Serialize(aPropertyName,rItemValue);
-                try
-                  //jValue := TYamlValue(jPair.YamlValue.Clone);
-                  yvalue := ypair.Value;
-                  yArray.AddElement(yvalue);
-                  //jPair.YamlValue.Owned := False;
-                finally
-                  ypair.Free;
-                  //jValue.Owned := True;
-                end;
-              end;
-            end;
-            Result.Value := yArray;
-          finally
-            //DynArrayClear(pArr,propinfo.PropType);
-            pArr := nil;
-          end;
-        end;
-      tkClass :
-        begin
-          Result.Value := TYamlValue(Serialize(GetObjectProp(aObject,aPropertyName)));
-        end;
-      tkString, tkLString, tkWString, tkUString, tkAString :
-        begin
-          Result.Value := TYamlString.Create(GetStrProp(aObject,aPropertyName));
-        end;
-      tkChar, tkWChar :
-        begin
-          Result.Value := TYamlString.Create(Char(GetOrdProp(aObject,aPropertyName)));
-        end;
-      tkInteger :
-        begin
-          Result.Value := TYamlInteger.Create(GetOrdProp(aObject,aPropertyName));
-        end;
-      tkInt64 :
-        begin
-          Result.Value := TYamlInteger.Create(GetOrdProp(aObject,aPropertyName));
-        end;
-      tkFloat :
-        begin
-          if propinfo.PropType = TypeInfo(TDateTime) then
-          begin
-            if aValue.AsExtended <> 0.0 then Result.Value := TYamlString.Create(DateTimeToJsonDate(GetFloatProp(aObject,aPropertyName)));
-          end
-          else if propinfo.PropType = TypeInfo(TDate) then
-          begin
-            if aValue.AsExtended <> 0.0 then Result.Value := TYamlString.Create(DateToStr(GetFloatProp(aObject,aPropertyName)));
-          end
-          else if propinfo.PropType = TypeInfo(TTime) then
-          begin
-            Result.Value := TYamlString.Create(TimeToStr(GetFloatProp(aObject,aPropertyName)));
-          end
-          else
-          begin
-            //Result.YamlValue := TYamlFloatNumber.Create(GetFloatProp(aObject,aPropertyName));
-            Result.Value := TYamlFloat.Create(StrToFloat(FloatProperty(aObject,propinfo)));
-          end;
-        end;
-      tkEnumeration,tkBool :
-        begin
-          if (propinfo.PropType = System.TypeInfo(Boolean)) then
-          begin
-            Result.Value := TYamlBoolean.Create(Boolean(GetOrdProp(aObject,aPropertyName)));
-          end
-          else
-          begin
-            if fUseEnumNames then Result.Value := TYamlString.Create(GetEnumName(propinfo.PropType,GetOrdProp(aObject,aPropertyName)))
-              else Result.Value := TYamlInteger.Create(GetOrdProp(aObject,aPropertyName));
-            //Result.YamlValue := TYamlString.Create(aValue.ToString);
-          end;
-        end;
-      tkSet :
-        begin
-          Result.Value := TYamlString.Create(GetSetProp(aObject,aPropertyName));
-        end;
-      {$IFNDEF FPC}
-      tkRecord :
-        begin
-          rRec := ctx.GetType(aValue.TypeInfo).AsRecord;
-          try
-            Yaml := TYamlObject.Create;
-            for rField in rRec.GetFields do
-            begin
-              Yaml.AddPair(Serialize(rField.name,rField.GetValue(aValue.GetReferenceToRawData)));
-            end;
-            Result.YamlValue := Yaml;
-          finally
-            ctx.Free;
-          end;
-        end;
-      {$ENDIF}
-      tkMethod, tkPointer, tkClassRef ,tkInterface, tkProcedure :
-        begin
-          //skip these properties
-          //FreeAndNil(Result);
-        end
-    else
-      begin
-
-        //raise EYamlDeserializeError.CreateFmt('Not supported type "%s":%d',[aName,Integer(aValue.Kind)]);
-      end;
-    end;
-    if Result.Value = nil then Result.Value := TYamlNull.Create;
-  except
-    on E : Exception do
-    begin
-      Result.Free;
-      {$IFNDEF FPC}
-      raise EYamlSerializeError.CreateFmt('Serialize error class "%s.%s" : %s',[aName,aValue.ToString,e.Message]);
-      {$ENDIF}
-    end;
-  end;
-end;
-{$ENDIF}
-
-
-{ TYamlSerializer}
-
-constructor TYamlSerializer.Create(aSerializeLevel: TSerializeLevel; aUseEnumNames : Boolean = True);
-begin
-  {$IFDEF FPC}
-  if aSerializeLevel = TSerializeLevel.slPublicProperty then raise EYamlSerializeError.Create('FreePascal RTTI only supports published properties');
-  {$ENDIF}
-  fSerializeLevel := aSerializeLevel;
-  fUseEnumNames := aUseEnumNames;
-  fUseYamlCaseSense := False;
-  fRTTIYaml := TRTTIYaml.Create(aSerializeLevel,aUseEnumNames);
-  fRTTIYaml.UseYamlCaseSense := fUseYamlCaseSense;
-end;
-
-function TYamlSerializer.YamlToObject(aType: TClass; const aYaml: string): TObject;
-var
-  Yaml: TYamlObject;
-begin
-  Yaml := TYamlObject.ParseYamlValue(aYaml) as TYamlObject;
-  try
-    Result := fRTTIYaml.DeserializeClass(aType,Yaml);
-  finally
-    Yaml.Free;
-  end;
-end;
-
-destructor TYamlSerializer.Destroy;
-begin
-  fRTTIYaml.Free;
-  inherited;
-end;
-
-function TYamlSerializer.YamlToObject(aObject: TObject; const aYaml: string): TObject;
-var
-  Yaml: TYamlObject;
-begin
-  Result := aObject;
-  Yaml := TYamlObject(TYamlObject.ParseYamlValue(aYaml));
-  try
-    fRTTIYaml.DeserializeObject(aObject,Yaml);
-  finally
-    Yaml.Free;
-  end;
-end;
-
-function TYamlSerializer.ObjectToYaml(aObject : TObject): string;
-var
-  Yaml: TYamlObject;
-begin
-  Yaml := fRTTIYaml.Serialize(aObject);
-  try
-    Result := Yaml.ToYaml;
-  finally
-    Yaml.Free;
-  end;
-end;
-
-procedure TYamlSerializer.SetSerializeLevel(const Value: TSerializeLevel);
-begin
-  fSerializeLevel := Value;
-  if Assigned(fRTTIYaml) then fRTTIYaml.fSerializeLevel := Value;
-end;
-
-procedure TYamlSerializer.SetUseEnumNames(const Value: Boolean);
-begin
-  fUseEnumNames := Value;
-  if Assigned(fRTTIYaml) then fRTTIYaml.UseEnumNames := Value;
-end;
-
-procedure TYamlSerializer.SetUseYamlCaseSense(const Value: Boolean);
-begin
-  fUseYamlCaseSense := Value;
-  if Assigned(fRTTIYaml) then fRTTIYaml.UseYamlCaseSense := Value;
-end;
-
-{$IFNDEF FPC}
-{ TCommentProperty }
-
-constructor TCommentProperty.Create(const aComment: string);
-begin
-  fComment := aComment;
-end;
-
-{ TCustomNameProperty }
-
-constructor TCustomNameProperty.Create(const aName: string);
-begin
-  fName := aName;
-end;
-{$ENDIF}
-
-
-end.
-
-
-
-
+{ ***************************************************************************
+  Copyright (c) 2015-2021 Kike P�rez
+  Unit        : Quick.YAML.Serializer
+  Description : YAML Serializer
+  Author      : Kike P�rez
+  Version     : 1.0
+  Created     : 12/04/2019
+  Modified    : 05/08/2021
+  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.Serializer;
+
+{$i QuickLib.inc}
+
+interface
+
+uses
+  Classes,
+  SysUtils,
+  Rtti,
+  TypInfo,
+  {$IFDEF FPC}
+   rttiutils,
+   strUtils,
+   Generics.Collections,
+  {$ELSE}
+    {$IFDEF DELPHIRX10_UP}
+    System.Generics.Collections,
+    {$ENDIF}
+  {$ENDIF}
+  DateUtils,
+  Quick.Commons,
+  Quick.RTTI.Utils,
+  Quick.YAML,
+  Quick.Value,
+  Quick.Arrays;
+
+type
+
+  EYamlSerializeError = class(Exception);
+  EYamlDeserializeError = class(Exception);
+
+  {$IFNDEF FPC}
+  TNotSerializableProperty = class(TCustomAttribute);
+
+  TCommentProperty = class(TCustomAttribute)
+  private
+    fComment : string;
+  public
+    constructor Create(const aComment: string);
+    property Comment : string read fComment;
+  end;
+
+  TCustomNameProperty = class(TCustomAttribute)
+  private
+    fName : string;
+  public
+    constructor Create(const aName: string);
+    property Name : string read fName;
+  end;
+  {$ENDIF}
+
+  IYamlSerializer = interface
+  ['{CA26F7AE-F1FE-41BE-9C23-723A687F60D1}']
+    function YamlToObject(aType: TClass; const aYaml: string): TObject; overload;
+    function YamlToObject(aObject: TObject; const aYaml: string): TObject; overload;
+    function ObjectToYaml(aObject : TObject): string;
+  end;
+
+  TSerializeLevel = (slPublicProperty, slPublishedProperty);
+
+  TRTTIYaml = class
+  private
+    fSerializeLevel : TSerializeLevel;
+    fUseEnumNames : Boolean;
+    fUseYamlCaseSense : Boolean;
+    function GetValue(aAddr: Pointer; aType: TRTTIType): TValue; overload;
+    //function GetValue(aAddr: Pointer; aTypeInfo: PTypeInfo): TValue; overload;
+    function IsAllowedProperty(aObject : TObject; const aPropertyName : string) : Boolean;
+    function IsGenericList(aObject : TObject) : Boolean;
+    function IsGenericXArray(const aClassName : string) : Boolean;
+    //function GetPropertyValue(Instance : TObject; const PropertyName : string) : TValue;
+    function GetPropertyValueFromObject(Instance : TObject; const PropertyName : string) : TValue;
+    {$IFNDEF FPC}
+    function GetFieldValueFromRecord(aValue : TValue; const FieldName : string) : TValue;
+    function CreateInstance(aClass: TClass): TValue; overload;
+    function CreateInstance(aType: TRttiType): TValue; overload;
+    {$ENDIF}
+    {$IFDEF FPC}
+    procedure SetPropertyValue(Instance : TObject; aPropInfo : PPropInfo; aValue : TValue); overload;
+    procedure SetPropertyValue(Instance : TObject; const PropertyName : string; aValue : TValue); overload;
+    function FloatProperty(aObject : TObject; aPropInfo: PPropInfo): string;
+    function GetPropType(aPropInfo: PPropInfo): PTypeInfo;
+    procedure LoadSetProperty(aInstance : TObject; aPropInfo: PPropInfo; const aValue: string);
+    {$ENDIF}
+  public
+    constructor Create(aSerializeLevel : TSerializeLevel; aUseEnumNames : Boolean = True);
+    property UseEnumNames : Boolean read fUseEnumNames write fUseEnumNames;
+    property UseYamlCaseSense : Boolean read fUseYamlCaseSense write fUseYamlCaseSense;
+    {$IFNDEF FPC}
+    function DeserializeDynArray(aTypeInfo : PTypeInfo; aObject : TObject; const aYamlArray: TYamlArray) : TValue;
+    function DeserializeRecord(aRecord : TValue; aObject : TObject; const aYaml : TYamlObject) : TValue;
+    {$ELSE}
+    procedure DeserializeDynArray(aTypeInfo: PTypeInfo; const aPropertyName : string; aObject: TObject; const aYamlArray: TYamlArray);
+    {$ENDIF}
+    function DeserializeClass(aType : TClass; const aYaml : TYamlObject) : TObject;
+    function DeserializeObject(aObject : TObject; const aYaml : TYamlObject) : TObject; overload;
+    {$IFNDEF FPC}
+    function DeserializeList(aObject: TObject; const aName : string; const aYaml: TYamlObject) : TObject;
+    procedure DeserializeXArray(Instance : TObject; aRecord : TValue; aProperty : TRttiProperty; const aPropertyName : string; aYaml : TYamlObject);
+    {$ENDIF}
+    function DeserializeProperty(aObject : TObject; const aName : string; aProperty : TRttiProperty; const aYaml : TYamlObject) : TObject; overload;
+    {$IFNDEF FPC}
+    function DeserializeType(aObject : TObject; aType : TTypeKind; aTypeInfo : PTypeInfo; const aValue: string) : TValue;
+    {$ELSE}
+    function DeserializeType(aObject : TObject; aType : TTypeKind; const aPropertyName, aValue: string) : TValue;
+    {$ENDIF}
+    {$IFNDEF FPC}
+    function Serialize(const aName : string; aValue : TValue) : TYamlPair; overload;
+    {$ELSE}
+    function Serialize(aObject : TObject; aType : TTypeKind; const aPropertyName : string) : TYamlPair;
+    function Serialize(const aName : string; aValue : TValue) : TYamlPair;
+    {$ENDIF}
+    function Serialize(aObject : TObject) : TYamlObject; overload;
+    function GetYamlPairByName(aYaml : TYamlObject; const aName : string) : TYamlPair;
+  end;
+
+  TYamlSerializer = class(TInterfacedObject,IYamlSerializer)
+  strict private
+    fSerializeLevel : TSerializeLevel;
+    fUseEnumNames : Boolean;
+    fUseYamlCaseSense : Boolean;
+    fRTTIYaml : TRTTIYaml;
+  private
+    procedure SetUseEnumNames(const Value: Boolean);
+    procedure SetUseYamlCaseSense(const Value: Boolean);
+    procedure SetSerializeLevel(const Value: TSerializeLevel);
+  public
+    constructor Create(aSerializeLevel: TSerializeLevel; aUseEnumNames : Boolean = True);
+    destructor Destroy; override;
+    property SerializeLevel : TSerializeLevel read fSerializeLevel write SetSerializeLevel;
+    property UseEnumNames : Boolean read fUseEnumNames write SetUseEnumNames;
+    property UseYamlCaseSense : Boolean read fUseYamlCaseSense write SetUseYamlCaseSense;
+    function YamlToObject(aType : TClass; const aYaml: string) : TObject; overload;
+    function YamlToObject(aObject : TObject; const aYaml: string) : TObject; overload;
+    function ObjectToYaml(aObject : TObject): string;
+  end;
+
+  PPByte = ^PByte;
+
+resourcestring
+  cNotSupportedDataType = 'Not supported "%s" data type "%s"';
+  cNotSerializable = 'Object is not serializable';
+
+implementation
+
+{ TRTTIYaml }
+
+{$IFNDEF FPC}
+function TRTTIYaml.DeserializeDynArray(aTypeInfo: PTypeInfo; aObject: TObject; const aYamlArray: TYamlArray) : TValue;
+var
+  rType: PTypeInfo;
+  len: NativeInt;
+  pArr: Pointer;
+  rItemValue: TValue;
+  i: Integer;
+  objClass: TClass;
+  ctx : TRttiContext;
+  Yaml : TYamlObject;
+  rDynArray : TRttiDynamicArrayType;
+  propObj : TObject;
+begin
+  if GetTypeData(aTypeInfo).DynArrElType = nil then Exit;
+  if not assigned(aYamlArray) then Exit;
+
+  len := aYamlArray.Count;
+  rType := GetTypeData(aTypeInfo).DynArrElType^;
+  pArr := nil;
+  DynArraySetLength(pArr,aTypeInfo, 1, @len);
+  try
+    TValue.Make(@pArr,aTypeInfo, Result);
+    rDynArray := ctx.GetType(Result.TypeInfo) as TRTTIDynamicArrayType;
+
+    for i := 0 to aYamlArray.Count - 1 do
+    begin
+      rItemValue := nil;
+      case rType.Kind of
+        tkClass :
+          begin
+            if TYamlPair(aYamlArray.Items[i]).Value is TYamlObject then
+            begin
+              Yaml := TYamlObject(TYamlPair(aYamlArray.Items[i]).value);
+              propObj := GetValue(PPByte(Result.GetReferenceToRawData)^ +rDynArray.ElementType.TypeSize * i, rDynArray.ElementType).AsObject;
+              if propObj = nil then
+              begin
+                objClass := rType.TypeData.ClassType;
+                rItemValue := DeserializeClass(objClass,yaml);
+              end
+              else
+              begin
+                DeserializeObject(propObj,yaml);
+              end;
+            end;
+          end;
+        tkRecord :
+          begin
+            Yaml := TYamlObject(TYamlPair(aYamlArray.Items[i]).value);
+            rItemValue := DeserializeRecord(GetValue(PPByte(Result.GetReferenceToRawData)^ +rDynArray.ElementType.TypeSize * i,
+                                            rDynArray.ElementType),aObject,Yaml);
+          end;
+        tkMethod, tkPointer, tkClassRef ,tkInterface, tkProcedure :
+          begin
+            //skip these properties
+          end
+      else
+        begin
+          rItemValue := DeserializeType(aObject,rType.Kind,aTypeInfo,aYamlArray.Items[i].Value);
+        end;
+      end;
+      if not rItemValue.IsEmpty then Result.SetArrayElement(i,rItemValue);
+    end;
+    //aProperty.SetValue(aObject,rValue);
+  finally
+    DynArrayClear(pArr,aTypeInfo);
+  end;
+end;
+{$ELSE}
+procedure TRTTIYaml.DeserializeDynArray(aTypeInfo: PTypeInfo; const aPropertyName : string; aObject: TObject; const aYamlArray: TYamlArray);
+var
+  rType: PTypeInfo;
+  len: NativeInt;
+  pArr: Pointer;
+  rItemValue: TValue;
+  i: Integer;
+  objClass: TClass;
+  propObj : TObject;
+  rValue : TValue;
+  yaml : TYamlObject;
+begin
+  if GetTypeData(aTypeInfo).ElType2 = nil then Exit;
+  len := aYamlArray.Count;
+  rType := GetTypeData(aTypeInfo).ElType2;
+  pArr := nil;
+  DynArraySetLength(pArr,aTypeInfo, 1, @len);
+  try
+    TValue.Make(@pArr,aTypeInfo, rValue);
+    for i := 0 to aYamlArray.Count - 1 do
+    begin
+      rItemValue := nil;
+      case rType.Kind of
+        tkClass :
+          begin
+            if TYamlPair(aYamlArray.Items[i]).Value is TYamlObject then
+            begin
+              Yaml := TYamlObject(TYamlPair(aYamlArray.Items[i]).value);
+              propObj := GetValue(PPByte(rValue.GetReferenceToRawData)^ +GetTypeData(aTypeInfo).elSize * i, GetTypeData(aTypeInfo).ElType2).AsObject;
+              if propObj = nil then
+              begin
+                //objClass := GetTypeData(aTypeInfo).ClassType;
+                objClass := GetTypeData(GetTypeData(aTypeInfo).ElType2).ClassType;
+                rItemValue := DeserializeClass(objClass,yaml);
+              end
+              else
+              begin
+                DeserializeObject(propObj,yaml);
+              end;
+            end;
+          end;
+        tkRecord :
+          begin
+            {Yaml := TYamlObject(aYamlArray.Items[i]);
+            rItemValue := DeserializeRecord(GetValue(PPByte(Result.GetReferenceToRawData)^ +rDynArray.ElementType.TypeSize * i,
+                                            rDynArray.ElementType),aObject,Yaml);  }
+          end;
+        tkMethod, tkPointer, tkClassRef ,tkInterface, tkProcedure :
+          begin
+            //skip these properties
+          end
+      else
+        begin
+          rItemValue := DeserializeType(aObject,GetTypeData(aTypeInfo).ElType2.Kind,aPropertyName,aYamlArray.Items[i].Value);
+        end;
+      end;
+      if not rItemValue.IsEmpty then rValue.SetArrayElement(i,rItemValue);
+    end;
+    //aProperty.SetValue(aObject,rValue);
+    SetDynArrayProp(aObject,GetPropInfo(aObject,aPropertyName),pArr);
+  finally
+    DynArrayClear(pArr,aTypeInfo);
+  end;
+end;
+{$ENDIF}
+
+{$IFNDEF FPC}
+function TRTTIYaml.DeserializeRecord(aRecord : TValue; aObject : TObject; const aYaml : TYamlObject) : TValue;
+var
+  ctx : TRttiContext;
+  rRec : TRttiRecordType;
+  rField : TRttiField;
+  rValue : TValue;
+  member : TYamlPair;
+  yArray : TYamlArray;
+  Yaml : TYamlObject;
+  objClass : TClass;
+  propobj : TObject;
+begin
+  rRec := ctx.GetType(aRecord.TypeInfo).AsRecord;
+  try
+    for rField in rRec.GetFields do
+    begin
+      rValue := nil;
+      //member := TYamlPair(aYaml.GetValue(rField.Name));
+      member := GetYamlPairByName(aYaml,rField.Name);
+      if member <> nil then
+      case rField.FieldType.TypeKind of
+        tkDynArray :
+          begin
+            yArray := TYamlObject.ParseYamlValue(member.ToYaml) as TYamlArray;
+            try
+              rValue := DeserializeDynArray(rField.FieldType.Handle,aObject,yArray);
+            finally
+              yArray.Free;
+            end;
+          end;
+        tkClass :
+          begin
+            //if (member.YamlValue is TYamlObject) then
+            begin
+              propobj := rField.GetValue(@aRecord).AsObject;
+              Yaml := TYamlObject.ParseYamlValue(member.ToYaml) as TYamlObject;
+              try
+                if propobj = nil then
+                begin
+                  objClass := rField.FieldType.Handle^.TypeData.ClassType;// aProperty.PropertyType.Handle^.TypeData.ClassType;
+                  rValue := DeserializeClass(objClass,Yaml);
+                end
+                else
+                begin
+                  DeserializeObject(propobj,Yaml);
+                end;
+              finally
+                Yaml.Free;
+              end;
+            end
+          end;
+        tkRecord :
+          begin
+            Yaml := TYamlObject.ParseYamlValue(member.ToYaml) as TYamlObject;
+            try
+              rValue := DeserializeRecord(rField.GetValue(aRecord.GetReferenceToRawData),aObject,Yaml);
+            finally
+              Yaml.Free;
+            end;
+          end
+      else
+        begin
+          //rValue := DeserializeType(aObject,rField.FieldType.TypeKind,rField.FieldType.Handle,member.ToYaml);
+          {$IFNDEF FPC}
+          //avoid return unicode escaped chars if string
+          if rField.FieldType.TypeKind in [tkString, tkLString, tkWString, tkUString] then
+            {$IFDEF DELPHIRX10_UP}
+            rValue := DeserializeType(aObject,rField.FieldType.TypeKind,rField.FieldType.Handle,member.Value.AsString)
+            {$ELSE}
+            rValue := DeserializeType(aObject,rField.FieldType.TypeKind,rField.FieldType.Handle,member.YamlString.ToString)
+            {$ENDIF}
+            else rValue := DeserializeType(aObject,rField.FieldType.TypeKind,rField.FieldType.Handle,member.Value.AsString);
+          {$ELSE}
+          rValue := DeserializeType(aObject,rField.FieldType.TypeKind,aName,member.Value.AsString);
+          {$ENDIF}
+        end;
+      end;
+      if not rValue.IsEmpty then rField.SetValue(aRecord.GetReferenceToRawData,rValue);
+    end;
+    Result := aRecord;
+  finally
+    ctx.Free;
+  end;
+end;
+{$ENDIF}
+
+constructor TRTTIYaml.Create(aSerializeLevel : TSerializeLevel; aUseEnumNames : Boolean = True);
+begin
+  fSerializeLevel := aSerializeLevel;
+  fUseEnumNames := aUseEnumNames;
+  fUseYamlCaseSense := False;
+end;
+
+function TRTTIYaml.DeserializeClass(aType: TClass; const aYaml: TYamlObject): TObject;
+begin
+  Result := nil;
+  if (aYaml = nil) or ((aYaml as TYamlValue) is TYamlNull) or (aYaml.Count = 0) then Exit;
+
+  {$IFNDEF FPC}
+  Result := CreateInstance(aType).AsObject;
+  {$ELSE}
+  Result := aType.Create;
+  {$ENDIF}
+  try
+    Result := DeserializeObject(Result, aYaml);
+  except
+    on E : Exception do
+    begin
+      Result.Free;
+      raise EYamlDeserializeError.CreateFmt('Deserialize error class "%s" : %s',[aType.ClassName,e.Message]);
+    end;
+  end;
+end;
+
+function TRTTIYaml.DeserializeObject(aObject: TObject; const aYaml: TYamlObject): TObject;
+var
+  ctx: TRttiContext;
+  rType: TRttiType;
+  rProp: TRttiProperty;
+  {$IFNDEF FPC}
+  attr: TCustomAttribute;
+  {$ENDIF}
+  propertyname : string;
+begin
+  Result := aObject;
+
+  if (aYaml = nil) or ((aYaml as TYamlValue) is TYamlNull) or (aYaml.Count = 0) or (Result = nil) then Exit;
+
+  try
+    rType := ctx.GetType(aObject.ClassInfo);
+    try
+      for rProp in rType.GetProperties do
+      begin
+        {$IFNDEF FPC}
+        if ((fSerializeLevel = slPublicProperty) and (rProp.PropertyType.IsPublicType))
+            or ((fSerializeLevel = slPublishedProperty) and ((IsPublishedProp(aObject,rProp.Name)) or (rProp.Name = 'List'))) then
+        {$ENDIF}
+        begin
+          if ((rProp.IsWritable) or (rProp.Name = 'List')) and (IsAllowedProperty(aObject,rProp.Name)) then
+          begin
+            propertyname := rProp.Name;
+            {$IFNDEF FPC}
+            for attr in rProp.GetAttributes do if attr is TCustomNameProperty then propertyname := TCustomNameProperty(attr).Name;
+            if rProp.Name = 'List' then
+            begin
+              Result := DeserializeList(Result,propertyname,aYaml);
+            end
+            else if (rProp.GetValue(aObject).IsObject) and (IsGenericList(rProp.GetValue(aObject).AsObject)) then
+            begin
+              DeserializeList(rProp.GetValue(aObject).AsObject,'List',TYamlObject(aYaml.GetValue(propertyname)));
+            end
+            else if (not rProp.GetValue(aObject).IsObject) and (IsGenericXArray(string(rProp.GetValue(aObject){$IFNDEF NEXTGEN}.TypeInfo.Name{$ELSE}.TypeInfo.NameFld.ToString{$ENDIF}))) then
+            begin
+              DeserializeXArray(Result,rProp.GetValue(aObject),rProp,propertyname,aYaml);
+            end
+            else
+            {$ENDIF}
+            Result := DeserializeProperty(Result,propertyname,rProp,aYaml);
+          end;
+        end;
+      end;
+    finally
+      ctx.Free;
+    end;
+  except
+    on E : Exception do
+    begin
+      Result.Free;
+      raise EYamlDeserializeError.CreateFmt('Deserialize error for object "%s" : %s',[aObject.ClassName,e.Message]);
+    end;
+  end;
+end;
+
+{$IFNDEF FPC}
+function TRTTIYaml.DeserializeList(aObject: TObject; const aName : string; const aYaml: TYamlObject) : TObject;
+var
+  ctx : TRttiContext;
+  rType : TRttiType;
+  yArray : TYamlArray;
+  member : TYamlPair;
+  rvalue : TValue;
+  i : Integer;
+  rProp : TRttiProperty;
+  {$IFNDEF DELPHIRX103_UP}
+  rfield : TRttiField;
+  {$ENDIF}
+begin
+  Result := aObject;
+
+  rType := ctx.GetType(aObject.ClassInfo);
+  try
+    rProp := rType.GetProperty('List');
+    if rProp = nil then Exit;
+  finally
+    ctx.Free;
+  end;
+  member := GetYamlPairByName(aYaml,aName);
+  //var a := aYaml.ToYaml;
+  if member = nil then yArray := TYamlArray(aYaml) //TYamlObject.ParseYamlValue(aYaml.ToYaml) as TYamlArray
+    else yArray := TYamlObject.ParseYamlValue(member.ToYaml) as TYamlArray;
+
+  rvalue := DeserializeDynArray(rProp.PropertyType.Handle,Result,yArray);
+
+  if not rValue.IsEmpty then
+  begin
+    {$IFDEF DELPHIRX103_UP}
+    if (TObjectList<TObject>(aObject) <> nil) and (rvalue.IsArray) then
+    begin
+      TObjectList<TObject>(aObject).Clear;
+      TObjectList<TObject>(aObject).Capacity := rvalue.GetArrayLength;
+      for i := 0 to rvalue.GetArrayLength - 1 do
+      begin
+        TObjectList<TObject>(aObject).Add(rvalue.GetArrayElement(i).AsObject);
+      end;
+    end;
+    {$ELSE}
+    for rfield in rType.GetFields do
+    begin
+      if rfield.Name = 'FOwnsObjects' then rfield.SetValue(aObject,True);
+      //if rfield.Name = 'FCount' then rfield.SetValue(aObject,i);
+      if rfield.Name = 'FItems' then
+      begin
+        //if TList(aObject) <> nil then TList(aObject).Clear;
+        //rfield.GetValue(aObject).AsObject.Free;// aValue.GetReferenceToRawData)
+        rfield.SetValue(aObject,rValue);// .SetDynArrayProp(aObject,'fItems',Result);
+        Break;
+      end;
+    end;
+    rProp := rType.GetProperty('Count');
+    rProp.SetValue(aObject,i);
+    {$ENDIF}
+  end;
+end;
+{$ENDIF}
+
+{$IFNDEF FPC}
+procedure TRTTIYaml.DeserializeXArray(Instance : TObject; aRecord : TValue; aProperty : TRttiProperty; const aPropertyName : string; aYaml : TYamlObject);
+var
+  ctx : TRttiContext;
+  rRec : TRttiRecordType;
+  rfield : TRttiField;
+  rValue : TValue;
+  member : TYamlPair;
+  yArray : TYamlArray;
+begin
+  rRec := ctx.GetType(aRecord.TypeInfo).AsRecord;
+  try
+    rfield := rRec.GetField('fArray');
+    if rfield <> nil then
+    begin
+      rValue := nil;
+      //member := TYamlPair(aYaml.GetValue(rField.Name));
+      member := GetYamlPairByName(aYaml,aPropertyName);
+      if (member <> nil) and (rField.FieldType.TypeKind = tkDynArray) then
+      begin
+        yArray := TYamlObject.ParseYamlValue(member.ToYaml) as TYamlArray;
+        try
+          rValue := DeserializeDynArray(rField.FieldType.Handle,nil,yArray);
+        finally
+          yArray.Free;
+        end;
+      end;
+    end;
+    if not rValue.IsEmpty then rField.SetValue(aRecord.GetReferenceToRawData,rValue);
+    aProperty.SetValue(Instance,aRecord);
+  finally
+    ctx.Free;
+  end;
+end;
+{$ENDIF}
+
+function TRTTIYaml.DeserializeProperty(aObject : TObject; const aName : string; aProperty : TRttiProperty; const aYaml : TYamlObject) : TObject;
+var
+  rValue : TValue;
+  member : TYamlPair;
+  objClass: TClass;
+  yArray : TYamlArray;
+  Yaml : TYamlObject;
+begin
+    Result := aObject;
+    rValue := nil;
+    //member := TYamlPair(aYaml.GetValue(aName));
+    member := GetYamlPairByName(aYaml,aName);
+    if member <> nil then
+    begin
+      case aProperty.PropertyType.TypeKind of
+        tkDynArray :
+          begin
+            yArray := member.Value as TYamlArray;
+            {$IFNDEF FPC}
+            aProperty.SetValue(aObject,DeserializeDynArray(aProperty.PropertyType.Handle,Result,yArray));
+            {$ELSE}
+            DeserializeDynArray(aProperty.PropertyType.Handle,aName,Result,yArray);
+            {$ENDIF}
+            Exit;
+          end;
+        tkClass :
+          begin
+            //if (member.YamlValue is TYamlObject) then
+            begin
+              Yaml := TYamlObject(TYamlObject.ParseYamlValue(member.ToYaml));
+              try
+                if aProperty.GetValue(aObject).AsObject = nil then
+                begin
+                  {$IFNDEF FPC}
+                  objClass := aProperty.PropertyType.Handle^.TypeData.ClassType;
+                  rValue := DeserializeClass(objClass,Yaml);
+                  {$ELSE}
+                  objClass := GetObjectPropClass(aObject,aName);
+                  //objClass := GetTypeData(aProperty.PropertyType.Handle)^.ClassType;
+                  rValue := DeserializeClass(objClass,Yaml);
+                  SetObjectProp(aObject,aName,rValue.AsObject);
+                  Exit;
+                  {$ENDIF}
+                end
+                else
+                begin
+                  rValue := DeserializeObject(aProperty.GetValue(aObject).AsObject,Yaml);
+                  Exit;
+                end;
+              finally
+                Yaml.Free;
+              end;
+            end
+          end;
+        {$IFNDEF FPC}
+        tkRecord :
+          begin
+            Yaml := TYamlObject.ParseYamlValue(member.ToYaml) as TYamlObject;
+            try
+              rValue := DeserializeRecord(aProperty.GetValue(aObject),aObject,Yaml);
+            finally
+              Yaml.Free;
+            end;
+          end;
+        tkSet :
+          begin
+            rValue := DeserializeType(aObject,aProperty.PropertyType.TypeKind,aProperty.GetValue(aObject).TypeInfo,member.ToYaml)
+          end
+        {$ENDIF}
+      else
+        begin
+          {$IFNDEF FPC}
+          //avoid return unicode escaped chars if string
+          if aProperty.PropertyType.TypeKind in [tkString, tkLString, tkWString, tkUString] then
+            {$IFDEF DELPHIRX10_UP}
+            rValue := DeserializeType(aObject,aProperty.PropertyType.TypeKind,aProperty.GetValue(aObject).TypeInfo,member.Value.AsString)
+            {$ELSE}
+            rValue := DeserializeType(aObject,aProperty.PropertyType.TypeKind,aProperty.GetValue(aObject).TypeInfo,member.YamlString.ToString)
+            {$ENDIF}
+          else rValue := DeserializeType(aObject,aProperty.PropertyType.TypeKind,aProperty.GetValue(aObject).TypeInfo,member.Value.AsString);
+          {$ELSE}
+          rValue := DeserializeType(aObject,aProperty.PropertyType.TypeKind,aName,member.Value.AsString);
+          if not rValue.IsEmpty then SetPropertyValue(aObject,aName,rValue);
+          {$ENDIF}
+        end;
+      end;
+      {$IFNDEF FPC}
+      if not rValue.IsEmpty then aProperty.SetValue(Result,rValue);
+      {$ENDIF}
+    end;
+end;
+
+{$IFNDEF FPC}
+function TRTTIYaml.DeserializeType(aObject : TObject; aType : TTypeKind; aTypeInfo : PTypeInfo; const aValue: string) : TValue;
+var
+  i : Integer;
+  value : string;
+  fsettings : TFormatSettings;
+begin
+  try
+    value := AnsiDequotedStr(aValue,'"');
+    case aType of
+      tkString, tkLString, tkWString, tkUString :
+        begin
+          Result := value;
+        end;
+      tkChar, tkWChar :
+        begin
+          Result := value;
+        end;
+      tkInteger :
+        begin
+          Result := StrToInt(value);
+        end;
+      tkInt64 :
+        begin
+          Result := StrToInt64(value);
+        end;
+      tkFloat :
+        begin
+          if aTypeInfo = TypeInfo(TDateTime) then
+          begin
+            if CompareText(value,'null') <> 0 then Result := JsonDateToDateTime(value);
+          end
+          else if aTypeInfo = TypeInfo(TDate) then
+          begin
+            if CompareText(value,'null') <> 0 then Result := StrToDate(value);
+          end
+          else if aTypeInfo = TypeInfo(TTime) then
+          begin
+            Result := StrToTime(value);
+          end
+          else
+          begin
+            fsettings := TFormatSettings.Create;
+            Result := StrToFloat(StringReplace(value,'.',fsettings.DecimalSeparator,[]));
+          end;
+        end;
+      tkEnumeration :
+        begin
+          if aTypeInfo = System.TypeInfo(Boolean) then
+          begin
+            Result := StrToBool(value);
+          end
+          else
+          begin
+            //if fUseEnumNames then TValue.Make(GetEnumValue(aTypeInfo,value),aTypeInfo, Result)
+            //  else TValue.Make(StrToInt(value),aTypeInfo, Result);
+            if not TryStrToInt(value,i) then TValue.Make(GetEnumValue(aTypeInfo,value),aTypeInfo, Result)
+              else TValue.Make(StrToInt(value),aTypeInfo, Result);
+          end;
+        end;
+      tkSet :
+        begin
+          i := StringToSet(aTypeInfo,value);
+          TValue.Make(@i,aTypeInfo,Result);
+        end;
+    else
+        begin
+          //raise EclYamlSerializerError.Create('Not supported data type!');
+        end;
+    end;
+  except
+    on E : Exception do
+    begin
+      raise EYamlDeserializeError.CreateFmt('Deserialize error type "%s.%s" : %s',[aObject.ClassName,GetTypeName(aTypeInfo),e.Message]);
+    end;
+  end;
+end;
+{$ELSE}
+function TRTTIYaml.DeserializeType(aObject : TObject; aType : TTypeKind; const aPropertyName, aValue: string) : TValue;
+var
+  value : string;
+  propinfo : PPropInfo;
+  fsettings : TFormatSettings;
+begin
+  try
+    value := AnsiDequotedStr(aValue,'"');
+
+    if value = '' then
+    begin
+      Result := nil;
+      Exit;
+    end;
+    propinfo := GetPropInfo(aObject,aPropertyName);
+    //case propinfo.PropType.Kind of
+    case aType of
+      tkString, tkLString, tkWString, tkUString, tkAString :
+        begin
+          Result := value;
+          //SetStrProp(aObject,propinfo,value);
+        end;
+      tkChar, tkWChar :
+        begin
+          Result := value;
+        end;
+      tkInteger :
+        begin
+          Result := StrToInt(value);
+        end;
+      tkInt64 :
+        begin
+          Result := StrToInt64(value);
+        end;
+      tkFloat :
+        begin
+          if propinfo.PropType = TypeInfo(TDateTime) then
+          begin
+            if CompareText(value,'null') <> 0  then Result := JsonDateToDateTime(value);
+          end
+          else if propinfo.PropType = TypeInfo(TDate) then
+          begin
+            if CompareText(value,'null') <> 0 then Result := StrToDate(value);
+          end
+          else if propinfo.PropType = TypeInfo(TTime) then
+          begin
+            Result := StrToTime(value);
+          end
+          else
+          begin
+            fsettings := DefaultFormatSettings;
+            Result := StrToFloat(StringReplace(value,'.',fsettings.DecimalSeparator,[]));
+          end;
+        end;
+      tkEnumeration:
+        begin
+          Result := value;
+        end;
+      tkBool :
+          begin
+            Result := StrToBool(value);
+          end;
+      tkSet :
+        begin
+          Result := value;
+        end;
+    else
+        begin
+          //raise EclYamlSerializerError.Create('Not supported data type!');
+        end;
+    end;
+    //if not Result.IsEmpty then SetPropertyValue(aObject,propinfo,Result);
+  except
+    on E : Exception do
+    begin
+      raise EYamlDeserializeError.CreateFmt('Deserialize error type "%s" : %s',[aObject.ClassName,e.Message]);
+    end;
+  end;
+end;
+{$ENDIF}
+
+function TRTTIYaml.IsAllowedProperty(aObject : TObject; const aPropertyName : string) : Boolean;
+var
+  propname : string;
+begin
+  Result := True;
+  propname := aPropertyName.ToLower;
+  if IsGenericList(aObject) then
+  begin
+    if (propname = 'capacity') or (propname = 'count') or (propname = 'ownsobjects') then Result := False;
+  end
+  else if (propname = 'refcount') then Result := False;
+end;
+
+function TRTTIYaml.IsGenericList(aObject : TObject) : Boolean;
+var
+  cname : string;
+begin
+  if aObject = nil then Exit(False);
+
+  cname := aObject.ClassName;
+  Result := (cname.StartsWith('TObjectList')) or (cname.StartsWith('TList'));
+end;
+
+function TRTTIYaml.IsGenericXArray(const aClassName : string) : Boolean;
+begin
+  Result := aClassName.StartsWith('TXArray');
+end;
+
+function TRTTIYaml.GetYamlPairByName(aYaml: TYamlObject; const aName: string): TYamlPair;
+var
+  candidate : TYamlPair;
+  yvalue : TYamlValue;
+  i : Integer;
+begin
+  Result := nil;
+  if fUseYamlCaseSense then
+  begin
+    yvalue := aYaml.GetValue(aName);
+    if yvalue <> nil then Result := TYamlPair(yvalue);
+    Exit;
+  end
+  else
+  begin
+    if aYaml <> nil then
+    for i := 0 to aYaml.Count - 1 do
+    begin
+      candidate := aYaml.Pairs[I];
+      if (candidate = nil) or (candidate.Value = nil) then Exit(nil);
+      if CompareText(candidate.Name,aName) = 0 then
+        Exit(candidate);
+    end;
+  end;
+  Result := nil;
+end;
+
+//function TRTTIYaml.GetPropertyValue(Instance : TObject; const PropertyName : string) : TValue;
+//var
+//  pinfo : PPropInfo;
+//begin
+//  Result := nil;
+//  pinfo := GetPropInfo(Instance,PropertyName);
+//  case pinfo.PropType^.Kind of
+//    tkInteger : Result := GetOrdProp(Instance,pinfo);
+//    tkInt64 : Result := GetInt64Prop(Instance,PropertyName);
+//    tkFloat : Result := GetFloatProp(Instance,PropertyName);
+//    tkChar : Result := Char(GetOrdProp(Instance,PropertyName));
+//    {$IFDEF FPC}
+//    tkWString : Result := GetWideStrProp(Instance,PropertyName);
+//    tkSString,
+//    tkAString,
+//    {$ELSE}
+//    tkWString,
+//    {$ENDIF}
+//    tkLString : Result := GetStrProp(Instance,pinfo);
+//    {$IFDEF FPC}
+//    tkEnumeration :
+//      begin
+//        if fUseEnumNames then Result := GetEnumName(pinfo.PropType,GetOrdProp(Instance,PropertyName))
+//          else Result := GetOrdProp(Instance,PropertyName);
+//      end;
+//    {$ELSE}
+//    tkEnumeration :
+//      begin
+//        if fUseEnumNames then Result := GetEnumName(@pinfo.PropType,GetOrdProp(Instance,PropertyName))
+//          else Result := GetOrdProp(Instance,PropertyName);
+//      end;
+//    {$ENDIF}
+//    tkSet : Result := GetSetProp(Instance,pinfo,True);
+//    {$IFNDEF FPC}
+//    tkClass :
+//    {$ELSE}
+//    tkBool : Result := Boolean(GetOrdProp(Instance,pinfo));
+//    tkObject :
+//    {$ENDIF} Result := GetObjectProp(Instance,pinfo);
+//    tkDynArray : Result := GetDynArrayProp(Instance,pinfo);
+//  end;
+//end;
+
+function TRTTIYaml.GetPropertyValueFromObject(Instance : TObject; const PropertyName : string) : TValue;
+var
+  ctx : TRttiContext;
+  rprop : TRttiProperty;
+begin
+  rprop := ctx.GetType(Instance.ClassInfo).GetProperty(PropertyName);
+  Result := rprop.GetValue(Instance);
+end;
+
+{$IFNDEF FPC}
+function TRTTIYaml.GetFieldValueFromRecord(aValue : TValue; const FieldName : string) : TValue;
+var
+  ctx : TRttiContext;
+  rec : TRttiRecordType;
+  rfield : TRttiField;
+begin
+  rec := ctx.GetType(aValue.TypeInfo).AsRecord;
+  rfield := rec.GetField(FieldName);
+  if rfield <> nil then Result := rField.GetValue(aValue.GetReferenceToRawData)
+    else Result := nil;
+end;
+{$ENDIF}
+
+{$IFNDEF FPC}
+function TRTTIYaml.CreateInstance(aClass: TClass): TValue;
+var
+  ctx : TRttiContext;
+  rtype : TRttiType;
+begin
+  Result := nil;
+  rtype := ctx.GetType(aClass);
+  Result := CreateInstance(rtype);
+end;
+{$ENDIF}
+
+{$IFNDEF FPC}
+function TRTTIYaml.CreateInstance(aType: TRttiType): TValue;
+var
+  rmethod : TRttiMethod;
+begin
+  Result := nil;
+  if atype = nil then Exit;
+  for rmethod in TRttiInstanceType(atype).GetMethods do
+  begin
+    if rmethod.IsConstructor then
+    begin
+      //create if don't have parameters
+      if Length(rmethod.GetParameters) = 0 then
+      begin
+        Result := rmethod.Invoke(TRttiInstanceType(atype).MetaclassType,[]);
+        Break;
+      end;
+    end;
+  end;
+end;
+{$ENDIF}
+
+{$IFDEF FPC}
+procedure TRTTIYaml.SetPropertyValue(Instance : TObject; const PropertyName : string; aValue : TValue);
+var
+  pinfo : PPropInfo;
+begin
+  pinfo := GetPropInfo(Instance,PropertyName);
+  SetPropertyValue(Instance,pinfo,aValue);
+end;
+
+procedure TRTTIYaml.SetPropertyValue(Instance : TObject; aPropInfo : PPropInfo; aValue : TValue);
+begin
+  case aPropInfo.PropType^.Kind of
+    tkInteger : SetOrdProp(Instance,aPropInfo,aValue.AsInteger);
+    tkInt64 : SetInt64Prop(Instance,aPropInfo,aValue.AsInt64);
+    tkFloat : SetFloatProp(Instance,aPropInfo,aValue.AsExtended);
+    tkChar : SetOrdProp(Instance,aPropInfo,aValue.AsOrdinal);
+    {$IFDEF FPC}
+    tkWString : SetWideStrProp(Instance,aPropInfo,aValue.AsString);
+    tkSString,
+    tkAString,
+    {$ELSE}
+    tkWString,
+    {$ENDIF}
+    tkLString : SetStrProp(Instance,aPropInfo,aValue.AsString);
+    {$IFDEF FPC}
+    tkBool : SetOrdProp(Instance,aPropInfo,aValue.AsOrdinal);
+    tkSet : LoadSetProperty(Instance,aPropInfo,aValue.AsString);
+    {$ENDIF}
+    tkEnumeration : SetEnumProp(Instance,aPropInfo,aValue.AsString);
+    {$IFNDEF FPC}
+    tkClass :
+    {$ELSE}
+    tkObject :
+    {$ENDIF} SetObjectProp(Instance,aPropInfo,aValue.AsObject);
+  end;
+end;
+
+procedure TRTTIYaml.LoadSetProperty(aInstance : TObject; aPropInfo: PPropInfo; const aValue: string);
+type
+  TCardinalSet = set of 0..SizeOf(Cardinal) * 8 - 1;
+const
+  Delims = [' ', ',', '[', ']'];
+var
+  TypeInfo: PTypeInfo;
+  W: Cardinal;
+  I, N: Integer;
+  Count: Integer;
+  EnumName: string;
+begin
+  W := 0;
+  TypeInfo := GetTypeData(GetPropType(aPropInfo))^.CompType;
+  Count := WordCount(aValue, Delims);
+  for N := 1 to Count do
+  begin
+    EnumName := ExtractWord(N, aValue, Delims);
+    try
+      I := GetEnumValue(TypeInfo, EnumName);
+      if I >= 0 then Include(TCardinalSet(W),I);
+    except
+    end;
+  end;
+  SetOrdProp(aInstance,aPropInfo,W);
+end;
+{$ENDIF}
+
+function TRTTIYaml.Serialize(aObject: TObject): TYamlObject;
+var
+  ctx: TRttiContext;
+  {$IFNDEF FPC}
+  attr : TCustomAttribute;
+  comment : string;
+  {$ENDIF}
+  rType: TRttiType;
+  rProp: TRttiProperty;
+  ypair : TYamlPair;
+  ExcludeSerialize : Boolean;
+  propertyname : string;
+begin
+  if (aObject = nil) then
+  begin
+    Result := nil;
+    Exit;
+  end;
+
+  Result := TYamlObject.Create;
+  try
+    rType := ctx.GetType(aObject.ClassInfo);
+    try
+      //s := rType.ToString;
+      for rProp in TRTTI.GetProperties(rType,roFirstBase) do
+      begin
+        ExcludeSerialize := False;
+        propertyname := rProp.Name;
+        {$IFNDEF FPC}
+        comment := '';
+        for attr in rProp.GetAttributes do
+        begin
+          if attr is TNotSerializableProperty then ExcludeSerialize := True
+          else if attr is TCommentProperty then comment := TCommentProperty(attr).Comment
+          else if  attr is TCustomNameProperty then propertyname := TCustomNameProperty(attr).Name;
+        end;
+        if ((fSerializeLevel = slPublicProperty) and (rProp.PropertyType.IsPublicType))
+            or ((fSerializeLevel = slPublishedProperty) and ((IsPublishedProp(aObject,rProp.Name)) or (rProp.Name = 'List'))) then
+        {$ENDIF}
+        begin
+          if (IsAllowedProperty(aObject,propertyname)) and (not ExcludeSerialize) then
+          begin
+            //add comment as pair
+            {$IFNDEF FPC}
+            if comment <> '' then Result.AddPair(TYamlPair.Create('#',TYamlComment.Create(Comment)));
+            {$ENDIF}
+            begin
+              if (rProp.GetValue(aObject).IsObject) and (IsGenericList(rProp.GetValue(aObject).AsObject)) then
+              begin
+                ypair := Serialize(propertyname,GetPropertyValueFromObject(rProp.GetValue(aObject).AsObject,'List'));
+              end
+              {$IFNDEF FPC}
+              else if (not rProp.GetValue(aObject).IsObject) and (IsGenericXArray(string(rProp.GetValue(aObject){$IFNDEF NEXTGEN}.TypeInfo.Name{$ELSE}.TypeInfo.NameFld.ToString{$ENDIF}))) then
+              begin
+                ypair := Serialize(propertyname,GetFieldValueFromRecord(rProp.GetValue(aObject),'fArray'));
+              end
+              {$ENDIF}
+              else
+              begin
+                {$IFNDEF FPC}
+                ypair := Serialize(propertyname,rProp.GetValue(aObject));
+                {$ELSE}
+                ypair := Serialize(aObject,rProp.PropertyType.TypeKind,propertyname);
+                {$ENDIF}
+              end;
+              //s := jpair.YamlValue.ToString;
+              if ypair <> nil then
+              begin
+                Result.AddPair(ypair);
+              end
+              else ypair.Free;
+            end;
+            //Result.AddPair(Serialize(rProp.Name,rProp.GetValue(aObject)));
+            //s := Result.ToYaml;
+          end;
+        end;
+      end;
+    finally
+      ctx.Free;
+    end;
+  except
+    on E : Exception do
+    begin
+      Result.Free;
+      raise EYamlSerializeError.CreateFmt('Serialize error object "%s" : %s',[aObject.ClassName,e.Message]);
+    end;
+  end;
+end;
+
+function TRTTIYaml.GetValue(aAddr: Pointer; aType: TRTTIType): TValue;
+begin
+  TValue.Make(aAddr,aType.Handle,Result);
+end;
+
+//function TRTTIYaml.GetValue(aAddr: Pointer; aTypeInfo: PTypeInfo): TValue;
+//begin
+//  TValue.Make(aAddr,aTypeInfo,Result);
+//end;
+
+{$IFNDEF FPC}
+function TRTTIYaml.Serialize(const aName : string; aValue : TValue) : TYamlPair;
+var
+  ctx: TRttiContext;
+  rRec : TRttiRecordType;
+  rField : TRttiField;
+  rDynArray : TRTTIDynamicArrayType;
+  Yaml : TYamlObject;
+  yArray : TYamlArray;
+  ypair : TYamlPair;
+  yvalue : TYamlValue;
+  i : Integer;
+begin
+  Result := TYamlPair.Create(aName,nil);
+  //Result.YamlString := TYamlString(aName);
+  try
+    case avalue.Kind of
+      tkDynArray :
+        begin
+          yArray := TYamlArray.Create;
+          rDynArray := ctx.GetType(aValue.TypeInfo) as TRTTIDynamicArrayType;
+          try
+            for i := 0 to aValue.GetArrayLength - 1 do
+            begin
+              if not GetValue(PPByte(aValue.GetReferenceToRawData)^ + rDynArray.ElementType.TypeSize * i, rDynArray.ElementType).IsEmpty then
+              begin
+                yvalue := nil;
+                ypair := Serialize(aName,GetValue(PPByte(aValue.GetReferenceToRawData)^ + rDynArray.ElementType.TypeSize * i, rDynArray.ElementType));
+                try
+                  //jValue := TYamlValue(jPair.YamlValue.Clone);
+                  yvalue := ypair.Value;
+                  if yvalue <> nil then
+                  begin
+                    yArray.AddElement(yvalue);
+                    ypair.Value.Owned := False;
+                  end;
+                finally
+                  ypair.Free;
+                  if yvalue <> nil then yvalue.Owned := True;
+                end;
+              end;
+            end;
+            Result.Value := yArray;
+          finally
+            ctx.Free;
+          end;
+        end;
+      tkClass :
+        begin
+           Result.Value := TYamlValue(Serialize(aValue.AsObject));
+        end;
+      tkString, tkLString, tkWString, tkUString :
+        begin
+          Result.Value := TYamlString.Create(aValue.AsString);
+        end;
+      tkChar, tkWChar :
+        begin
+          Result.Value := TYamlString.Create(aValue.AsString);
+        end;
+      tkInteger :
+        begin
+          Result.Value := TYamlInteger.Create(aValue.AsInteger);
+        end;
+      tkInt64 :
+        begin
+          Result.Value := TYamlInteger.Create(aValue.AsInt64);
+        end;
+      tkFloat :
+        begin
+          if aValue.TypeInfo = TypeInfo(TDateTime) then
+          begin
+            if aValue.AsExtended <> 0.0 then Result.Value := TYamlString.Create(DateTimeToJsonDate(aValue.AsExtended));
+          end
+          else if aValue.TypeInfo = TypeInfo(TDate) then
+          begin
+            if aValue.AsExtended <> 0.0 then Result.Value := TYamlString.Create(DateToStr(aValue.AsExtended));
+          end
+          else if aValue.TypeInfo = TypeInfo(TTime) then
+          begin
+            Result.Value := TYamlString.Create(TimeToStr(aValue.AsExtended));
+          end
+          else
+          begin
+            Result.Value := TYamlFloat.Create(aValue.AsExtended);
+          end;
+        end;
+      tkEnumeration :
+        begin
+          if (aValue.TypeInfo = System.TypeInfo(Boolean)) then
+          begin
+            Result.Value := TYamlBoolean.Create(aValue.AsBoolean);
+          end
+          else
+          begin
+            //Result.YamlValue := TYamlString.Create(GetEnumName(aValue.TypeInfo,aValue.AsOrdinal));
+            if fUseEnumNames then Result.Value := TYamlString.Create(aValue.ToString)
+              else Result.Value := TYamlInteger.Create(GetEnumValue(aValue.TypeInfo,aValue.ToString));
+          end;
+        end;
+      tkSet :
+        begin
+          Result.Value := TYamlString.Create(aValue.ToString);
+        end;
+      tkRecord :
+        begin
+          rRec := ctx.GetType(aValue.TypeInfo).AsRecord;
+          try
+            Yaml := TYamlObject.Create;
+            for rField in rRec.GetFields do
+            begin
+              Yaml.AddPair(Serialize(rField.name,rField.GetValue(aValue.GetReferenceToRawData)));
+            end;
+            Result.Value := Yaml;
+          finally
+            ctx.Free;
+          end;
+        end;
+      tkMethod, tkPointer, tkClassRef ,tkInterface, tkProcedure :
+        begin
+          //skip these properties
+          //FreeAndNil(Result);
+        end
+    else
+      begin
+        raise EYamlSerializeError.CreateFmt(cNotSupportedDataType,[aName,GetTypeName(aValue.TypeInfo)]);
+      end;
+    end;
+    if Result.Value = nil then Result.Value := TYamlNull.Create;
+  except
+    on E : Exception do
+    begin
+      Result.Free;
+      raise EYamlSerializeError.CreateFmt('Serialize error class "%s.%s" : %s',[aName,aValue.ToString,e.Message]);
+    end;
+  end;
+end;
+{$ELSE}
+function TRTTIYaml.GetPropType(aPropInfo: PPropInfo): PTypeInfo;
+begin
+  Result := aPropInfo^.PropType;
+end;
+
+function TRTTIYaml.FloatProperty(aObject : TObject; aPropInfo: PPropInfo): string;
+const
+  Precisions: array[TFloatType] of Integer = (7, 15, 18, 18, 19);
+var
+  fsettings : TFormatSettings;
+begin
+  fsettings := FormatSettings;
+  Result := StringReplace(FloatToStrF(GetFloatProp(aObject, aPropInfo), ffGeneral,
+    Precisions[GetTypeData(GetPropType(aPropInfo))^.FloatType],0),
+    '.',fsettings.DecimalSeparator,[rfReplaceAll]);
+end;
+
+function TRTTIYaml.Serialize(const aName : string; aValue : TValue) : TYamlPair;
+begin
+  Result := TYamlPair.Create(aName,nil);
+  //Result.YamlString := TYamlString(aName);
+  try
+    case avalue.Kind of
+      tkClass :
+        begin
+           Result.Value := TYamlValue(Serialize(aValue.AsObject));
+        end;
+      tkString, tkLString, tkWString, tkUString :
+        begin
+          Result.Value := TYamlString.Create(aValue.AsString);
+        end;
+      tkChar, tkWChar :
+        begin
+          Result.Value := TYamlString.Create(aValue.AsString);
+        end;
+      tkInteger :
+        begin
+          Result.Value := TYamlInteger.Create(aValue.AsInteger);
+        end;
+      tkInt64 :
+        begin
+          Result.Value := TYamlInteger.Create(aValue.AsInt64);
+        end;
+      tkFloat :
+        begin
+          if aValue.TypeInfo = TypeInfo(TDateTime) then
+          begin
+            if aValue.AsExtended <> 0.0 then Result.Value := TYamlString.Create(DateTimeToJsonDate(aValue.AsExtended));
+          end
+          else if aValue.TypeInfo = TypeInfo(TDate) then
+          begin
+            if aValue.AsExtended <> 0.0 then Result.Value := TYamlString.Create(DateToStr(aValue.AsExtended));
+          end
+          else if aValue.TypeInfo = TypeInfo(TTime) then
+          begin
+            Result.Value := TYamlString.Create(TimeToStr(aValue.AsExtended));
+          end
+          else
+          begin
+            Result.Value := TYamlFloat.Create(aValue.AsExtended);
+          end;
+        end;
+      tkEnumeration :
+        begin
+          if (aValue.TypeInfo = System.TypeInfo(Boolean)) then
+          begin
+            Result.Value := TYamlBoolean.Create(aValue.AsBoolean);
+          end
+          else
+          begin
+            //Result.YamlValue := TYamlString.Create(GetEnumName(aValue.TypeInfo,aValue.AsOrdinal));
+            if fUseEnumNames then Result.Value := TYamlString.Create(aValue.ToString)
+              else Result.Value := TYamlInteger.Create(GetEnumValue(aValue.TypeInfo,aValue.ToString));
+          end;
+        end;
+      tkSet :
+        begin
+          Result.Value := TYamlString.Create(aValue.ToString);
+        end;
+    else
+      begin
+        //raise EYamlDeserializeError.CreateFmt('Not supported type "%s":%d',[aName,Integer(aValue.Kind)]);
+      end;
+    end;
+    if Result.Value = nil then Result.Value := TYamlNull.Create;
+  except
+    Result.Free;
+  end;
+end;
+
+function TRTTIYaml.Serialize(aObject : TObject; aType : TTypeKind; const aPropertyName : string) : TYamlPair;
+var
+  propinfo : PPropInfo;
+  yArray : TYamlArray;
+  ypair : TYamlPair;
+  yvalue : TYamlValue;
+  i : Integer;
+  pArr : Pointer;
+  rValue : TValue;
+  rItemValue : TValue;
+  len : Integer;
+begin
+  try
+    Result := TYamlPair.Create(aPropertyName,nil);
+
+    propinfo := GetPropInfo(aObject,aPropertyName);
+    //case propinfo.PropType.Kind of
+    case aType of
+      tkDynArray :
+        begin
+          len := 0;
+          yArray := TYamlArray.Create;
+          try
+            pArr := GetDynArrayProp(aObject,aPropertyName);
+            TValue.Make(@pArr,propinfo.PropType, rValue);
+            if rValue.IsArray then
+            begin
+              len := rValue.GetArrayLength;
+              for i := 0 to len - 1 do
+              begin
+                rItemValue := rValue.GetArrayElement(i);
+                ypair := Serialize(aPropertyName,rItemValue);
+                try
+                  //jValue := TYamlValue(jPair.YamlValue.Clone);
+                  yvalue := ypair.Value;
+                  yArray.AddElement(yvalue);
+                  //jPair.YamlValue.Owned := False;
+                finally
+                  ypair.Free;
+                  //jValue.Owned := True;
+                end;
+              end;
+            end;
+            Result.Value := yArray;
+          finally
+            //DynArrayClear(pArr,propinfo.PropType);
+            pArr := nil;
+          end;
+        end;
+      tkClass :
+        begin
+          Result.Value := TYamlValue(Serialize(GetObjectProp(aObject,aPropertyName)));
+        end;
+      tkString, tkLString, tkWString, tkUString, tkAString :
+        begin
+          Result.Value := TYamlString.Create(GetStrProp(aObject,aPropertyName));
+        end;
+      tkChar, tkWChar :
+        begin
+          Result.Value := TYamlString.Create(Char(GetOrdProp(aObject,aPropertyName)));
+        end;
+      tkInteger :
+        begin
+          Result.Value := TYamlInteger.Create(GetOrdProp(aObject,aPropertyName));
+        end;
+      tkInt64 :
+        begin
+          Result.Value := TYamlInteger.Create(GetOrdProp(aObject,aPropertyName));
+        end;
+      tkFloat :
+        begin
+          if propinfo.PropType = TypeInfo(TDateTime) then
+          begin
+            if aValue.AsExtended <> 0.0 then Result.Value := TYamlString.Create(DateTimeToJsonDate(GetFloatProp(aObject,aPropertyName)));
+          end
+          else if propinfo.PropType = TypeInfo(TDate) then
+          begin
+            if aValue.AsExtended <> 0.0 then Result.Value := TYamlString.Create(DateToStr(GetFloatProp(aObject,aPropertyName)));
+          end
+          else if propinfo.PropType = TypeInfo(TTime) then
+          begin
+            Result.Value := TYamlString.Create(TimeToStr(GetFloatProp(aObject,aPropertyName)));
+          end
+          else
+          begin
+            //Result.YamlValue := TYamlFloatNumber.Create(GetFloatProp(aObject,aPropertyName));
+            Result.Value := TYamlFloat.Create(StrToFloat(FloatProperty(aObject,propinfo)));
+          end;
+        end;
+      tkEnumeration,tkBool :
+        begin
+          if (propinfo.PropType = System.TypeInfo(Boolean)) then
+          begin
+            Result.Value := TYamlBoolean.Create(Boolean(GetOrdProp(aObject,aPropertyName)));
+          end
+          else
+          begin
+            if fUseEnumNames then Result.Value := TYamlString.Create(GetEnumName(propinfo.PropType,GetOrdProp(aObject,aPropertyName)))
+              else Result.Value := TYamlInteger.Create(GetOrdProp(aObject,aPropertyName));
+            //Result.YamlValue := TYamlString.Create(aValue.ToString);
+          end;
+        end;
+      tkSet :
+        begin
+          Result.Value := TYamlString.Create(GetSetProp(aObject,aPropertyName));
+        end;
+      {$IFNDEF FPC}
+      tkRecord :
+        begin
+          rRec := ctx.GetType(aValue.TypeInfo).AsRecord;
+          try
+            Yaml := TYamlObject.Create;
+            for rField in rRec.GetFields do
+            begin
+              Yaml.AddPair(Serialize(rField.name,rField.GetValue(aValue.GetReferenceToRawData)));
+            end;
+            Result.YamlValue := Yaml;
+          finally
+            ctx.Free;
+          end;
+        end;
+      {$ENDIF}
+      tkMethod, tkPointer, tkClassRef ,tkInterface, tkProcedure :
+        begin
+          //skip these properties
+          //FreeAndNil(Result);
+        end
+    else
+      begin
+
+        //raise EYamlDeserializeError.CreateFmt('Not supported type "%s":%d',[aName,Integer(aValue.Kind)]);
+      end;
+    end;
+    if Result.Value = nil then Result.Value := TYamlNull.Create;
+  except
+    on E : Exception do
+    begin
+      Result.Free;
+      {$IFNDEF FPC}
+      raise EYamlSerializeError.CreateFmt('Serialize error class "%s.%s" : %s',[aName,aValue.ToString,e.Message]);
+      {$ENDIF}
+    end;
+  end;
+end;
+{$ENDIF}
+
+
+{ TYamlSerializer}
+
+constructor TYamlSerializer.Create(aSerializeLevel: TSerializeLevel; aUseEnumNames : Boolean = True);
+begin
+  {$IFDEF FPC}
+  if aSerializeLevel = TSerializeLevel.slPublicProperty then raise EYamlSerializeError.Create('FreePascal RTTI only supports published properties');
+  {$ENDIF}
+  fSerializeLevel := aSerializeLevel;
+  fUseEnumNames := aUseEnumNames;
+  fUseYamlCaseSense := False;
+  fRTTIYaml := TRTTIYaml.Create(aSerializeLevel,aUseEnumNames);
+  fRTTIYaml.UseYamlCaseSense := fUseYamlCaseSense;
+end;
+
+function TYamlSerializer.YamlToObject(aType: TClass; const aYaml: string): TObject;
+var
+  Yaml: TYamlObject;
+begin
+  Yaml := TYamlObject.ParseYamlValue(aYaml) as TYamlObject;
+  try
+    Result := fRTTIYaml.DeserializeClass(aType,Yaml);
+  finally
+    Yaml.Free;
+  end;
+end;
+
+destructor TYamlSerializer.Destroy;
+begin
+  fRTTIYaml.Free;
+  inherited;
+end;
+
+function TYamlSerializer.YamlToObject(aObject: TObject; const aYaml: string): TObject;
+var
+  Yaml: TYamlObject;
+begin
+  Result := aObject;
+  Yaml := TYamlObject(TYamlObject.ParseYamlValue(aYaml));
+  try
+    fRTTIYaml.DeserializeObject(aObject,Yaml);
+  finally
+    Yaml.Free;
+  end;
+end;
+
+function TYamlSerializer.ObjectToYaml(aObject : TObject): string;
+var
+  Yaml: TYamlObject;
+begin
+  Yaml := fRTTIYaml.Serialize(aObject);
+  try
+    Result := Yaml.ToYaml;
+  finally
+    Yaml.Free;
+  end;
+end;
+
+procedure TYamlSerializer.SetSerializeLevel(const Value: TSerializeLevel);
+begin
+  fSerializeLevel := Value;
+  if Assigned(fRTTIYaml) then fRTTIYaml.fSerializeLevel := Value;
+end;
+
+procedure TYamlSerializer.SetUseEnumNames(const Value: Boolean);
+begin
+  fUseEnumNames := Value;
+  if Assigned(fRTTIYaml) then fRTTIYaml.UseEnumNames := Value;
+end;
+
+procedure TYamlSerializer.SetUseYamlCaseSense(const Value: Boolean);
+begin
+  fUseYamlCaseSense := Value;
+  if Assigned(fRTTIYaml) then fRTTIYaml.UseYamlCaseSense := Value;
+end;
+
+{$IFNDEF FPC}
+{ TCommentProperty }
+
+constructor TCommentProperty.Create(const aComment: string);
+begin
+  fComment := aComment;
+end;
+
+{ TCustomNameProperty }
+
+constructor TCustomNameProperty.Create(const aName: string);
+begin
+  fName := aName;
+end;
+{$ENDIF}
+
+
+end.

+ 27 - 8
Quick.YAML.pas

@@ -186,7 +186,6 @@ type
     class function ParsePairValue(const aPair : string) : string;
     class function ParseArrayValue(const aValue : string) : TYamlValue;
     class function GetItemLevel(const aValue : string) : Integer;
-    function InSameLevel(const aValue1, aValue2 : string) : Boolean;
     function ParseToYaml(aIndent : Integer) : string;
   protected
     procedure AddDescendant(const aDescendent: TYamlAncestor); override;
@@ -208,6 +207,7 @@ type
     function GetEnumerator: TEnumerator; inline;
     property Pairs[const aIndex: Integer]: TYamlPair read GetPair;
     function ToYaml : string;
+    function AsString : string; override;
   end;
 
   { TYamlArray }
@@ -239,6 +239,7 @@ type
     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);
@@ -298,6 +299,11 @@ begin
   Result := Self;
 end;
 
+function TYamlObject.AsString: string;
+begin
+  Result := ToYaml;
+end;
+
 constructor TYamlObject.Create(const aData: string);
 begin
   inherited Create;
@@ -393,11 +399,6 @@ begin
   Result := nil;
 end;
 
-function TYamlObject.InSameLevel(const aValue1, aValue2: string): Boolean;
-begin
-  Result := GetItemLevel(aValue1) = GetItemLevel(aValue2);
-end;
-
 class function TYamlObject.ParseArrayValue(const aValue: string): TYamlValue;
 var
   nint : Int64;
@@ -430,6 +431,8 @@ var
   aitem : string;
   yamlType : TYamlType;
 begin
+  Result := nil;
+  level := 0;
   while yaml.Count > vIndex do
   begin
     value := yaml[vIndex].Trim;
@@ -453,7 +456,8 @@ begin
       value := ParsePairValue(value);
       if (value.StartsWith('[')) and (value.EndsWith(']')) then yamlType := ytScalarArray
         else yamlType := ytScalar;
-    end;
+    end
+    else yamlType := TYamlType.ytScalar;
 
     case yamlType of
       ytArray : //is array
@@ -881,6 +885,20 @@ 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;
@@ -920,6 +938,7 @@ var
   isscalar : Boolean;
 begin
   Result := '';
+  yvalue := nil;
   yaml := TYamlWriter.Create;
   try
     indent := StringOfChar(' ',aIndent);
@@ -953,7 +972,7 @@ begin
       end;
       yaml.Writeln('');
     end;
-    if yvalue.IsScalar then
+    if (yvalue <> nil) and (yvalue.IsScalar) then
     begin
       Result := '[' + Result + ']';
       vIsScalar := True;

+ 43 - 22
QuickLib.inc

@@ -70,71 +70,78 @@
     {$endif LINUX}
     {$if CompilerVersion >= 17}
       {$define DELPHI2005_UP} //Delphi 2005 or newer
-    {$ifend}
+    {$endif}
     {$if CompilerVersion >= 18}
       {$define DELPHI2006_UP} //Delphi 2006 or newer
       {$define HASINLINE}
-    {$ifend}
+    {$endif}
     {$if CompilerVersion > 18}
       {$define DELPHI2007_UP} //Delphi 2007 or newer
-    {$ifend}
+    {$endif}
     {$if CompilerVersion = 20}
       {$define DELPHI2009_UP} //Delphi 2009
-    {$ifend}
+    {$endif}
     {$if CompilerVersion >= 21.0} //Delphi 2010
       {$define DELPHI2010_UP}
       {$define FPC_OR_UNICODE}
-    {$ifend}
+    {$endif}
     {$if CompilerVersion >= 22.0} //Delphi XE
       {$define DELPHIXE_UP}
-    {$ifend}
+    {$endif}
     {$if CompilerVersion >= 23.0} //Delphi XE2
       {$define DELPHIXE2_UP}
-    {$ifend}
+    {$endif}
     {$if CompilerVersion >= 24.0} //Delphi XE3
       {$define DELPHIXE3_UP}
-    {$ifend}
+    {$endif}
     {$if CompilerVersion >= 25.0} //Delphi XE4
       {$define DELPHIXE4_UP}
-    {$ifend}
+    {$endif}
     {$if CompilerVersion >= 26.0} //Delphi XE5
       {$define DELPHIXE5_UP}
-    {$ifend}
+    {$endif}
     {$if CompilerVersion >= 27.0} //Delphi XE6
       {$define DELPHIXE6_UP}
-    {$ifend}
+    {$endif}
     {$if CompilerVersion >= 28.0} //Delphi XE7
       {$define DELPHIXE7_UP}
-    {$ifend}
+    {$endif}
     {$if CompilerVersion >= 29.0} //Delphi XE8
       {$define DELPHIXE8_UP}
-    {$ifend}
+    {$endif}
     {$if CompilerVersion >= 30.0} //Delphi XE10 Seattle
       {$define DELPHIRX10_UP}
 	  {$define DELPHISEATTLE_UP}
-    {$ifend}
+    {$endif}
     {$if CompilerVersion >= 31.0} //Delphi RX10.1 Berlin
       {$define DELPHIRX101_UP}
 	    {$define DELPHIBERLIN_UP}
-    {$ifend}
+    {$endif}
     {$if CompilerVersion >= 32.0} //Delphi RX10.2 Tokyo
       {$define DELPHIRX102_UP}
 	    {$define DELPHITOKYO_UP}
       {$ifdef LINUX}
         {$define DELPHILINUX}
-      {$ifend}
-    {$ifend}
+      {$endif}
+    {$endif}
     {$if CompilerVersion >= 33.0} //Delphi RX10.3 Rio
       {$define DELPHIRX103_UP}
 	    {$define DELPHIRIO_UP}
-    {$ifend}
+    {$endif}
     {$if CompilerVersion >= 34.0} //Delphi RX10.4 Sydney
       {$define DELPHIRX104_UP}
 	    {$define DELPHISYDNEY_UP}
-      {$if defined(ANDROID) OR defined(LINUX) OR defined(IOS)}
+      {$if defined(ANDROID) OR defined(IOS)}
+        {$define NEXTGEN} //compatibility with older delphis
+      {$endif}
+    {$endif}
+    {$if CompilerVersion >= 35.0} //Delphi RX11 Alexandria
+      {$define DELPHIRX11_UP}
+	    {$define DELPHIALEXANDRIA_UP}
+      {$if defined(ANDROID) OR defined(IOS)}
         {$define NEXTGEN} //compatibility with older delphis
       {$endif}
-    {$ifend}
+    {$endif}
   {$else}
     //Delphi 5 or older
     {$define DELPHI6OROLDER}
@@ -161,8 +168,22 @@
 
 //Debug library
 {$IFDEF DEBUG}
-  {$DEFINE DEBUG_SERIALIZER}
-  {$DEFINE DEBUG_HTTPSERVER}
+  {.$DEFINE DEBUG_SERIALIZER}
+  {.$DEFINE DEBUG_HTTPSERVER}
+  {.$DEFINE DEBUG_OBJPOOL}
+  {.$DEFINE DEBUG_PARAMETERS}
+  {.$DEFINE DEBUG_REDIS}
 {$ENDIF}
 
+{.$DEFINE QUICK_HINTSOFF}
+{.$DEFINE QUICK_WARNOFF}
+
+{$ifdef QUICK_HINTSOFF}
+	{$HINTS OFF}
+{$endif}
+
+{$ifdef QUICK_WARNOFF}
+	{$WARNINGS OFF}
+{$endif}
+
 

+ 58 - 6
README.md

@@ -4,7 +4,7 @@
 **QuickLib**
 --------
 
-Small delphi/Firemonkey(Windows, Linux, Android, OSX & IOS) and fpc(Windows & Linux) library containing interesting and quick to implement functions, created to simplify application development and crossplatform support and improve productivity. Delphi XE8 - Delphi 10.4 Sydney supported.
+Small delphi/Firemonkey(Windows, Linux, Android, OSX & IOS) and fpc(Windows & Linux) library containing interesting and quick to implement functions, created to simplify application development and crossplatform support and improve productivity. Delphi XE8 - Delphi 11 Alexandria supported.
 
 **Areas of functionality:**
   
@@ -58,10 +58,17 @@ Small delphi/Firemonkey(Windows, Linux, Android, OSX & IOS) and fpc(Windows & Li
 * **Quick.Template:** String template replacing with dictionary or delegate.
 * **Quick.Debug.Utils:** Simple debugging and code benchmark utils.
 * **Quick.Parameters:** Work with commandline parameters like a class.
+* **Quick.Url.Utils:** Simple url manipulation
+* **Quick.RegEx.Utils:** Commonly used RegEx comparison (email verification, password complexity, etc)
+* **Quick.Conditions:** Pre and postcondition validations in fluent style.
 
 
 **Updates:**
 
+* NEW: RAD Studio 11 supported
+* NEW: Condition checks
+* NEW: Commonly used RegEx validations
+* NEW: Url manipulation utils
 * NEW: QuickParameters to work with commandline arguments like a class.
 * NEW: HttpServer custom and dynamic error pages.
 * NEW: Debug utils
@@ -817,12 +824,17 @@ Serialize/Deserialize object from/to Yaml.
 
 **Quick.Expression:**
 --
- Evaluate object properties using expressions.
+ Evaluate object properties or single values using expressions.
 ```delphi
   if TExpressionParser.Validate(user,('(Age > 30) AND (Dept.Name = "Financial")') then
   begin
     //do something
   end;
+
+  if TExpressionParser.Validate(user,('(20 > 30) OR (5 > 3)') then
+  begin
+    //do something
+  end;
 ```
 
 **Quick.Linq:**
@@ -1279,14 +1291,14 @@ type
   end;
 
 ```
-And pass to de commandline extension:
+Use param:
 ```delphi
-services.AddCommandline<TArguments>;
+params := TMyParameter.Create;
 ```
 When you call your exe with --help you get documentation. If you need to check for a switch or value, you can do like this:
 ```delphi
-if services.Commandline<TArguments>.Port = 0 then ...
-if services.Commandline<TArguments>.Silent then ...
+if params.Port = 0 then ...
+if params.Silent then ...
 ```
 QuickParameters uses custom attributes to define special parameter conditions:
 
@@ -1339,3 +1351,43 @@ Arguments:
   --Help, -h                 Show this documentation
 ```
 
+**Quick.Url.Utils:**
+--
+- **GetProtocol:** Get protocol from an url.
+- **GetHost:** Get hostname from an url.
+- **GetPath:** Get path from an url.
+- **GetQuery:** Get Query part from an url.
+- **RemoveProtocol:** Remove protocol from an url.
+- **RemoveQuery:** Remove query part from an url.
+- **EncodeUrl:** Encode path and query from and url.
+
+**Quick.RegEx.Utils:**
+--
+Commonly used validations.
+```delphi
+```
+
+**Quick.Conditions:**
+--
+Pre and postcondition validations in fluent style.
+Condition.Requires evaluates a variable for conditions before do some operations.
+Condition.Ensures evaluates a variable result for conditions after do some operations.
+```delphi
+    Condition.Requires(num, "num")
+        .IsInRange(1,10,'value for num is out of range');   // throws custom error if not in range
+        .IsNotGreater(50);   // throws ArgumentException if not equal to 128
+
+    Condition.Requires(myobj, "myobj")
+        .WithExceptionOnFailure(EMyException) //throws specific exception on failure
+        .IsNotNull()          // throws ArgumentNullException if null
+        .Evaluate(myobj.id > 10); // myobj.id must be greater than 10
+
+    Condition.Requires(text, "text")
+        .IsNotEmpty()          // throws ArgumentNullException if empty
+        .StartsWith("<html>") // throws ArgumentException if not starts with <html>
+        .EndsWith("</html>") // throws ArgumentException if not ends with </html>
+        .IsNotLowerCase // thows ArgumentException if not lowercase
+        .Evaluate(text.Contains("sometxt") or test.Contains('othertxt')); // throws ArgumentException if not evaluates
+```
+
+>Do you want to learn delphi or improve your skills? [learndelphi.org](https://learndelphi.org)

+ 1 - 0
samples/delphi/QuickAppService/ConsoleAndService/MyServiceConsole.dpr

@@ -60,6 +60,7 @@ begin
     begin
         AppService.ServiceName := 'MyService';
         AppService.DisplayName := 'MyServicesvc';
+        AppService.DesktopInteraction := False;
         {$IFDEF FPC}
         AppService.OnStart := TSrvFactory.CreateMyService;
         {$ELSE}

+ 416 - 39
samples/delphi/QuickAppService/ConsoleAndService/MyServiceConsole.dproj

@@ -7,7 +7,7 @@
         <TargetedPlatforms>1025</TargetedPlatforms>
         <AppType>Console</AppType>
         <FrameworkType>None</FrameworkType>
-        <ProjectVersion>18.5</ProjectVersion>
+        <ProjectVersion>19.1</ProjectVersion>
         <Platform Condition="'$(Platform)'==''">Win32</Platform>
     </PropertyGroup>
     <PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
@@ -18,8 +18,13 @@
         <CfgParent>Base</CfgParent>
         <Base>true</Base>
     </PropertyGroup>
-    <PropertyGroup Condition="('$(Platform)'=='iOSDevice32' and '$(Base)'=='true') or '$(Base_iOSDevice32)'!=''">
-        <Base_iOSDevice32>true</Base_iOSDevice32>
+    <PropertyGroup Condition="('$(Platform)'=='Android64' and '$(Base)'=='true') or '$(Base_Android64)'!=''">
+        <Base_Android64>true</Base_Android64>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='iOSDevice64' and '$(Base)'=='true') or '$(Base_iOSDevice64)'!=''">
+        <Base_iOSDevice64>true</Base_iOSDevice64>
         <CfgParent>Base</CfgParent>
         <Base>true</Base>
     </PropertyGroup>
@@ -43,12 +48,6 @@
         <CfgParent>Base</CfgParent>
         <Base>true</Base>
     </PropertyGroup>
-    <PropertyGroup Condition="('$(Platform)'=='iOSDevice32' and '$(Cfg_2)'=='true') or '$(Cfg_2_iOSDevice32)'!=''">
-        <Cfg_2_iOSDevice32>true</Cfg_2_iOSDevice32>
-        <CfgParent>Cfg_2</CfgParent>
-        <Cfg_2>true</Cfg_2>
-        <Base>true</Base>
-    </PropertyGroup>
     <PropertyGroup Condition="('$(Platform)'=='iOSDevice64' and '$(Cfg_2)'=='true') or '$(Cfg_2_iOSDevice64)'!=''">
         <Cfg_2_iOSDevice64>true</Cfg_2_iOSDevice64>
         <CfgParent>Cfg_2</CfgParent>
@@ -106,42 +105,53 @@
         <AUP_WRITE_EXTERNAL_STORAGE>true</AUP_WRITE_EXTERNAL_STORAGE>
         <AUP_READ_PHONE_STATE>true</AUP_READ_PHONE_STATE>
         <EnabledSysJars>android-support-v4.dex.jar;cloud-messaging.dex.jar;fmx.dex.jar;google-analytics-v2.dex.jar;google-play-billing.dex.jar;google-play-licensing.dex.jar;google-play-services-ads-7.0.0.dex.jar;google-play-services-analytics-7.0.0.dex.jar;google-play-services-base-7.0.0.dex.jar;google-play-services-identity-7.0.0.dex.jar;google-play-services-maps-7.0.0.dex.jar;google-play-services-panorama-7.0.0.dex.jar;google-play-services-plus-7.0.0.dex.jar;google-play-services-wallet-7.0.0.dex.jar</EnabledSysJars>
+        <Android_NotificationIcon24>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_24x24.png</Android_NotificationIcon24>
+        <Android_NotificationIcon36>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_36x36.png</Android_NotificationIcon36>
+        <Android_NotificationIcon48>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_48x48.png</Android_NotificationIcon48>
+        <Android_NotificationIcon72>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_72x72.png</Android_NotificationIcon72>
+        <Android_NotificationIcon96>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_96x96.png</Android_NotificationIcon96>
     </PropertyGroup>
-    <PropertyGroup Condition="'$(Base_iOSDevice32)'!=''">
-        <VerInfo_Keys>CFBundleName=$(MSBuildProjectName);CFBundleDevelopmentRegion=en;CFBundleDisplayName=$(MSBuildProjectName);CFBundleIdentifier=$(MSBuildProjectName);CFBundleInfoDictionaryVersion=7.1;CFBundleVersion=1.0.0;CFBundleShortVersionString=1.0.0;CFBundlePackageType=APPL;CFBundleSignature=????;LSRequiresIPhoneOS=true;CFBundleAllowMixedLocalizations=YES;CFBundleExecutable=$(MSBuildProjectName);UIDeviceFamily=iPhone &amp; iPad;CFBundleResourceSpecification=ResourceRules.plist;NSLocationAlwaysUsageDescription=The reason for accessing the location information of the user;NSLocationWhenInUseUsageDescription=The reason for accessing the location information of the user;FMLocalNotificationPermission=false;UIBackgroundModes=;NSContactsUsageDescription=The reason for accessing the contacts;NSPhotoLibraryUsageDescription=The reason for accessing the photo library;NSCameraUsageDescription=The reason for accessing the camera</VerInfo_Keys>
-        <VerInfo_UIDeviceFamily>iPhoneAndiPad</VerInfo_UIDeviceFamily>
-        <VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
+    <PropertyGroup Condition="'$(Base_Android64)'!=''">
+        <VerInfo_Keys>package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=</VerInfo_Keys>
         <BT_BuildType>Debug</BT_BuildType>
-        <VerInfo_BundleId>$(MSBuildProjectName)</VerInfo_BundleId>
-        <iPhone_AppIcon60>$(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_60x60.png</iPhone_AppIcon60>
-        <iPhone_AppIcon120>$(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_120x120.png</iPhone_AppIcon120>
-        <iPhone_Spotlight40>$(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_40x40.png</iPhone_Spotlight40>
-        <iPhone_Spotlight80>$(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_80x80.png</iPhone_Spotlight80>
-        <iPad_SpotLight40>$(BDS)\bin\Artwork\iOS\iPad\FM_SpotlightSearchIcon_40x40.png</iPad_SpotLight40>
-        <iPad_SpotLight80>$(BDS)\bin\Artwork\iOS\iPad\FM_SpotlightSearchIcon_80x80.png</iPad_SpotLight80>
-        <iPad_AppIcon76>$(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_76x76.png</iPad_AppIcon76>
-        <iPad_AppIcon152>$(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_152x152.png</iPad_AppIcon152>
-        <iPad_Launch768x1024>$(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImagePortrait_768x1024.png</iPad_Launch768x1024>
-        <iPad_Launch1024x768>$(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImageLandscape_1024x768.png</iPad_Launch1024x768>
-        <iPad_Launch1536x2048>$(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImagePortrait_1536x2048.png</iPad_Launch1536x2048>
-        <iPad_Launch2048x1536>$(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImageLandscape_2048x1536.png</iPad_Launch2048x1536>
+        <Base_Android>true</Base_Android>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+        <Android_LauncherIcon36>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_36x36.png</Android_LauncherIcon36>
+        <Android_LauncherIcon48>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_48x48.png</Android_LauncherIcon48>
+        <Android_LauncherIcon72>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_72x72.png</Android_LauncherIcon72>
+        <Android_LauncherIcon96>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_96x96.png</Android_LauncherIcon96>
+        <Android_LauncherIcon144>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_144x144.png</Android_LauncherIcon144>
+        <Android_SplashImage426>$(BDS)\bin\Artwork\Android\FM_SplashImage_426x320.png</Android_SplashImage426>
+        <Android_SplashImage470>$(BDS)\bin\Artwork\Android\FM_SplashImage_470x320.png</Android_SplashImage470>
+        <Android_SplashImage640>$(BDS)\bin\Artwork\Android\FM_SplashImage_640x480.png</Android_SplashImage640>
+        <Android_SplashImage960>$(BDS)\bin\Artwork\Android\FM_SplashImage_960x720.png</Android_SplashImage960>
+        <AUP_ACCESS_COARSE_LOCATION>true</AUP_ACCESS_COARSE_LOCATION>
+        <AUP_ACCESS_FINE_LOCATION>true</AUP_ACCESS_FINE_LOCATION>
+        <AUP_CALL_PHONE>true</AUP_CALL_PHONE>
+        <AUP_CAMERA>true</AUP_CAMERA>
+        <AUP_INTERNET>true</AUP_INTERNET>
+        <AUP_READ_CALENDAR>true</AUP_READ_CALENDAR>
+        <AUP_READ_EXTERNAL_STORAGE>true</AUP_READ_EXTERNAL_STORAGE>
+        <AUP_WRITE_CALENDAR>true</AUP_WRITE_CALENDAR>
+        <AUP_WRITE_EXTERNAL_STORAGE>true</AUP_WRITE_EXTERNAL_STORAGE>
+        <AUP_READ_PHONE_STATE>true</AUP_READ_PHONE_STATE>
+        <EnabledSysJars>android-support-v4.dex.jar;cloud-messaging.dex.jar;fmx.dex.jar;google-analytics-v2.dex.jar;google-play-billing.dex.jar;google-play-licensing.dex.jar;google-play-services-ads-7.0.0.dex.jar;google-play-services-analytics-7.0.0.dex.jar;google-play-services-base-7.0.0.dex.jar;google-play-services-identity-7.0.0.dex.jar;google-play-services-maps-7.0.0.dex.jar;google-play-services-panorama-7.0.0.dex.jar;google-play-services-plus-7.0.0.dex.jar;google-play-services-wallet-7.0.0.dex.jar</EnabledSysJars>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_iOSDevice64)'!=''">
+        <iOS_AppStore1024>$(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_1024x1024.png</iOS_AppStore1024>
     </PropertyGroup>
     <PropertyGroup Condition="'$(Base_iOSSimulator)'!=''">
         <VerInfo_Keys>CFBundleName=$(MSBuildProjectName);CFBundleDevelopmentRegion=en;CFBundleDisplayName=$(MSBuildProjectName);CFBundleIdentifier=$(MSBuildProjectName);CFBundleInfoDictionaryVersion=7.1;CFBundleVersion=1.0.0;CFBundleShortVersionString=1.0.0;CFBundlePackageType=APPL;CFBundleSignature=????;LSRequiresIPhoneOS=true;CFBundleAllowMixedLocalizations=YES;CFBundleExecutable=$(MSBuildProjectName);UIDeviceFamily=iPhone &amp; iPad;CFBundleResourceSpecification=ResourceRules.plist;NSLocationAlwaysUsageDescription=The reason for accessing the location information of the user;NSLocationWhenInUseUsageDescription=The reason for accessing the location information of the user;FMLocalNotificationPermission=false;UIBackgroundModes=;NSContactsUsageDescription=The reason for accessing the contacts;NSPhotoLibraryUsageDescription=The reason for accessing the photo library;NSCameraUsageDescription=The reason for accessing the camera</VerInfo_Keys>
         <VerInfo_UIDeviceFamily>iPhoneAndiPad</VerInfo_UIDeviceFamily>
         <VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
-        <iPhone_AppIcon60>$(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_60x60.png</iPhone_AppIcon60>
         <iPhone_AppIcon120>$(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_120x120.png</iPhone_AppIcon120>
-        <iPhone_Spotlight40>$(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_40x40.png</iPhone_Spotlight40>
         <iPhone_Spotlight80>$(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_80x80.png</iPhone_Spotlight80>
-        <iPad_SpotLight40>$(BDS)\bin\Artwork\iOS\iPad\FM_SpotlightSearchIcon_40x40.png</iPad_SpotLight40>
         <iPad_SpotLight80>$(BDS)\bin\Artwork\iOS\iPad\FM_SpotlightSearchIcon_80x80.png</iPad_SpotLight80>
-        <iPad_AppIcon76>$(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_76x76.png</iPad_AppIcon76>
         <iPad_AppIcon152>$(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_152x152.png</iPad_AppIcon152>
-        <iPad_Launch768x1024>$(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImagePortrait_768x1024.png</iPad_Launch768x1024>
-        <iPad_Launch1024x768>$(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImageLandscape_1024x768.png</iPad_Launch1024x768>
-        <iPad_Launch1536x2048>$(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImagePortrait_1536x2048.png</iPad_Launch1536x2048>
-        <iPad_Launch2048x1536>$(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImageLandscape_2048x1536.png</iPad_Launch2048x1536>
+        <iPhone_Notification60>$(BDS)\bin\Artwork\iOS\iPhone\FM_NotificationIcon_60x60.png</iPhone_Notification60>
+        <iPhone_Notification40>$(BDS)\bin\Artwork\iOS\iPhone\FM_NotificationIcon_40x40.png</iPhone_Notification40>
+        <iPad_Notification40>$(BDS)\bin\Artwork\iOS\iPad\FM_NotificationIcon_40x40.png</iPad_Notification40>
     </PropertyGroup>
     <PropertyGroup Condition="'$(Base_Win32)'!=''">
         <DCC_Namespace>Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
@@ -160,14 +170,14 @@
         <DCC_Optimize>false</DCC_Optimize>
         <DCC_GenerateStackFrames>true</DCC_GenerateStackFrames>
     </PropertyGroup>
-    <PropertyGroup Condition="'$(Cfg_2_iOSDevice32)'!=''">
-        <DCC_RemoteDebug>true</DCC_RemoteDebug>
-    </PropertyGroup>
     <PropertyGroup Condition="'$(Cfg_2_iOSDevice64)'!=''">
         <BT_BuildType>Debug</BT_BuildType>
     </PropertyGroup>
     <PropertyGroup Condition="'$(Cfg_2_iOSSimulator)'!=''">
         <DCC_RemoteDebug>true</DCC_RemoteDebug>
+        <iPhone_Notification60>$(BDS)\bin\Artwork\iOS\iPhone\FM_NotificationIcon_60x60.png</iPhone_Notification60>
+        <iPhone_Notification40>$(BDS)\bin\Artwork\iOS\iPhone\FM_NotificationIcon_40x40.png</iPhone_Notification40>
+        <iPad_Notification40>$(BDS)\bin\Artwork\iOS\iPad\FM_NotificationIcon_40x40.png</iPad_Notification40>
     </PropertyGroup>
     <PropertyGroup Condition="'$(Cfg_2_Win32)'!=''">
         <VerInfo_Locale>1033</VerInfo_Locale>
@@ -213,10 +223,9 @@
             </Delphi.Personality>
             <Platforms>
                 <Platform value="Android">False</Platform>
-                <Platform value="iOSDevice32">False</Platform>
+                <Platform value="Android64">False</Platform>
                 <Platform value="iOSDevice64">True</Platform>
                 <Platform value="iOSSimulator">False</Platform>
-                <Platform value="OSX32">False</Platform>
                 <Platform value="Win32">True</Platform>
                 <Platform value="Win64">False</Platform>
             </Platforms>
@@ -270,12 +279,20 @@
                         <RemoteDir>classes</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>classes</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="AndroidFileProvider">
                     <Platform Name="Android">
                         <RemoteDir>res\xml</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\xml</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="AndroidGDBServer">
                     <Platform Name="Android">
@@ -288,96 +305,242 @@
                         <RemoteDir>library\lib\armeabi</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\armeabi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidLibnativeArmeabiv7aFile">
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="AndroidLibnativeMipsFile">
                     <Platform Name="Android">
                         <RemoteDir>library\lib\mips</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\mips</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="AndroidServiceOutput">
                     <Platform Name="Android">
                         <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\arm64-v8a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidServiceOutput_Android32">
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="AndroidSplashImageDef">
                     <Platform Name="Android">
                         <RemoteDir>res\drawable</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="AndroidSplashStyles">
                     <Platform Name="Android">
                         <RemoteDir>res\values</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="AndroidSplashStylesV21">
                     <Platform Name="Android">
                         <RemoteDir>res\values-v21</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\values-v21</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_Colors">
+                    <Platform Name="Android">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="Android_DefaultAppIcon">
                     <Platform Name="Android">
                         <RemoteDir>res\drawable</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="Android_LauncherIcon144">
                     <Platform Name="Android">
                         <RemoteDir>res\drawable-xxhdpi</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="Android_LauncherIcon36">
                     <Platform Name="Android">
                         <RemoteDir>res\drawable-ldpi</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-ldpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="Android_LauncherIcon48">
                     <Platform Name="Android">
                         <RemoteDir>res\drawable-mdpi</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-mdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="Android_LauncherIcon72">
                     <Platform Name="Android">
                         <RemoteDir>res\drawable-hdpi</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-hdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="Android_LauncherIcon96">
                     <Platform Name="Android">
                         <RemoteDir>res\drawable-xhdpi</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_NotificationIcon24">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-mdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-mdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_NotificationIcon36">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-hdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-hdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_NotificationIcon48">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_NotificationIcon72">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_NotificationIcon96">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xxxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xxxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="Android_SplashImage426">
                     <Platform Name="Android">
                         <RemoteDir>res\drawable-small</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-small</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="Android_SplashImage470">
                     <Platform Name="Android">
                         <RemoteDir>res\drawable-normal</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-normal</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="Android_SplashImage640">
                     <Platform Name="Android">
                         <RemoteDir>res\drawable-large</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-large</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="Android_SplashImage960">
                     <Platform Name="Android">
                         <RemoteDir>res\drawable-xlarge</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xlarge</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_Strings">
+                    <Platform Name="Android">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="DebugSymbols">
                     <Platform Name="iOSSimulator">
@@ -447,6 +610,9 @@
                     <Platform Name="Android">
                         <Operation>0</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <Operation>0</Operation>
+                    </Platform>
                     <Platform Name="iOSDevice32">
                         <Operation>0</Operation>
                     </Platform>
@@ -466,6 +632,32 @@
                         <Operation>0</Operation>
                     </Platform>
                 </DeployClass>
+                <DeployClass Name="iOS_AppStore1024">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_AppIcon152">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_AppIcon167">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
                 <DeployClass Name="iPad_Launch1024">
                     <Platform Name="iOSDevice32">
                         <Operation>1</Operation>
@@ -499,6 +691,16 @@
                         <Operation>1</Operation>
                     </Platform>
                 </DeployClass>
+                <DeployClass Name="iPad_Launch2x">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
                 <DeployClass Name="iPad_Launch768">
                     <Platform Name="iOSDevice32">
                         <Operation>1</Operation>
@@ -510,6 +712,76 @@
                         <Operation>1</Operation>
                     </Platform>
                 </DeployClass>
+                <DeployClass Name="iPad_LaunchDark2x">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_Notification40">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_Setting58">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_SpotLight80">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_AppIcon120">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_AppIcon180">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch2x">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
                 <DeployClass Name="iPhone_Launch320">
                     <Platform Name="iOSDevice32">
                         <Operation>1</Operation>
@@ -521,6 +793,16 @@
                         <Operation>1</Operation>
                     </Platform>
                 </DeployClass>
+                <DeployClass Name="iPhone_Launch3x">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
                 <DeployClass Name="iPhone_Launch640">
                     <Platform Name="iOSDevice32">
                         <Operation>1</Operation>
@@ -543,10 +825,93 @@
                         <Operation>1</Operation>
                     </Platform>
                 </DeployClass>
+                <DeployClass Name="iPhone_LaunchDark2x">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_LaunchDark3x">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Notification40">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Notification60">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Setting58">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Setting87">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Spotlight120">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Spotlight80">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
                 <DeployClass Name="ProjectAndroidManifest">
                     <Platform Name="Android">
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="ProjectiOSDeviceDebug">
                     <Platform Name="iOSDevice32">
@@ -561,6 +926,7 @@
                 <DeployClass Name="ProjectiOSDeviceResourceRules"/>
                 <DeployClass Name="ProjectiOSEntitlements"/>
                 <DeployClass Name="ProjectiOSInfoPList"/>
+                <DeployClass Name="ProjectiOSLaunchScreen"/>
                 <DeployClass Name="ProjectiOSResource">
                     <Platform Name="iOSDevice32">
                         <Operation>1</Operation>
@@ -590,6 +956,10 @@
                         <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\arm64-v8a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                     <Platform Name="iOSDevice32">
                         <Operation>1</Operation>
                     </Platform>
@@ -612,6 +982,12 @@
                         <Operation>0</Operation>
                     </Platform>
                 </DeployClass>
+                <DeployClass Name="ProjectOutput_Android32">
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
                 <DeployClass Name="ProjectUWPManifest">
                     <Platform Name="Win32">
                         <Operation>1</Operation>
@@ -649,6 +1025,7 @@
                 <ProjectRoot Platform="Android" Name="$(PROJECTNAME)"/>
                 <ProjectRoot Platform="OSX64" Name="$(PROJECTNAME)"/>
                 <ProjectRoot Platform="iOSSimulator" Name="$(PROJECTNAME).app"/>
+                <ProjectRoot Platform="Android64" Name="$(PROJECTNAME)"/>
             </Deployment>
         </BorlandProject>
         <ProjectFileVersion>12</ProjectFileVersion>

+ 15 - 2
samples/delphi/QuickCollections/InterfacedLists.dpr

@@ -55,6 +55,8 @@ begin
 
     //add values
     myarray := ['Joe','Mat','Lee'];
+    //remove if starts with J
+    myarray.Where('^J',True).Delete;
     //search for regex match
     cout('Search for regex match',ccYellow);
     for name in myarray.Where('e$',True).Select do
@@ -73,9 +75,9 @@ begin
 
     //search for regex match
     cout('Search for regex match',ccYellow);
-    for name in List.Where('e$',True).Select do
+    for name in List.Where('^Ma',True).Select do
     begin
-      cout('User %s ends with "e"',[name],etInfo);
+      cout('User %s starts with "Ma"',[name],etInfo);
     end;
 
     //add values to objectlist
@@ -102,6 +104,17 @@ begin
     user := ListObj.Where('Roles2 CONTAINS ?',['SuperAdmin']).SelectFirst;
     if user <> nil then cout('%s is %s',[user.Name,CommaText(user.Roles)],etInfo);
 
+    cout('List before remove Mat',ccYellow);
+    for user in ListObj do
+    begin
+      cout('User "%s"',[user.Name],etInfo);
+    end;
+    ListObj.Where('Name = ?',['Mat']).Delete;
+    cout('List after remove Mat',ccYellow);
+    for user in ListObj do
+    begin
+      cout('User "%s"',[user.Name],etInfo);
+    end;
 
     cout('Press ENTER to Exit',ccYellow);
     ConsoleWaitForEnterKey;

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1 - 89
samples/delphi/QuickCollections/InterfacedLists.dproj


+ 46 - 0
samples/delphi/QuickCommons/Url/Url_Manipulation.dpr

@@ -0,0 +1,46 @@
+program Url_Manipulation;
+
+{$APPTYPE CONSOLE}
+
+{$R *.res}
+
+uses
+  System.SysUtils,
+  Quick.Commons,
+  Quick.Console;
+
+const
+  aurls : array[0..4] of string = ('https://mydomain.com',
+                            'http://www.google.com/Test/other',
+                            'www.google.com/test/other?query=1&other=2',
+                            'http://127.0.0.1:80/onemoretest/',
+                            'www.google.com');
+
+var
+  i : Integer;
+  host : string;
+  path : string;
+  query : string;
+  woquery : string;
+begin
+  try
+    for i := Low(aurls) to High(aurls) do
+    begin
+      cout('URL="%s"',[aurls[i]],etWarning);
+      host := UrlGetHost(aurls[i]);
+      path := UrlGetPath(aurls[i]);
+      query := UrlGetQuery(aurls[i]);
+      woquery := UrlRemovequery(aurls[i]);
+      cout('Host="%s"',[host],etInfo);
+      cout('Path="%s"',[path],etInfo);
+      cout('Query="%s"',[query],etInfo);
+      cout('Without query="%s"',[woquery],etInfo);
+      cout('------------',etWarning);
+    end;
+    ConsoleWaitForEnterKey;
+
+  except
+    on E: Exception do
+      Writeln(E.ClassName, ': ', E.Message);
+  end;
+end.

+ 980 - 0
samples/delphi/QuickCommons/Url/Url_Manipulation.dproj

@@ -0,0 +1,980 @@
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+    <PropertyGroup>
+        <ProjectGuid>{CA4490EB-9A6D-423A-A76A-6197C3A291E9}</ProjectGuid>
+        <ProjectVersion>19.1</ProjectVersion>
+        <FrameworkType>None</FrameworkType>
+        <Base>True</Base>
+        <Config Condition="'$(Config)'==''">Debug</Config>
+        <Platform Condition="'$(Platform)'==''">Win32</Platform>
+        <TargetedPlatforms>1</TargetedPlatforms>
+        <AppType>Console</AppType>
+        <MainSource>Url_Manipulation.dpr</MainSource>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Android' and '$(Base)'=='true') or '$(Base_Android)'!=''">
+        <Base_Android>true</Base_Android>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Android64' and '$(Base)'=='true') or '$(Base_Android64)'!=''">
+        <Base_Android64>true</Base_Android64>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='iOSDevice64' and '$(Base)'=='true') or '$(Base_iOSDevice64)'!=''">
+        <Base_iOSDevice64>true</Base_iOSDevice64>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='iOSSimulator' and '$(Base)'=='true') or '$(Base_iOSSimulator)'!=''">
+        <Base_iOSSimulator>true</Base_iOSSimulator>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='OSX64' and '$(Base)'=='true') or '$(Base_OSX64)'!=''">
+        <Base_OSX64>true</Base_OSX64>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''">
+        <Base_Win32>true</Base_Win32>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Base)'=='true') or '$(Base_Win64)'!=''">
+        <Base_Win64>true</Base_Win64>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_1)'!=''">
+        <Cfg_1>true</Cfg_1>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_1)'=='true') or '$(Cfg_1_Win32)'!=''">
+        <Cfg_1_Win32>true</Cfg_1_Win32>
+        <CfgParent>Cfg_1</CfgParent>
+        <Cfg_1>true</Cfg_1>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_2)'!=''">
+        <Cfg_2>true</Cfg_2>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base)'!=''">
+        <DCC_DcuOutput>.\$(Platform)\$(Config)</DCC_DcuOutput>
+        <DCC_ExeOutput>.\$(Platform)\$(Config)</DCC_ExeOutput>
+        <DCC_E>false</DCC_E>
+        <DCC_N>false</DCC_N>
+        <DCC_S>false</DCC_S>
+        <DCC_F>false</DCC_F>
+        <DCC_K>false</DCC_K>
+        <DCC_Namespace>System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace)</DCC_Namespace>
+        <SanitizedProjectName>Url_Manipulation</SanitizedProjectName>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Android)'!=''">
+        <DCC_UsePackage>DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;FMXComponents;tethering;bindcompfmx;FmxTeeUI;fmx;FireDACIBDriver;dbexpress;IndyCore;dsnap;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;inet;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;FMXTee;soaprtl;DbxCommonDriver;xmlrtl;soapmidas;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;dbrtl;IndyProtocols;$(DCC_UsePackage)</DCC_UsePackage>
+        <Android_LauncherIcon36>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_36x36.png</Android_LauncherIcon36>
+        <Android_LauncherIcon48>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_48x48.png</Android_LauncherIcon48>
+        <Android_LauncherIcon72>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_72x72.png</Android_LauncherIcon72>
+        <Android_LauncherIcon96>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_96x96.png</Android_LauncherIcon96>
+        <Android_LauncherIcon144>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_144x144.png</Android_LauncherIcon144>
+        <Android_SplashImage426>$(BDS)\bin\Artwork\Android\FM_SplashImage_426x320.png</Android_SplashImage426>
+        <Android_SplashImage470>$(BDS)\bin\Artwork\Android\FM_SplashImage_470x320.png</Android_SplashImage470>
+        <Android_SplashImage640>$(BDS)\bin\Artwork\Android\FM_SplashImage_640x480.png</Android_SplashImage640>
+        <Android_SplashImage960>$(BDS)\bin\Artwork\Android\FM_SplashImage_960x720.png</Android_SplashImage960>
+        <Android_NotificationIcon24>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_24x24.png</Android_NotificationIcon24>
+        <Android_NotificationIcon36>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_36x36.png</Android_NotificationIcon36>
+        <Android_NotificationIcon48>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_48x48.png</Android_NotificationIcon48>
+        <Android_NotificationIcon72>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_72x72.png</Android_NotificationIcon72>
+        <Android_NotificationIcon96>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_96x96.png</Android_NotificationIcon96>
+        <EnabledSysJars>android-support-v4.dex.jar;cloud-messaging.dex.jar;com-google-android-gms.play-services-ads-base.17.2.0.dex.jar;com-google-android-gms.play-services-ads-identifier.16.0.0.dex.jar;com-google-android-gms.play-services-ads-lite.17.2.0.dex.jar;com-google-android-gms.play-services-ads.17.2.0.dex.jar;com-google-android-gms.play-services-analytics-impl.16.0.8.dex.jar;com-google-android-gms.play-services-analytics.16.0.8.dex.jar;com-google-android-gms.play-services-base.16.0.1.dex.jar;com-google-android-gms.play-services-basement.16.2.0.dex.jar;com-google-android-gms.play-services-gass.17.2.0.dex.jar;com-google-android-gms.play-services-identity.16.0.0.dex.jar;com-google-android-gms.play-services-maps.16.1.0.dex.jar;com-google-android-gms.play-services-measurement-base.16.4.0.dex.jar;com-google-android-gms.play-services-measurement-sdk-api.16.4.0.dex.jar;com-google-android-gms.play-services-stats.16.0.1.dex.jar;com-google-android-gms.play-services-tagmanager-v4-impl.16.0.8.dex.jar;com-google-android-gms.play-services-tasks.16.0.1.dex.jar;com-google-android-gms.play-services-wallet.16.0.1.dex.jar;com-google-firebase.firebase-analytics.16.4.0.dex.jar;com-google-firebase.firebase-common.16.1.0.dex.jar;com-google-firebase.firebase-iid-interop.16.0.1.dex.jar;com-google-firebase.firebase-iid.17.1.1.dex.jar;com-google-firebase.firebase-measurement-connector.17.0.1.dex.jar;com-google-firebase.firebase-messaging.17.5.0.dex.jar;fmx.dex.jar;google-play-billing.dex.jar;google-play-licensing.dex.jar</EnabledSysJars>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Android64)'!=''">
+        <DCC_UsePackage>DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;FMXComponents;tethering;bindcompfmx;FmxTeeUI;fmx;FireDACIBDriver;dbexpress;IndyCore;dsnap;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;inet;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;FMXTee;soaprtl;DbxCommonDriver;xmlrtl;soapmidas;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;dbrtl;IndyProtocols;$(DCC_UsePackage)</DCC_UsePackage>
+        <Android_LauncherIcon36>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_36x36.png</Android_LauncherIcon36>
+        <Android_LauncherIcon48>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_48x48.png</Android_LauncherIcon48>
+        <Android_LauncherIcon72>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_72x72.png</Android_LauncherIcon72>
+        <Android_LauncherIcon96>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_96x96.png</Android_LauncherIcon96>
+        <Android_LauncherIcon144>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_144x144.png</Android_LauncherIcon144>
+        <Android_SplashImage426>$(BDS)\bin\Artwork\Android\FM_SplashImage_426x320.png</Android_SplashImage426>
+        <Android_SplashImage470>$(BDS)\bin\Artwork\Android\FM_SplashImage_470x320.png</Android_SplashImage470>
+        <Android_SplashImage640>$(BDS)\bin\Artwork\Android\FM_SplashImage_640x480.png</Android_SplashImage640>
+        <Android_SplashImage960>$(BDS)\bin\Artwork\Android\FM_SplashImage_960x720.png</Android_SplashImage960>
+        <Android_NotificationIcon24>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_24x24.png</Android_NotificationIcon24>
+        <Android_NotificationIcon36>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_36x36.png</Android_NotificationIcon36>
+        <Android_NotificationIcon48>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_48x48.png</Android_NotificationIcon48>
+        <Android_NotificationIcon72>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_72x72.png</Android_NotificationIcon72>
+        <Android_NotificationIcon96>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_96x96.png</Android_NotificationIcon96>
+        <EnabledSysJars>android-support-v4.dex.jar;cloud-messaging.dex.jar;com-google-android-gms.play-services-ads-base.17.2.0.dex.jar;com-google-android-gms.play-services-ads-identifier.16.0.0.dex.jar;com-google-android-gms.play-services-ads-lite.17.2.0.dex.jar;com-google-android-gms.play-services-ads.17.2.0.dex.jar;com-google-android-gms.play-services-analytics-impl.16.0.8.dex.jar;com-google-android-gms.play-services-analytics.16.0.8.dex.jar;com-google-android-gms.play-services-base.16.0.1.dex.jar;com-google-android-gms.play-services-basement.16.2.0.dex.jar;com-google-android-gms.play-services-gass.17.2.0.dex.jar;com-google-android-gms.play-services-identity.16.0.0.dex.jar;com-google-android-gms.play-services-maps.16.1.0.dex.jar;com-google-android-gms.play-services-measurement-base.16.4.0.dex.jar;com-google-android-gms.play-services-measurement-sdk-api.16.4.0.dex.jar;com-google-android-gms.play-services-stats.16.0.1.dex.jar;com-google-android-gms.play-services-tagmanager-v4-impl.16.0.8.dex.jar;com-google-android-gms.play-services-tasks.16.0.1.dex.jar;com-google-android-gms.play-services-wallet.16.0.1.dex.jar;com-google-firebase.firebase-analytics.16.4.0.dex.jar;com-google-firebase.firebase-common.16.1.0.dex.jar;com-google-firebase.firebase-iid-interop.16.0.1.dex.jar;com-google-firebase.firebase-iid.17.1.1.dex.jar;com-google-firebase.firebase-measurement-connector.17.0.1.dex.jar;com-google-firebase.firebase-messaging.17.5.0.dex.jar;fmx.dex.jar;google-play-billing.dex.jar;google-play-licensing.dex.jar</EnabledSysJars>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_iOSDevice64)'!=''">
+        <DCC_UsePackage>DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;tethering;bindcompfmx;TMSFMXPackPkgDXE13;FmxTeeUI;fmx;FireDACIBDriver;dbexpress;IndyCore;dsnap;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;inet;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;FMXTee;soaprtl;DbxCommonDriver;xmlrtl;soapmidas;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;dbrtl;IndyProtocols;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_iOSSimulator)'!=''">
+        <DCC_UsePackage>DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;tethering;bindcompfmx;FmxTeeUI;fmx;FireDACIBDriver;dbexpress;IndyCore;dsnap;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;inet;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;FMXTee;soaprtl;DbxCommonDriver;xmlrtl;soapmidas;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;dbrtl;IndyProtocols;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_OSX64)'!=''">
+        <DCC_UsePackage>DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;tethering;bindcompfmx;inetdb;FmxTeeUI;fmx;FireDACIBDriver;fmxdae;dbexpress;IndyCore;dsnap;FireDACCommon;RESTBackendComponents;soapserver;bindengine;DBXMySQLDriver;CloudService;FireDACMySQLDriver;FireDACCommonODBC;FireDACCommonDriver;inet;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;FireDACPgDriver;FMXTee;soaprtl;DbxCommonDriver;xmlrtl;soapmidas;fmxobj;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;dbrtl;IndyProtocols;inetdbxpress;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
+        <DCC_ConsoleTarget>true</DCC_ConsoleTarget>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Win32)'!=''">
+        <DCC_UsePackage>DBXSqliteDriver;RESTComponents;OmniThreadLibraryRuntime;DBXInterBaseDriver;vclactnband;vclFireDAC;FMXComponents;bindcompvclsmp;tethering;svnui;JvGlobus;FireDACADSDriver;JvPluginSystem;JvMM;PngComponentsD;vcltouch;JvBands;vcldb;bindcompfmx;svn;JvJans;JvNet;inetdb;JvAppFrm;TMSFMXPackPkgDXE13;FmxTeeUI;JvDotNetCtrls;TMSVCLUIPackPkgWizDXE13;fmx;FireDACIBDriver;fmxdae;vcledge;JvWizards;dbexpress;IndyCore;TMSVCLUIPackPkgXlsDXE13;vclx;JvPageComps;dsnap;FireDACCommon;JvDB;RESTBackendComponents;VCLRESTComponents;soapserver;JclDeveloperTools;TMSVCLUIPackPkgDXE13;vclie;TMSVCLIWPkgDEDXE13;bindengine;DBXMySQLDriver;CloudService;JvCmp;FireDACMySQLDriver;JvHMI;FireDACCommonODBC;FireDACCommonDriver;FMXComponentEd;inet;TMSVCLUIPackPkgExDXE13;IndyIPCommon;bindcompdbx;JvCustom;vcl;IndyIPServer;JvXPCtrls;IndySystem;dsnapcon;TMSVCLIWPkgDXE13;FireDACMSAccDriver;fmxFireDAC;vclimg;TeeDB;FireDAC;Jcl;JvCore;JvCrypt;FireDACSqliteDriver;FireDACPgDriver;FMXTee;soaprtl;DbxCommonDriver;JvDlgs;JvRuntimeDesign;JvManagedThreads;Tee;xmlrtl;soapmidas;JvTimeFramework;fmxobj;vclwinx;rtl;DbxClientDriver;CustomIPTransport;vcldsnap;JvSystem;JvStdCtrls;bindcomp;appanalytics;IndyIPClient;bindcompvcl;TeeUI;JvDocking;dbxcds;VclSmp;JvPascalInterpreter;adortl;JclVcl;dsnapxml;dbrtl;IndyProtocols;inetdbxpress;JvControls;JvPrintPreview;JclContainers;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
+        <DCC_Namespace>Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
+        <BT_BuildType>Debug</BT_BuildType>
+        <VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
+        <VerInfo_Locale>1033</VerInfo_Locale>
+        <DCC_ConsoleTarget>true</DCC_ConsoleTarget>
+        <UWP_DelphiLogo44>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png</UWP_DelphiLogo44>
+        <UWP_DelphiLogo150>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png</UWP_DelphiLogo150>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Win64)'!=''">
+        <DCC_UsePackage>DBXSqliteDriver;RESTComponents;OmniThreadLibraryRuntime;DBXInterBaseDriver;vclactnband;vclFireDAC;bindcompvclsmp;tethering;FireDACADSDriver;PngComponentsD;vcltouch;vcldb;bindcompfmx;inetdb;FmxTeeUI;fmx;FireDACIBDriver;fmxdae;vcledge;dbexpress;IndyCore;vclx;dsnap;FireDACCommon;RESTBackendComponents;VCLRESTComponents;soapserver;TMSVCLUIPackPkgDXE13;vclie;bindengine;DBXMySQLDriver;CloudService;FireDACMySQLDriver;FireDACCommonODBC;FireDACCommonDriver;inet;TMSVCLUIPackPkgExDXE13;IndyIPCommon;bindcompdbx;vcl;IndyIPServer;IndySystem;dsnapcon;TMSVCLIWPkgDXE13;FireDACMSAccDriver;fmxFireDAC;vclimg;TeeDB;FireDAC;FireDACSqliteDriver;FireDACPgDriver;FMXTee;soaprtl;DbxCommonDriver;Tee;xmlrtl;soapmidas;fmxobj;vclwinx;rtl;DbxClientDriver;CustomIPTransport;vcldsnap;bindcomp;appanalytics;IndyIPClient;bindcompvcl;TeeUI;dbxcds;VclSmp;adortl;dsnapxml;dbrtl;IndyProtocols;inetdbxpress;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
+        <DCC_ConsoleTarget>true</DCC_ConsoleTarget>
+        <UWP_DelphiLogo44>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png</UWP_DelphiLogo44>
+        <UWP_DelphiLogo150>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png</UWP_DelphiLogo150>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_1)'!=''">
+        <DCC_Define>DEBUG;$(DCC_Define)</DCC_Define>
+        <DCC_DebugDCUs>true</DCC_DebugDCUs>
+        <DCC_Optimize>false</DCC_Optimize>
+        <DCC_GenerateStackFrames>true</DCC_GenerateStackFrames>
+        <DCC_DebugInfoInExe>true</DCC_DebugInfoInExe>
+        <DCC_RemoteDebug>true</DCC_RemoteDebug>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_1_Win32)'!=''">
+        <DCC_RemoteDebug>false</DCC_RemoteDebug>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2)'!=''">
+        <DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
+        <DCC_Define>RELEASE;$(DCC_Define)</DCC_Define>
+        <DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo>
+        <DCC_DebugInformation>0</DCC_DebugInformation>
+    </PropertyGroup>
+    <ItemGroup>
+        <DelphiCompile Include="$(MainSource)">
+            <MainSource>MainSource</MainSource>
+        </DelphiCompile>
+        <BuildConfiguration Include="Release">
+            <Key>Cfg_2</Key>
+            <CfgParent>Base</CfgParent>
+        </BuildConfiguration>
+        <BuildConfiguration Include="Base">
+            <Key>Base</Key>
+        </BuildConfiguration>
+        <BuildConfiguration Include="Debug">
+            <Key>Cfg_1</Key>
+            <CfgParent>Base</CfgParent>
+        </BuildConfiguration>
+    </ItemGroup>
+    <ProjectExtensions>
+        <Borland.Personality>Delphi.Personality.12</Borland.Personality>
+        <Borland.ProjectType>Application</Borland.ProjectType>
+        <BorlandProject>
+            <Delphi.Personality>
+                <Source>
+                    <Source Name="MainSource">Url_Manipulation.dpr</Source>
+                </Source>
+            </Delphi.Personality>
+            <Deployment Version="3">
+                <DeployFile LocalName="Win32\Debug\Url_Manipulation.exe" Configuration="Debug" Class="ProjectOutput">
+                    <Platform Name="Win32">
+                        <RemoteName>Url_Manipulation.exe</RemoteName>
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile LocalName="$(BDS)\Redist\osx32\libcgunwind.1.0.dylib" Class="DependencyModule">
+                    <Platform Name="OSX32">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile LocalName="$(BDS)\Redist\iossimulator\libcgunwind.1.0.dylib" Class="DependencyModule">
+                    <Platform Name="iOSSimulator">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile LocalName="$(BDS)\Redist\iossimulator\libpcre.dylib" Class="DependencyModule">
+                    <Platform Name="iOSSimulator">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployClass Name="AdditionalDebugSymbols">
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidClassesDexFile">
+                    <Platform Name="Android">
+                        <RemoteDir>classes</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>classes</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidFileProvider">
+                    <Platform Name="Android">
+                        <RemoteDir>res\xml</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\xml</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidGDBServer">
+                    <Platform Name="Android">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidLibnativeArmeabiFile">
+                    <Platform Name="Android">
+                        <RemoteDir>library\lib\armeabi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\armeabi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidLibnativeArmeabiv7aFile">
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidLibnativeMipsFile">
+                    <Platform Name="Android">
+                        <RemoteDir>library\lib\mips</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\mips</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidServiceOutput">
+                    <Platform Name="Android">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\arm64-v8a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidServiceOutput_Android32">
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidSplashImageDef">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidSplashStyles">
+                    <Platform Name="Android">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidSplashStylesV21">
+                    <Platform Name="Android">
+                        <RemoteDir>res\values-v21</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\values-v21</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_Colors">
+                    <Platform Name="Android">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_DefaultAppIcon">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon144">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon36">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-ldpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-ldpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon48">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-mdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-mdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon72">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-hdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-hdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon96">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_NotificationIcon24">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-mdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-mdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_NotificationIcon36">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-hdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-hdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_NotificationIcon48">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_NotificationIcon72">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_NotificationIcon96">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xxxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xxxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_SplashImage426">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-small</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-small</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_SplashImage470">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-normal</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-normal</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_SplashImage640">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-large</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-large</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_SplashImage960">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xlarge</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xlarge</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_Strings">
+                    <Platform Name="Android">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="DebugSymbols">
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="DependencyFramework">
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.framework</Extensions>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.framework</Extensions>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="DependencyModule">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                        <Extensions>.dll;.bpl</Extensions>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Required="true" Name="DependencyPackage">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                        <Extensions>.bpl</Extensions>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="File">
+                    <Platform Name="Android">
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice32">
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\Resources\StartUp\</RemoteDir>
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\Resources\StartUp\</RemoteDir>
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iOS_AppStore1024">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_AppIcon152">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_AppIcon167">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_Launch2x">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_LaunchDark2x">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_Notification40">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_Setting58">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_SpotLight80">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_AppIcon120">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_AppIcon180">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch2x">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch3x">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_LaunchDark2x">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_LaunchDark3x">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Notification40">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Notification60">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Setting58">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Setting87">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Spotlight120">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Spotlight80">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectAndroidManifest">
+                    <Platform Name="Android">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectiOSDeviceDebug">
+                    <Platform Name="iOSDevice32">
+                        <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectiOSEntitlements">
+                    <Platform Name="iOSDevice32">
+                        <RemoteDir>..\</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectiOSInfoPList">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectiOSLaunchScreen">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen</RemoteDir>
+                        <Operation>64</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen</RemoteDir>
+                        <Operation>64</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectiOSResource">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectOSXDebug">
+                    <Platform Name="OSX64">
+                        <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectOSXEntitlements">
+                    <Platform Name="OSX32">
+                        <RemoteDir>..\</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>..\</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectOSXInfoPList">
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectOSXResource">
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\Resources</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\Resources</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Required="true" Name="ProjectOutput">
+                    <Platform Name="Android">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\arm64-v8a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Linux64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectOutput_Android32">
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectUWPManifest">
+                    <Platform Name="Win32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win64">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="UWP_DelphiLogo150">
+                    <Platform Name="Win32">
+                        <RemoteDir>Assets</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win64">
+                        <RemoteDir>Assets</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="UWP_DelphiLogo44">
+                    <Platform Name="Win32">
+                        <RemoteDir>Assets</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win64">
+                        <RemoteDir>Assets</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <ProjectRoot Platform="iOSDevice64" Name="$(PROJECTNAME).app"/>
+                <ProjectRoot Platform="Win64" Name="$(PROJECTNAME)"/>
+                <ProjectRoot Platform="iOSDevice32" Name="$(PROJECTNAME).app"/>
+                <ProjectRoot Platform="Linux64" Name="$(PROJECTNAME)"/>
+                <ProjectRoot Platform="Win32" Name="$(PROJECTNAME)"/>
+                <ProjectRoot Platform="OSX32" Name="$(PROJECTNAME).app"/>
+                <ProjectRoot Platform="Android" Name="$(PROJECTNAME)"/>
+                <ProjectRoot Platform="OSX64" Name="$(PROJECTNAME).app"/>
+                <ProjectRoot Platform="iOSSimulator" Name="$(PROJECTNAME).app"/>
+                <ProjectRoot Platform="Android64" Name="$(PROJECTNAME)"/>
+            </Deployment>
+            <Platforms>
+                <Platform value="Android">False</Platform>
+                <Platform value="Android64">False</Platform>
+                <Platform value="iOSDevice64">False</Platform>
+                <Platform value="iOSSimulator">False</Platform>
+                <Platform value="OSX64">False</Platform>
+                <Platform value="Win32">True</Platform>
+                <Platform value="Win64">False</Platform>
+            </Platforms>
+        </BorlandProject>
+        <ProjectFileVersion>12</ProjectFileVersion>
+    </ProjectExtensions>
+    <Import Project="$(BDS)\Bin\CodeGear.Delphi.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')"/>
+    <Import Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj" Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')"/>
+    <Import Project="$(MSBuildProjectName).deployproj" Condition="Exists('$(MSBuildProjectName).deployproj')"/>
+</Project>

+ 61 - 0
samples/delphi/QuickConditions/ConditionChecks.deployproj

@@ -0,0 +1,61 @@
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+    <Import Condition="Exists('$(BDS)\bin\CodeGear.Deployment.targets')" Project="$(BDS)\bin\CodeGear.Deployment.targets"/>
+    <ProjectExtensions>
+        <ProjectFileVersion>12</ProjectFileVersion>
+    </ProjectExtensions>
+    <PropertyGroup>
+        <DeviceId Condition="'$(Platform)'=='Android'"/>
+        <DeviceId Condition="'$(Platform)'=='Android64'"/>
+        <DeviceId Condition="'$(Platform)'=='iOSDevice64'"/>
+        <DeviceId Condition="'$(Platform)'=='iOSSimulator'"/>
+    </PropertyGroup>
+    <ItemGroup Condition="'$(Platform)'=='iOSDevice64'"/>
+    <ItemGroup Condition="'$(Platform)'=='Win64'"/>
+    <ItemGroup Condition="'$(Platform)'=='Win32'">
+        <DeployFile Include="Win32\Debug\ConditionChecks.exe" Condition="'$(Config)'=='Debug'">
+            <RemoteDir>ConditionChecks\</RemoteDir>
+            <RemoteName>ConditionChecks.exe</RemoteName>
+            <DeployClass>ProjectOutput</DeployClass>
+            <Operation>0</Operation>
+            <LocalCommand/>
+            <RemoteCommand/>
+            <Overwrite>True</Overwrite>
+            <Required>True</Required>
+        </DeployFile>
+    </ItemGroup>
+    <ItemGroup Condition="'$(Platform)'=='Linux64'">
+        <DeployFile Include="Linux64\Debug\ConditionChecks" Condition="'$(Config)'=='Debug'">
+            <RemoteDir>ConditionChecks\</RemoteDir>
+            <RemoteName>ConditionChecks</RemoteName>
+            <DeployClass>ProjectOutput</DeployClass>
+            <Operation>1</Operation>
+            <LocalCommand/>
+            <RemoteCommand/>
+            <Overwrite>True</Overwrite>
+            <Required>True</Required>
+        </DeployFile>
+    </ItemGroup>
+    <ItemGroup Condition="'$(Platform)'=='OSX64'"/>
+    <ItemGroup Condition="'$(Platform)'=='Android'"/>
+    <ItemGroup Condition="'$(Platform)'=='iOSSimulator'">
+        <DeployFile Include="$(BDS)\Redist\iossimulator\libcgunwind.1.0.dylib">
+            <RemoteDir>ConditionChecks.app\</RemoteDir>
+            <RemoteName>libcgunwind.1.0.dylib</RemoteName>
+            <DeployClass>DependencyModule</DeployClass>
+            <Operation>1</Operation>
+            <LocalCommand/>
+            <RemoteCommand/>
+            <Overwrite>True</Overwrite>
+        </DeployFile>
+        <DeployFile Include="$(BDS)\Redist\iossimulator\libpcre.dylib">
+            <RemoteDir>ConditionChecks.app\</RemoteDir>
+            <RemoteName>libpcre.dylib</RemoteName>
+            <DeployClass>DependencyModule</DeployClass>
+            <Operation>1</Operation>
+            <LocalCommand/>
+            <RemoteCommand/>
+            <Overwrite>True</Overwrite>
+        </DeployFile>
+    </ItemGroup>
+    <ItemGroup Condition="'$(Platform)'=='Android64'"/>
+</Project>

+ 80 - 0
samples/delphi/QuickConditions/ConditionChecks.dpr

@@ -0,0 +1,80 @@
+program ConditionChecks;
+
+{$APPTYPE CONSOLE}
+
+{$R *.res}
+
+uses
+  Classes,
+  System.SysUtils,
+  Quick.Console,
+  Quick.Conditions;
+
+type
+  EMyException = class(Exception);
+
+var
+  result : string;
+  num : Int64;
+  fnum : Double;
+  obj : TStream;
+
+begin
+  try
+    //text must start with h and end with o
+    result := 'Hello';
+    Condition.Requires(result,'result')
+      .IsNotEmpty
+      .StartsWith('h',True)
+      .EndsWith('o');
+
+    //text longer than 10 and contains check
+    result := 'Text to check';
+    Condition.Requires(result,'result')
+      .IsNotEmpty
+      .IsLongerThan(10)
+      .Contains('check',True);
+
+    //text must be shorter than 10
+    result := 'Text';
+    Condition.Requires(result,'result')
+      .IsNotEmpty
+      .IsShorterThan(10);
+
+    //text must be not lowercase
+    result := 'Text';
+    Condition.Requires(result,'result')
+      .IsNotEmpty
+      .IsNotLowerCase;
+
+    //num min 1 and max 10
+    num := 10;
+    Condition.Requires(num,'num')
+      .IsInRange(1,10,'value for num is out of range');
+
+    fnum := 7.3;
+    Condition.Requires(fnum,'fnum')
+      .IsGreaterThan(5)
+      .IsLessOrEqual(8)
+      .IsNotInRange(6,7);
+
+    obj := TStringStream.Create;
+    Condition.Requires(obj,'obj')
+      .WithExceptionOnFailure(EMyException)
+      .IsNotNull
+      .IsOfType(TStream)
+      .Evaluate(obj.Size = 0);
+    obj.Free;
+
+    Condition.Ensures(obj,'obj')
+      .IsNotNull;
+
+
+    cout('All conditions passed!',ccGreen);
+
+    ConsoleWaitForEnterKey;
+  except
+    on E: Exception do
+      Writeln(E.ClassName, ': ', E.Message);
+  end;
+end.

+ 1017 - 0
samples/delphi/QuickConditions/ConditionChecks.dproj

@@ -0,0 +1,1017 @@
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+    <PropertyGroup>
+        <ProjectGuid>{BD39DE8C-524A-43C2-B674-81382F8ADCC0}</ProjectGuid>
+        <ProjectVersion>19.2</ProjectVersion>
+        <FrameworkType>None</FrameworkType>
+        <Base>True</Base>
+        <Config Condition="'$(Config)'==''">Debug</Config>
+        <Platform Condition="'$(Platform)'==''">Win64</Platform>
+        <TargetedPlatforms>131</TargetedPlatforms>
+        <AppType>Console</AppType>
+        <MainSource>ConditionChecks.dpr</MainSource>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Android' and '$(Base)'=='true') or '$(Base_Android)'!=''">
+        <Base_Android>true</Base_Android>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Android64' and '$(Base)'=='true') or '$(Base_Android64)'!=''">
+        <Base_Android64>true</Base_Android64>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='iOSDevice64' and '$(Base)'=='true') or '$(Base_iOSDevice64)'!=''">
+        <Base_iOSDevice64>true</Base_iOSDevice64>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='iOSSimulator' and '$(Base)'=='true') or '$(Base_iOSSimulator)'!=''">
+        <Base_iOSSimulator>true</Base_iOSSimulator>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='OSX64' and '$(Base)'=='true') or '$(Base_OSX64)'!=''">
+        <Base_OSX64>true</Base_OSX64>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''">
+        <Base_Win32>true</Base_Win32>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Base)'=='true') or '$(Base_Win64)'!=''">
+        <Base_Win64>true</Base_Win64>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_1)'!=''">
+        <Cfg_1>true</Cfg_1>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_1)'=='true') or '$(Cfg_1_Win32)'!=''">
+        <Cfg_1_Win32>true</Cfg_1_Win32>
+        <CfgParent>Cfg_1</CfgParent>
+        <Cfg_1>true</Cfg_1>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_2)'!=''">
+        <Cfg_2>true</Cfg_2>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base)'!=''">
+        <DCC_DcuOutput>.\$(Platform)\$(Config)</DCC_DcuOutput>
+        <DCC_ExeOutput>.\$(Platform)\$(Config)</DCC_ExeOutput>
+        <DCC_E>false</DCC_E>
+        <DCC_N>false</DCC_N>
+        <DCC_S>false</DCC_S>
+        <DCC_F>false</DCC_F>
+        <DCC_K>false</DCC_K>
+        <DCC_Namespace>System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace)</DCC_Namespace>
+        <SanitizedProjectName>ConditionChecks</SanitizedProjectName>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Android)'!=''">
+        <DCC_UsePackage>DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;tethering;bindcompfmx;FmxTeeUI;fmx;FireDACIBDriver;FlatButtonSet;dbexpress;IndyCore;dsnap;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;inet;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;FMXTee;soaprtl;DbxCommonDriver;xmlrtl;soapmidas;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;dbrtl;IndyProtocols;$(DCC_UsePackage)</DCC_UsePackage>
+        <Android_LauncherIcon36>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_36x36.png</Android_LauncherIcon36>
+        <Android_LauncherIcon48>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_48x48.png</Android_LauncherIcon48>
+        <Android_LauncherIcon72>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_72x72.png</Android_LauncherIcon72>
+        <Android_LauncherIcon96>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_96x96.png</Android_LauncherIcon96>
+        <Android_LauncherIcon144>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_144x144.png</Android_LauncherIcon144>
+        <Android_LauncherIcon192>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_192x192.png</Android_LauncherIcon192>
+        <Android_SplashImage426>$(BDS)\bin\Artwork\Android\FM_SplashImage_426x320.png</Android_SplashImage426>
+        <Android_SplashImage470>$(BDS)\bin\Artwork\Android\FM_SplashImage_470x320.png</Android_SplashImage470>
+        <Android_SplashImage640>$(BDS)\bin\Artwork\Android\FM_SplashImage_640x480.png</Android_SplashImage640>
+        <Android_SplashImage960>$(BDS)\bin\Artwork\Android\FM_SplashImage_960x720.png</Android_SplashImage960>
+        <Android_NotificationIcon24>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_24x24.png</Android_NotificationIcon24>
+        <Android_NotificationIcon36>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_36x36.png</Android_NotificationIcon36>
+        <Android_NotificationIcon48>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_48x48.png</Android_NotificationIcon48>
+        <Android_NotificationIcon72>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_72x72.png</Android_NotificationIcon72>
+        <Android_NotificationIcon96>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_96x96.png</Android_NotificationIcon96>
+        <EnabledSysJars>android-support-v4.dex.jar;cloud-messaging.dex.jar;com-google-android-gms.play-services-ads-base.17.2.0.dex.jar;com-google-android-gms.play-services-ads-identifier.16.0.0.dex.jar;com-google-android-gms.play-services-ads-lite.17.2.0.dex.jar;com-google-android-gms.play-services-ads.17.2.0.dex.jar;com-google-android-gms.play-services-analytics-impl.16.0.8.dex.jar;com-google-android-gms.play-services-analytics.16.0.8.dex.jar;com-google-android-gms.play-services-base.16.0.1.dex.jar;com-google-android-gms.play-services-basement.16.2.0.dex.jar;com-google-android-gms.play-services-gass.17.2.0.dex.jar;com-google-android-gms.play-services-identity.16.0.0.dex.jar;com-google-android-gms.play-services-maps.16.1.0.dex.jar;com-google-android-gms.play-services-measurement-base.16.4.0.dex.jar;com-google-android-gms.play-services-measurement-sdk-api.16.4.0.dex.jar;com-google-android-gms.play-services-stats.16.0.1.dex.jar;com-google-android-gms.play-services-tagmanager-v4-impl.16.0.8.dex.jar;com-google-android-gms.play-services-tasks.16.0.1.dex.jar;com-google-android-gms.play-services-wallet.16.0.1.dex.jar;com-google-firebase.firebase-analytics.16.4.0.dex.jar;com-google-firebase.firebase-common.16.1.0.dex.jar;com-google-firebase.firebase-iid-interop.16.0.1.dex.jar;com-google-firebase.firebase-iid.17.1.1.dex.jar;com-google-firebase.firebase-measurement-connector.17.0.1.dex.jar;com-google-firebase.firebase-messaging.17.5.0.dex.jar;fmx.dex.jar;google-play-billing.dex.jar;google-play-licensing.dex.jar</EnabledSysJars>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Android64)'!=''">
+        <DCC_UsePackage>DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;tethering;bindcompfmx;FmxTeeUI;fmx;FireDACIBDriver;dbexpress;IndyCore;dsnap;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;inet;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;FMXTee;soaprtl;DbxCommonDriver;xmlrtl;soapmidas;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;dbrtl;IndyProtocols;$(DCC_UsePackage)</DCC_UsePackage>
+        <Android_LauncherIcon36>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_36x36.png</Android_LauncherIcon36>
+        <Android_LauncherIcon48>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_48x48.png</Android_LauncherIcon48>
+        <Android_LauncherIcon72>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_72x72.png</Android_LauncherIcon72>
+        <Android_LauncherIcon96>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_96x96.png</Android_LauncherIcon96>
+        <Android_LauncherIcon144>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_144x144.png</Android_LauncherIcon144>
+        <Android_LauncherIcon192>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_192x192.png</Android_LauncherIcon192>
+        <Android_SplashImage426>$(BDS)\bin\Artwork\Android\FM_SplashImage_426x320.png</Android_SplashImage426>
+        <Android_SplashImage470>$(BDS)\bin\Artwork\Android\FM_SplashImage_470x320.png</Android_SplashImage470>
+        <Android_SplashImage640>$(BDS)\bin\Artwork\Android\FM_SplashImage_640x480.png</Android_SplashImage640>
+        <Android_SplashImage960>$(BDS)\bin\Artwork\Android\FM_SplashImage_960x720.png</Android_SplashImage960>
+        <Android_NotificationIcon24>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_24x24.png</Android_NotificationIcon24>
+        <Android_NotificationIcon36>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_36x36.png</Android_NotificationIcon36>
+        <Android_NotificationIcon48>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_48x48.png</Android_NotificationIcon48>
+        <Android_NotificationIcon72>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_72x72.png</Android_NotificationIcon72>
+        <Android_NotificationIcon96>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_96x96.png</Android_NotificationIcon96>
+        <EnabledSysJars>android-support-v4.dex.jar;cloud-messaging.dex.jar;com-google-android-gms.play-services-ads-base.17.2.0.dex.jar;com-google-android-gms.play-services-ads-identifier.16.0.0.dex.jar;com-google-android-gms.play-services-ads-lite.17.2.0.dex.jar;com-google-android-gms.play-services-ads.17.2.0.dex.jar;com-google-android-gms.play-services-analytics-impl.16.0.8.dex.jar;com-google-android-gms.play-services-analytics.16.0.8.dex.jar;com-google-android-gms.play-services-base.16.0.1.dex.jar;com-google-android-gms.play-services-basement.16.2.0.dex.jar;com-google-android-gms.play-services-gass.17.2.0.dex.jar;com-google-android-gms.play-services-identity.16.0.0.dex.jar;com-google-android-gms.play-services-maps.16.1.0.dex.jar;com-google-android-gms.play-services-measurement-base.16.4.0.dex.jar;com-google-android-gms.play-services-measurement-sdk-api.16.4.0.dex.jar;com-google-android-gms.play-services-stats.16.0.1.dex.jar;com-google-android-gms.play-services-tagmanager-v4-impl.16.0.8.dex.jar;com-google-android-gms.play-services-tasks.16.0.1.dex.jar;com-google-android-gms.play-services-wallet.16.0.1.dex.jar;com-google-firebase.firebase-analytics.16.4.0.dex.jar;com-google-firebase.firebase-common.16.1.0.dex.jar;com-google-firebase.firebase-iid-interop.16.0.1.dex.jar;com-google-firebase.firebase-iid.17.1.1.dex.jar;com-google-firebase.firebase-measurement-connector.17.0.1.dex.jar;com-google-firebase.firebase-messaging.17.5.0.dex.jar;fmx.dex.jar;google-play-billing.dex.jar;google-play-licensing.dex.jar</EnabledSysJars>
+        <VerInfo_Keys>package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=</VerInfo_Keys>
+        <BT_BuildType>Debug</BT_BuildType>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_iOSDevice64)'!=''">
+        <DCC_UsePackage>DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;tethering;bindcompfmx;TMSFMXPackPkgDXE13;FmxTeeUI;fmx;FireDACIBDriver;dbexpress;IndyCore;dsnap;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;inet;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;FMXTee;soaprtl;DbxCommonDriver;xmlrtl;soapmidas;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;dbrtl;IndyProtocols;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_iOSSimulator)'!=''">
+        <DCC_UsePackage>DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;tethering;bindcompfmx;FmxTeeUI;fmx;FireDACIBDriver;dbexpress;IndyCore;dsnap;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;inet;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;FMXTee;soaprtl;DbxCommonDriver;xmlrtl;soapmidas;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;dbrtl;IndyProtocols;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_OSX64)'!=''">
+        <DCC_UsePackage>DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;tethering;bindcompfmx;inetdb;FmxTeeUI;fmx;FireDACIBDriver;fmxdae;dbexpress;IndyCore;dsnap;FireDACCommon;RESTBackendComponents;soapserver;bindengine;DBXMySQLDriver;CloudService;FireDACMySQLDriver;FireDACCommonODBC;FireDACCommonDriver;inet;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;FireDACPgDriver;FMXTee;soaprtl;DbxCommonDriver;xmlrtl;soapmidas;fmxobj;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;dbrtl;IndyProtocols;inetdbxpress;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
+        <DCC_ConsoleTarget>true</DCC_ConsoleTarget>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Win32)'!=''">
+        <DCC_UsePackage>DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;vclactnband;vclFireDAC;FMXComponents;bindcompvclsmp;tethering;svnui;JvGlobus;FireDACADSDriver;JvPluginSystem;JvMM;QuickFMX;PngComponentsD;vcltouch;JvBands;vcldb;bindcompfmx;svn;JvJans;JvNet;inetdb;JvAppFrm;TMSFMXPackPkgDXE13;FmxTeeUI;JvDotNetCtrls;TMSVCLUIPackPkgWizDXE13;fmx;FireDACIBDriver;fmxdae;vcledge;JvWizards;FlatButtonSet;dbexpress;IndyCore;TMSVCLUIPackPkgXlsDXE13;vclx;JvPageComps;dsnap;FireDACCommon;JvDB;RESTBackendComponents;VCLRESTComponents;soapserver;JclDeveloperTools;TMSVCLUIPackPkgDXE13;vclie;TMSVCLIWPkgDEDXE13;bindengine;DBXMySQLDriver;CloudService;JvCmp;FireDACMySQLDriver;JvHMI;FireDACCommonODBC;FireDACCommonDriver;FMXComponentEd;inet;TMSVCLUIPackPkgExDXE13;IndyIPCommon;bindcompdbx;JvCustom;vcl;IndyIPServer;JvXPCtrls;IndySystem;bindcompvclwinx;dsnapcon;TMSVCLIWPkgDXE13;FireDACMSAccDriver;fmxFireDAC;vclimg;TeeDB;FireDAC;Jcl;JvCore;JvCrypt;FireDACSqliteDriver;FireDACPgDriver;FMXTee;soaprtl;DbxCommonDriver;JvDlgs;JvRuntimeDesign;JvManagedThreads;Tee;xmlrtl;soapmidas;JvTimeFramework;fmxobj;vclwinx;rtl;DbxClientDriver;CustomIPTransport;vcldsnap;JvSystem;JvStdCtrls;bindcomp;appanalytics;IndyIPClient;bindcompvcl;TeeUI;JvDocking;dbxcds;VclSmp;JvPascalInterpreter;adortl;KernowSoftwareFMX;JclVcl;dsnapxml;dbrtl;IndyProtocols;inetdbxpress;JvControls;JvPrintPreview;JclContainers;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
+        <DCC_Namespace>Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
+        <BT_BuildType>Debug</BT_BuildType>
+        <VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
+        <VerInfo_Locale>1033</VerInfo_Locale>
+        <DCC_ConsoleTarget>true</DCC_ConsoleTarget>
+        <UWP_DelphiLogo44>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png</UWP_DelphiLogo44>
+        <UWP_DelphiLogo150>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png</UWP_DelphiLogo150>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Win64)'!=''">
+        <DCC_UsePackage>DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;vclactnband;vclFireDAC;bindcompvclsmp;tethering;FireDACADSDriver;QuickFMX;PngComponentsD;vcltouch;vcldb;bindcompfmx;inetdb;FmxTeeUI;fmx;FireDACIBDriver;fmxdae;vcledge;FlatButtonSet;dbexpress;IndyCore;vclx;dsnap;FireDACCommon;RESTBackendComponents;VCLRESTComponents;soapserver;TMSVCLUIPackPkgDXE13;vclie;bindengine;DBXMySQLDriver;CloudService;FireDACMySQLDriver;FireDACCommonODBC;FireDACCommonDriver;inet;TMSVCLUIPackPkgExDXE13;IndyIPCommon;bindcompdbx;vcl;IndyIPServer;IndySystem;bindcompvclwinx;dsnapcon;TMSVCLIWPkgDXE13;FireDACMSAccDriver;fmxFireDAC;vclimg;TeeDB;FireDAC;FireDACSqliteDriver;FireDACPgDriver;FMXTee;soaprtl;DbxCommonDriver;Tee;xmlrtl;soapmidas;fmxobj;vclwinx;rtl;DbxClientDriver;CustomIPTransport;vcldsnap;bindcomp;appanalytics;IndyIPClient;bindcompvcl;TeeUI;dbxcds;VclSmp;adortl;dsnapxml;dbrtl;IndyProtocols;inetdbxpress;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
+        <DCC_ConsoleTarget>true</DCC_ConsoleTarget>
+        <UWP_DelphiLogo44>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png</UWP_DelphiLogo44>
+        <UWP_DelphiLogo150>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png</UWP_DelphiLogo150>
+        <DCC_Namespace>Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace)</DCC_Namespace>
+        <BT_BuildType>Debug</BT_BuildType>
+        <VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
+        <VerInfo_Locale>1033</VerInfo_Locale>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_1)'!=''">
+        <DCC_Define>DEBUG;$(DCC_Define)</DCC_Define>
+        <DCC_DebugDCUs>true</DCC_DebugDCUs>
+        <DCC_Optimize>false</DCC_Optimize>
+        <DCC_GenerateStackFrames>true</DCC_GenerateStackFrames>
+        <DCC_DebugInfoInExe>true</DCC_DebugInfoInExe>
+        <DCC_RemoteDebug>true</DCC_RemoteDebug>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_1_Win32)'!=''">
+        <DCC_RemoteDebug>false</DCC_RemoteDebug>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2)'!=''">
+        <DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
+        <DCC_Define>RELEASE;$(DCC_Define)</DCC_Define>
+        <DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo>
+        <DCC_DebugInformation>0</DCC_DebugInformation>
+    </PropertyGroup>
+    <ItemGroup>
+        <DelphiCompile Include="$(MainSource)">
+            <MainSource>MainSource</MainSource>
+        </DelphiCompile>
+        <BuildConfiguration Include="Release">
+            <Key>Cfg_2</Key>
+            <CfgParent>Base</CfgParent>
+        </BuildConfiguration>
+        <BuildConfiguration Include="Base">
+            <Key>Base</Key>
+        </BuildConfiguration>
+        <BuildConfiguration Include="Debug">
+            <Key>Cfg_1</Key>
+            <CfgParent>Base</CfgParent>
+        </BuildConfiguration>
+    </ItemGroup>
+    <ProjectExtensions>
+        <Borland.Personality>Delphi.Personality.12</Borland.Personality>
+        <Borland.ProjectType>Application</Borland.ProjectType>
+        <BorlandProject>
+            <Delphi.Personality>
+                <Source>
+                    <Source Name="MainSource">ConditionChecks.dpr</Source>
+                </Source>
+            </Delphi.Personality>
+            <Deployment Version="3">
+                <DeployFile LocalName="Linux64\Debug\ConditionChecks" Configuration="Debug" Class="ProjectOutput">
+                    <Platform Name="Linux64">
+                        <RemoteName>ConditionChecks</RemoteName>
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile LocalName="$(BDS)\Redist\osx32\libcgunwind.1.0.dylib" Class="DependencyModule">
+                    <Platform Name="OSX32">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile LocalName="Win64\Debug\ConditionChecks.exe" Configuration="Debug" Class="ProjectOutput">
+                    <Platform Name="Win64">
+                        <RemoteName>ConditionChecks.exe</RemoteName>
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile LocalName="Win64\Debug\ConditionChecks.rsm" Configuration="Debug" Class="DebugSymbols">
+                    <Platform Name="Win64">
+                        <RemoteName>ConditionChecks.rsm</RemoteName>
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile LocalName="Win32\Debug\ConditionChecks.exe" Configuration="Debug" Class="ProjectOutput">
+                    <Platform Name="Win32">
+                        <RemoteName>ConditionChecks.exe</RemoteName>
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile LocalName="$(BDS)\Redist\iossimulator\libcgunwind.1.0.dylib" Class="DependencyModule">
+                    <Platform Name="iOSSimulator">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile LocalName="$(BDS)\Redist\iossimulator\libpcre.dylib" Class="DependencyModule">
+                    <Platform Name="iOSSimulator">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployClass Name="AdditionalDebugSymbols">
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidClassesDexFile">
+                    <Platform Name="Android">
+                        <RemoteDir>classes</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>classes</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidFileProvider">
+                    <Platform Name="Android">
+                        <RemoteDir>res\xml</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\xml</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidGDBServer">
+                    <Platform Name="Android">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidLibnativeArmeabiFile">
+                    <Platform Name="Android">
+                        <RemoteDir>library\lib\armeabi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\armeabi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidLibnativeArmeabiv7aFile">
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidLibnativeMipsFile">
+                    <Platform Name="Android">
+                        <RemoteDir>library\lib\mips</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\mips</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidServiceOutput">
+                    <Platform Name="Android">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\arm64-v8a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidServiceOutput_Android32">
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidSplashImageDef">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidSplashStyles">
+                    <Platform Name="Android">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidSplashStylesV21">
+                    <Platform Name="Android">
+                        <RemoteDir>res\values-v21</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\values-v21</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_Colors">
+                    <Platform Name="Android">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_DefaultAppIcon">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon144">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon192">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xxxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xxxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon36">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-ldpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-ldpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon48">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-mdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-mdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon72">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-hdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-hdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon96">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_NotificationIcon24">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-mdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-mdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_NotificationIcon36">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-hdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-hdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_NotificationIcon48">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_NotificationIcon72">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_NotificationIcon96">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xxxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xxxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_SplashImage426">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-small</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-small</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_SplashImage470">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-normal</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-normal</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_SplashImage640">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-large</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-large</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_SplashImage960">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xlarge</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xlarge</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_Strings">
+                    <Platform Name="Android">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="DebugSymbols">
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="DependencyFramework">
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.framework</Extensions>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.framework</Extensions>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="DependencyModule">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                        <Extensions>.dll;.bpl</Extensions>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Required="true" Name="DependencyPackage">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                        <Extensions>.bpl</Extensions>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="File">
+                    <Platform Name="Android">
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice32">
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\Resources\StartUp\</RemoteDir>
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\Resources\StartUp\</RemoteDir>
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iOS_AppStore1024">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_AppIcon152">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_AppIcon167">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_Launch2x">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_LaunchDark2x">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_Notification40">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_Setting58">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_SpotLight80">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_AppIcon120">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_AppIcon180">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch2x">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch3x">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_LaunchDark2x">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_LaunchDark3x">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Notification40">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Notification60">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Setting58">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Setting87">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Spotlight120">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Spotlight80">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectAndroidManifest">
+                    <Platform Name="Android">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectiOSDeviceDebug">
+                    <Platform Name="iOSDevice32">
+                        <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectiOSEntitlements">
+                    <Platform Name="iOSDevice32">
+                        <RemoteDir>..\</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectiOSInfoPList">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectiOSLaunchScreen">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen</RemoteDir>
+                        <Operation>64</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen</RemoteDir>
+                        <Operation>64</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectiOSResource">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectOSXDebug">
+                    <Platform Name="OSX64">
+                        <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectOSXEntitlements">
+                    <Platform Name="OSX32">
+                        <RemoteDir>..\</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>..\</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectOSXInfoPList">
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectOSXResource">
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\Resources</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\Resources</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Required="true" Name="ProjectOutput">
+                    <Platform Name="Android">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\arm64-v8a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Linux64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectOutput_Android32">
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectUWPManifest">
+                    <Platform Name="Win32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win64">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="UWP_DelphiLogo150">
+                    <Platform Name="Win32">
+                        <RemoteDir>Assets</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win64">
+                        <RemoteDir>Assets</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="UWP_DelphiLogo44">
+                    <Platform Name="Win32">
+                        <RemoteDir>Assets</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win64">
+                        <RemoteDir>Assets</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <ProjectRoot Platform="iOSDevice64" Name="$(PROJECTNAME).app"/>
+                <ProjectRoot Platform="Win64" Name="$(PROJECTNAME)"/>
+                <ProjectRoot Platform="iOSDevice32" Name="$(PROJECTNAME).app"/>
+                <ProjectRoot Platform="Linux64" Name="$(PROJECTNAME)"/>
+                <ProjectRoot Platform="Win32" Name="$(PROJECTNAME)"/>
+                <ProjectRoot Platform="OSX32" Name="$(PROJECTNAME).app"/>
+                <ProjectRoot Platform="Android" Name="$(PROJECTNAME)"/>
+                <ProjectRoot Platform="OSX64" Name="$(PROJECTNAME).app"/>
+                <ProjectRoot Platform="iOSSimulator" Name="$(PROJECTNAME).app"/>
+                <ProjectRoot Platform="Android64" Name="$(PROJECTNAME)"/>
+            </Deployment>
+            <Platforms>
+                <Platform value="Android">False</Platform>
+                <Platform value="Android64">False</Platform>
+                <Platform value="iOSDevice64">False</Platform>
+                <Platform value="iOSSimulator">False</Platform>
+                <Platform value="Linux64">True</Platform>
+                <Platform value="OSX64">False</Platform>
+                <Platform value="Win32">True</Platform>
+                <Platform value="Win64">True</Platform>
+            </Platforms>
+        </BorlandProject>
+        <ProjectFileVersion>12</ProjectFileVersion>
+    </ProjectExtensions>
+    <Import Project="$(BDS)\Bin\CodeGear.Delphi.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')"/>
+    <Import Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj" Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')"/>
+    <Import Project="$(MSBuildProjectName).deployproj" Condition="Exists('$(MSBuildProjectName).deployproj')"/>
+</Project>

+ 76 - 101
samples/delphi/QuickConfig/ConfigToJSON/ConfigToJSON.dproj

@@ -1,7 +1,7 @@
 <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
     <PropertyGroup>
         <ProjectGuid>{CDEBAD41-A241-457F-96FD-E367D8E3B0AE}</ProjectGuid>
-        <ProjectVersion>18.8</ProjectVersion>
+        <ProjectVersion>19.1</ProjectVersion>
         <FrameworkType>VCL</FrameworkType>
         <MainSource>ConfigToJSON.dpr</MainSource>
         <Base>True</Base>
@@ -576,51 +576,33 @@
                         <Operation>0</Operation>
                     </Platform>
                 </DeployClass>
-                <DeployClass Name="iPad_Launch1024">
-                    <Platform Name="iOSDevice32">
-                        <Operation>1</Operation>
-                    </Platform>
+                <DeployClass Name="iOS_AppStore1024">
                     <Platform Name="iOSDevice64">
-                        <Operation>1</Operation>
-                    </Platform>
-                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
                 </DeployClass>
-                <DeployClass Name="iPad_Launch1024x768">
-                    <Platform Name="iOSDevice32">
-                        <Operation>1</Operation>
-                    </Platform>
+                <DeployClass Name="iPad_AppIcon152">
                     <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
                     <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
                 </DeployClass>
-                <DeployClass Name="iPad_Launch1536">
-                    <Platform Name="iOSDevice32">
-                        <Operation>1</Operation>
-                    </Platform>
+                <DeployClass Name="iPad_AppIcon167">
                     <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
                     <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
                 </DeployClass>
-                <DeployClass Name="iPad_Launch1536x2048">
-                    <Platform Name="iOSDevice32">
-                        <Operation>1</Operation>
-                    </Platform>
-                    <Platform Name="iOSDevice64">
-                        <Operation>1</Operation>
-                    </Platform>
-                    <Platform Name="iOSSimulator">
-                        <Operation>1</Operation>
-                    </Platform>
-                </DeployClass>
-                <DeployClass Name="iPad_Launch1668">
+                <DeployClass Name="iPad_Launch1024">
                     <Platform Name="iOSDevice32">
                         <Operation>1</Operation>
                     </Platform>
@@ -631,7 +613,7 @@
                         <Operation>1</Operation>
                     </Platform>
                 </DeployClass>
-                <DeployClass Name="iPad_Launch1668x2388">
+                <DeployClass Name="iPad_Launch1536">
                     <Platform Name="iOSDevice32">
                         <Operation>1</Operation>
                     </Platform>
@@ -653,18 +635,17 @@
                         <Operation>1</Operation>
                     </Platform>
                 </DeployClass>
-                <DeployClass Name="iPad_Launch2048x1536">
-                    <Platform Name="iOSDevice32">
-                        <Operation>1</Operation>
-                    </Platform>
+                <DeployClass Name="iPad_Launch2x">
                     <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
                     <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
                 </DeployClass>
-                <DeployClass Name="iPad_Launch2048x2732">
+                <DeployClass Name="iPad_Launch768">
                     <Platform Name="iOSDevice32">
                         <Operation>1</Operation>
                     </Platform>
@@ -675,84 +656,77 @@
                         <Operation>1</Operation>
                     </Platform>
                 </DeployClass>
-                <DeployClass Name="iPad_Launch2224">
-                    <Platform Name="iOSDevice32">
-                        <Operation>1</Operation>
-                    </Platform>
+                <DeployClass Name="iPad_LaunchDark2x">
                     <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
                     <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
                 </DeployClass>
-                <DeployClass Name="iPad_Launch2388x1668">
-                    <Platform Name="iOSDevice32">
-                        <Operation>1</Operation>
-                    </Platform>
+                <DeployClass Name="iPad_Notification40">
                     <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
                     <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
                 </DeployClass>
-                <DeployClass Name="iPad_Launch2732x2048">
-                    <Platform Name="iOSDevice32">
-                        <Operation>1</Operation>
-                    </Platform>
+                <DeployClass Name="iPad_Setting58">
                     <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
                     <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
                 </DeployClass>
-                <DeployClass Name="iPad_Launch768">
-                    <Platform Name="iOSDevice32">
-                        <Operation>1</Operation>
-                    </Platform>
+                <DeployClass Name="iPad_SpotLight80">
                     <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
                     <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
                 </DeployClass>
-                <DeployClass Name="iPad_Launch768x1024">
-                    <Platform Name="iOSDevice32">
-                        <Operation>1</Operation>
-                    </Platform>
+                <DeployClass Name="iPhone_AppIcon120">
                     <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
                     <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
                 </DeployClass>
-                <DeployClass Name="iPhone_Launch1125">
-                    <Platform Name="iOSDevice32">
-                        <Operation>1</Operation>
-                    </Platform>
+                <DeployClass Name="iPhone_AppIcon180">
                     <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
                     <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
                 </DeployClass>
-                <DeployClass Name="iPhone_Launch1136x640">
-                    <Platform Name="iOSDevice32">
-                        <Operation>1</Operation>
-                    </Platform>
+                <DeployClass Name="iPhone_Launch2x">
                     <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
                     <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
                 </DeployClass>
-                <DeployClass Name="iPhone_Launch1242">
+                <DeployClass Name="iPhone_Launch320">
                     <Platform Name="iOSDevice32">
                         <Operation>1</Operation>
                     </Platform>
@@ -763,18 +737,17 @@
                         <Operation>1</Operation>
                     </Platform>
                 </DeployClass>
-                <DeployClass Name="iPhone_Launch1242x2688">
-                    <Platform Name="iOSDevice32">
-                        <Operation>1</Operation>
-                    </Platform>
+                <DeployClass Name="iPhone_Launch3x">
                     <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
                     <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
                 </DeployClass>
-                <DeployClass Name="iPhone_Launch1334">
+                <DeployClass Name="iPhone_Launch640">
                     <Platform Name="iOSDevice32">
                         <Operation>1</Operation>
                     </Platform>
@@ -785,7 +758,7 @@
                         <Operation>1</Operation>
                     </Platform>
                 </DeployClass>
-                <DeployClass Name="iPhone_Launch1792">
+                <DeployClass Name="iPhone_Launch640x1136">
                     <Platform Name="iOSDevice32">
                         <Operation>1</Operation>
                     </Platform>
@@ -796,91 +769,83 @@
                         <Operation>1</Operation>
                     </Platform>
                 </DeployClass>
-                <DeployClass Name="iPhone_Launch2208">
-                    <Platform Name="iOSDevice32">
-                        <Operation>1</Operation>
-                    </Platform>
+                <DeployClass Name="iPhone_LaunchDark2x">
                     <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
                     <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
                 </DeployClass>
-                <DeployClass Name="iPhone_Launch2436">
-                    <Platform Name="iOSDevice32">
-                        <Operation>1</Operation>
-                    </Platform>
+                <DeployClass Name="iPhone_LaunchDark3x">
                     <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
                     <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
                 </DeployClass>
-                <DeployClass Name="iPhone_Launch2688x1242">
-                    <Platform Name="iOSDevice32">
-                        <Operation>1</Operation>
-                    </Platform>
+                <DeployClass Name="iPhone_Notification40">
                     <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
                     <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
                 </DeployClass>
-                <DeployClass Name="iPhone_Launch320">
-                    <Platform Name="iOSDevice32">
-                        <Operation>1</Operation>
-                    </Platform>
+                <DeployClass Name="iPhone_Notification60">
                     <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
                     <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
                 </DeployClass>
-                <DeployClass Name="iPhone_Launch640">
-                    <Platform Name="iOSDevice32">
-                        <Operation>1</Operation>
-                    </Platform>
+                <DeployClass Name="iPhone_Setting58">
                     <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
                     <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
                 </DeployClass>
-                <DeployClass Name="iPhone_Launch640x1136">
-                    <Platform Name="iOSDevice32">
-                        <Operation>1</Operation>
-                    </Platform>
+                <DeployClass Name="iPhone_Setting87">
                     <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
                     <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
                 </DeployClass>
-                <DeployClass Name="iPhone_Launch750">
-                    <Platform Name="iOSDevice32">
-                        <Operation>1</Operation>
-                    </Platform>
+                <DeployClass Name="iPhone_Spotlight120">
                     <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
                     <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
                 </DeployClass>
-                <DeployClass Name="iPhone_Launch828">
-                    <Platform Name="iOSDevice32">
-                        <Operation>1</Operation>
-                    </Platform>
+                <DeployClass Name="iPhone_Spotlight80">
                     <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
                     <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
                 </DeployClass>
@@ -931,6 +896,16 @@
                         <Operation>1</Operation>
                     </Platform>
                 </DeployClass>
+                <DeployClass Name="ProjectiOSLaunchScreen">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen</RemoteDir>
+                        <Operation>64</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen</RemoteDir>
+                        <Operation>64</Operation>
+                    </Platform>
+                </DeployClass>
                 <DeployClass Name="ProjectiOSResource">
                     <Platform Name="iOSDevice32">
                         <Operation>1</Operation>

BIN
samples/delphi/QuickConfig/ConfigToJSON/ConfigToJSON.res


+ 1 - 0
samples/delphi/QuickConfig/ConfigToJSON/Main.pas

@@ -178,6 +178,7 @@ end;
 
 procedure TMainForm.FormCreate(Sender: TObject);
 begin
+  ReportMemoryLeaksOnShutdown := True;
   ConfigJson := TMyConfig.Create('.\config.json');
   ConfigJson.Provider.OnFileModified := OnFileModified;
   ConfigJson.Provider.ReloadIfFileChanged := True;

+ 388 - 1
samples/delphi/QuickConfig/ConfigToYAML/ConfigToYAML.dproj

@@ -1,7 +1,7 @@
 <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
     <PropertyGroup>
         <ProjectGuid>{CDEBAD41-A241-457F-96FD-E367D8E3B0AE}</ProjectGuid>
-        <ProjectVersion>18.6</ProjectVersion>
+        <ProjectVersion>19.2</ProjectVersion>
         <FrameworkType>VCL</FrameworkType>
         <MainSource>ConfigToYAML.dpr</MainSource>
         <Base>True</Base>
@@ -202,12 +202,20 @@
                         <RemoteDir>classes</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>classes</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="AndroidFileProvider">
                     <Platform Name="Android">
                         <RemoteDir>res\xml</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\xml</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="AndroidGDBServer">
                     <Platform Name="Android">
@@ -220,96 +228,252 @@
                         <RemoteDir>library\lib\armeabi</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\armeabi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidLibnativeArmeabiv7aFile">
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="AndroidLibnativeMipsFile">
                     <Platform Name="Android">
                         <RemoteDir>library\lib\mips</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\mips</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="AndroidServiceOutput">
                     <Platform Name="Android">
                         <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\arm64-v8a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidServiceOutput_Android32">
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="AndroidSplashImageDef">
                     <Platform Name="Android">
                         <RemoteDir>res\drawable</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="AndroidSplashStyles">
                     <Platform Name="Android">
                         <RemoteDir>res\values</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="AndroidSplashStylesV21">
                     <Platform Name="Android">
                         <RemoteDir>res\values-v21</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\values-v21</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_Colors">
+                    <Platform Name="Android">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="Android_DefaultAppIcon">
                     <Platform Name="Android">
                         <RemoteDir>res\drawable</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="Android_LauncherIcon144">
                     <Platform Name="Android">
                         <RemoteDir>res\drawable-xxhdpi</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon192">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xxxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xxxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="Android_LauncherIcon36">
                     <Platform Name="Android">
                         <RemoteDir>res\drawable-ldpi</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-ldpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="Android_LauncherIcon48">
                     <Platform Name="Android">
                         <RemoteDir>res\drawable-mdpi</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-mdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="Android_LauncherIcon72">
                     <Platform Name="Android">
                         <RemoteDir>res\drawable-hdpi</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-hdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="Android_LauncherIcon96">
                     <Platform Name="Android">
                         <RemoteDir>res\drawable-xhdpi</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_NotificationIcon24">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-mdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-mdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_NotificationIcon36">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-hdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-hdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_NotificationIcon48">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_NotificationIcon72">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_NotificationIcon96">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xxxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xxxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="Android_SplashImage426">
                     <Platform Name="Android">
                         <RemoteDir>res\drawable-small</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-small</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="Android_SplashImage470">
                     <Platform Name="Android">
                         <RemoteDir>res\drawable-normal</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-normal</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="Android_SplashImage640">
                     <Platform Name="Android">
                         <RemoteDir>res\drawable-large</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-large</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="Android_SplashImage960">
                     <Platform Name="Android">
                         <RemoteDir>res\drawable-xlarge</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xlarge</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_Strings">
+                    <Platform Name="Android">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="DebugSymbols">
                     <Platform Name="iOSSimulator">
@@ -398,6 +562,9 @@
                     <Platform Name="Android">
                         <Operation>0</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <Operation>0</Operation>
+                    </Platform>
                     <Platform Name="iOSDevice32">
                         <Operation>0</Operation>
                     </Platform>
@@ -419,6 +586,32 @@
                         <Operation>0</Operation>
                     </Platform>
                 </DeployClass>
+                <DeployClass Name="iOS_AppStore1024">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_AppIcon152">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_AppIcon167">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
                 <DeployClass Name="iPad_Launch1024">
                     <Platform Name="iOSDevice32">
                         <Operation>1</Operation>
@@ -452,6 +645,16 @@
                         <Operation>1</Operation>
                     </Platform>
                 </DeployClass>
+                <DeployClass Name="iPad_Launch2x">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
                 <DeployClass Name="iPad_Launch768">
                     <Platform Name="iOSDevice32">
                         <Operation>1</Operation>
@@ -463,6 +666,76 @@
                         <Operation>1</Operation>
                     </Platform>
                 </DeployClass>
+                <DeployClass Name="iPad_LaunchDark2x">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_Notification40">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_Setting58">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_SpotLight80">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_AppIcon120">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_AppIcon180">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch2x">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
                 <DeployClass Name="iPhone_Launch320">
                     <Platform Name="iOSDevice32">
                         <Operation>1</Operation>
@@ -474,6 +747,16 @@
                         <Operation>1</Operation>
                     </Platform>
                 </DeployClass>
+                <DeployClass Name="iPhone_Launch3x">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
                 <DeployClass Name="iPhone_Launch640">
                     <Platform Name="iOSDevice32">
                         <Operation>1</Operation>
@@ -496,10 +779,93 @@
                         <Operation>1</Operation>
                     </Platform>
                 </DeployClass>
+                <DeployClass Name="iPhone_LaunchDark2x">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_LaunchDark3x">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Notification40">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Notification60">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Setting58">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Setting87">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Spotlight120">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Spotlight80">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
                 <DeployClass Name="ProjectAndroidManifest">
                     <Platform Name="Android">
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="ProjectiOSDeviceDebug">
                     <Platform Name="iOSDevice32">
@@ -540,6 +906,16 @@
                         <Operation>1</Operation>
                     </Platform>
                 </DeployClass>
+                <DeployClass Name="ProjectiOSLaunchScreen">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen</RemoteDir>
+                        <Operation>64</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen</RemoteDir>
+                        <Operation>64</Operation>
+                    </Platform>
+                </DeployClass>
                 <DeployClass Name="ProjectiOSResource">
                     <Platform Name="iOSDevice32">
                         <Operation>1</Operation>
@@ -592,6 +968,10 @@
                         <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\arm64-v8a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                     <Platform Name="iOSDevice32">
                         <Operation>1</Operation>
                     </Platform>
@@ -616,6 +996,12 @@
                         <Operation>0</Operation>
                     </Platform>
                 </DeployClass>
+                <DeployClass Name="ProjectOutput_Android32">
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
                 <DeployClass Name="ProjectUWPManifest">
                     <Platform Name="Win32">
                         <Operation>1</Operation>
@@ -653,6 +1039,7 @@
                 <ProjectRoot Platform="Android" Name="$(PROJECTNAME)"/>
                 <ProjectRoot Platform="OSX64" Name="$(PROJECTNAME).app"/>
                 <ProjectRoot Platform="iOSSimulator" Name="$(PROJECTNAME).app"/>
+                <ProjectRoot Platform="Android64" Name="$(PROJECTNAME)"/>
             </Deployment>
             <Platforms>
                 <Platform value="Win32">True</Platform>

BIN
samples/delphi/QuickConfig/ConfigToYAML/ConfigToYAML.res


+ 1 - 0
samples/delphi/QuickConfig/ConfigToYAML/Main.pas

@@ -198,6 +198,7 @@ begin
     Assert(cConfig1.Complex.Priority = cConfig2.Complex.Priority);
     Assert(cConfig1.Complex.Redundant  = cConfig2.Complex.Redundant);
     Assert(cConfig1.Title = cConfig2.Title);
+    Assert(cConfig1.WorkList.Count = cConfig2.WorkList.Count);
     for i := 0 to cConfig1.WorkList.Count - 1 do
     begin
       Assert(cConfig1.WorkList[i].Name = cConfig2.WorkList[i].Name);

+ 56 - 0
samples/delphi/QuickExpressions/ExpressionsTest.dpr

@@ -0,0 +1,56 @@
+program ExpressionsTest;
+
+{$APPTYPE CONSOLE}
+
+{$R *.res}
+
+uses
+  System.SysUtils,
+  Quick.Commons,
+  Quick.Console,
+  Quick.Expression;
+
+var
+  listexpressions : TArray<string>;
+begin
+  try
+    //true expressions
+    listexpressions.Add('1 = 1');
+    listexpressions.Add('1 < 2');
+    listexpressions.Add('2 > 1');
+    listexpressions.Add('(1 = 1) AND (2 = 2)');
+    listexpressions.Add('(1 = 1) OR (2 = 3)');
+    listexpressions.Add('(1 = 2) OR (2 = 2)');
+    listexpressions.Add('(0.3 < 8) or ((5 < 4) and (2 = 1))');
+    listexpressions.Add('(8 > 3) or ((5 > 4) and (2 = 1))');
+
+    cout('True expressions',ccWhite);
+    for var expression in listexpressions do
+    begin
+      if TExpressionParser.Validate(expression) then cout(expression,ccGreen) else cout(expression,ccRed);
+    end;
+
+    listexpressions := [];
+
+    //false expressions
+    listexpressions.Add('1 = 2');
+    listexpressions.Add('2 < 1');
+    listexpressions.Add('1 > 2');
+    listexpressions.Add('(1 <> 1) AND (2 <> 2)');
+    listexpressions.Add('(1 <> 1) OR (2 = 3)');
+    listexpressions.Add('(1 = 2) OR (2 <> 2)');
+    listexpressions.Add('(0.3 > 8) or ((5 > 4) and (2 <> 2))');
+    listexpressions.Add('(8 < 3) or ((5 < 4) and (2 <> 1))');
+
+    cout('False expressions',ccWhite);
+    for var expression in listexpressions do
+    begin
+      if not TExpressionParser.Validate(expression) then cout(expression,ccGreen) else cout(expression,ccRed);
+    end;
+
+    ConsoleWaitForEnterKey;
+  except
+    on E: Exception do
+      Writeln(E.ClassName, ': ', E.Message);
+  end;
+end.

+ 980 - 0
samples/delphi/QuickExpressions/ExpressionsTest.dproj

@@ -0,0 +1,980 @@
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+    <PropertyGroup>
+        <ProjectGuid>{80FC0D6F-DE13-4D6C-A9C7-774B0E6BE3B1}</ProjectGuid>
+        <ProjectVersion>19.1</ProjectVersion>
+        <FrameworkType>None</FrameworkType>
+        <Base>True</Base>
+        <Config Condition="'$(Config)'==''">Debug</Config>
+        <Platform Condition="'$(Platform)'==''">Win32</Platform>
+        <TargetedPlatforms>1</TargetedPlatforms>
+        <AppType>Console</AppType>
+        <MainSource>ExpressionsTest.dpr</MainSource>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Android' and '$(Base)'=='true') or '$(Base_Android)'!=''">
+        <Base_Android>true</Base_Android>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Android64' and '$(Base)'=='true') or '$(Base_Android64)'!=''">
+        <Base_Android64>true</Base_Android64>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='iOSDevice64' and '$(Base)'=='true') or '$(Base_iOSDevice64)'!=''">
+        <Base_iOSDevice64>true</Base_iOSDevice64>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='iOSSimulator' and '$(Base)'=='true') or '$(Base_iOSSimulator)'!=''">
+        <Base_iOSSimulator>true</Base_iOSSimulator>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='OSX64' and '$(Base)'=='true') or '$(Base_OSX64)'!=''">
+        <Base_OSX64>true</Base_OSX64>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''">
+        <Base_Win32>true</Base_Win32>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Base)'=='true') or '$(Base_Win64)'!=''">
+        <Base_Win64>true</Base_Win64>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_1)'!=''">
+        <Cfg_1>true</Cfg_1>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_1)'=='true') or '$(Cfg_1_Win32)'!=''">
+        <Cfg_1_Win32>true</Cfg_1_Win32>
+        <CfgParent>Cfg_1</CfgParent>
+        <Cfg_1>true</Cfg_1>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_2)'!=''">
+        <Cfg_2>true</Cfg_2>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base)'!=''">
+        <DCC_DcuOutput>.\$(Platform)\$(Config)</DCC_DcuOutput>
+        <DCC_ExeOutput>.\$(Platform)\$(Config)</DCC_ExeOutput>
+        <DCC_E>false</DCC_E>
+        <DCC_N>false</DCC_N>
+        <DCC_S>false</DCC_S>
+        <DCC_F>false</DCC_F>
+        <DCC_K>false</DCC_K>
+        <DCC_Namespace>System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace)</DCC_Namespace>
+        <SanitizedProjectName>ExpressionsTest</SanitizedProjectName>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Android)'!=''">
+        <DCC_UsePackage>DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;tethering;bindcompfmx;FmxTeeUI;fmx;FireDACIBDriver;FlatButtonSet;dbexpress;IndyCore;dsnap;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;inet;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;FMXTee;soaprtl;DbxCommonDriver;xmlrtl;soapmidas;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;dbrtl;IndyProtocols;$(DCC_UsePackage)</DCC_UsePackage>
+        <Android_LauncherIcon36>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_36x36.png</Android_LauncherIcon36>
+        <Android_LauncherIcon48>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_48x48.png</Android_LauncherIcon48>
+        <Android_LauncherIcon72>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_72x72.png</Android_LauncherIcon72>
+        <Android_LauncherIcon96>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_96x96.png</Android_LauncherIcon96>
+        <Android_LauncherIcon144>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_144x144.png</Android_LauncherIcon144>
+        <Android_SplashImage426>$(BDS)\bin\Artwork\Android\FM_SplashImage_426x320.png</Android_SplashImage426>
+        <Android_SplashImage470>$(BDS)\bin\Artwork\Android\FM_SplashImage_470x320.png</Android_SplashImage470>
+        <Android_SplashImage640>$(BDS)\bin\Artwork\Android\FM_SplashImage_640x480.png</Android_SplashImage640>
+        <Android_SplashImage960>$(BDS)\bin\Artwork\Android\FM_SplashImage_960x720.png</Android_SplashImage960>
+        <Android_NotificationIcon24>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_24x24.png</Android_NotificationIcon24>
+        <Android_NotificationIcon36>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_36x36.png</Android_NotificationIcon36>
+        <Android_NotificationIcon48>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_48x48.png</Android_NotificationIcon48>
+        <Android_NotificationIcon72>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_72x72.png</Android_NotificationIcon72>
+        <Android_NotificationIcon96>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_96x96.png</Android_NotificationIcon96>
+        <EnabledSysJars>android-support-v4.dex.jar;cloud-messaging.dex.jar;com-google-android-gms.play-services-ads-base.17.2.0.dex.jar;com-google-android-gms.play-services-ads-identifier.16.0.0.dex.jar;com-google-android-gms.play-services-ads-lite.17.2.0.dex.jar;com-google-android-gms.play-services-ads.17.2.0.dex.jar;com-google-android-gms.play-services-analytics-impl.16.0.8.dex.jar;com-google-android-gms.play-services-analytics.16.0.8.dex.jar;com-google-android-gms.play-services-base.16.0.1.dex.jar;com-google-android-gms.play-services-basement.16.2.0.dex.jar;com-google-android-gms.play-services-gass.17.2.0.dex.jar;com-google-android-gms.play-services-identity.16.0.0.dex.jar;com-google-android-gms.play-services-maps.16.1.0.dex.jar;com-google-android-gms.play-services-measurement-base.16.4.0.dex.jar;com-google-android-gms.play-services-measurement-sdk-api.16.4.0.dex.jar;com-google-android-gms.play-services-stats.16.0.1.dex.jar;com-google-android-gms.play-services-tagmanager-v4-impl.16.0.8.dex.jar;com-google-android-gms.play-services-tasks.16.0.1.dex.jar;com-google-android-gms.play-services-wallet.16.0.1.dex.jar;com-google-firebase.firebase-analytics.16.4.0.dex.jar;com-google-firebase.firebase-common.16.1.0.dex.jar;com-google-firebase.firebase-iid-interop.16.0.1.dex.jar;com-google-firebase.firebase-iid.17.1.1.dex.jar;com-google-firebase.firebase-measurement-connector.17.0.1.dex.jar;com-google-firebase.firebase-messaging.17.5.0.dex.jar;fmx.dex.jar;google-play-billing.dex.jar;google-play-licensing.dex.jar</EnabledSysJars>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Android64)'!=''">
+        <DCC_UsePackage>DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;tethering;bindcompfmx;FmxTeeUI;fmx;FireDACIBDriver;dbexpress;IndyCore;dsnap;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;inet;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;FMXTee;soaprtl;DbxCommonDriver;xmlrtl;soapmidas;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;dbrtl;IndyProtocols;$(DCC_UsePackage)</DCC_UsePackage>
+        <Android_LauncherIcon36>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_36x36.png</Android_LauncherIcon36>
+        <Android_LauncherIcon48>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_48x48.png</Android_LauncherIcon48>
+        <Android_LauncherIcon72>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_72x72.png</Android_LauncherIcon72>
+        <Android_LauncherIcon96>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_96x96.png</Android_LauncherIcon96>
+        <Android_LauncherIcon144>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_144x144.png</Android_LauncherIcon144>
+        <Android_SplashImage426>$(BDS)\bin\Artwork\Android\FM_SplashImage_426x320.png</Android_SplashImage426>
+        <Android_SplashImage470>$(BDS)\bin\Artwork\Android\FM_SplashImage_470x320.png</Android_SplashImage470>
+        <Android_SplashImage640>$(BDS)\bin\Artwork\Android\FM_SplashImage_640x480.png</Android_SplashImage640>
+        <Android_SplashImage960>$(BDS)\bin\Artwork\Android\FM_SplashImage_960x720.png</Android_SplashImage960>
+        <Android_NotificationIcon24>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_24x24.png</Android_NotificationIcon24>
+        <Android_NotificationIcon36>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_36x36.png</Android_NotificationIcon36>
+        <Android_NotificationIcon48>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_48x48.png</Android_NotificationIcon48>
+        <Android_NotificationIcon72>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_72x72.png</Android_NotificationIcon72>
+        <Android_NotificationIcon96>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_96x96.png</Android_NotificationIcon96>
+        <EnabledSysJars>android-support-v4.dex.jar;cloud-messaging.dex.jar;com-google-android-gms.play-services-ads-base.17.2.0.dex.jar;com-google-android-gms.play-services-ads-identifier.16.0.0.dex.jar;com-google-android-gms.play-services-ads-lite.17.2.0.dex.jar;com-google-android-gms.play-services-ads.17.2.0.dex.jar;com-google-android-gms.play-services-analytics-impl.16.0.8.dex.jar;com-google-android-gms.play-services-analytics.16.0.8.dex.jar;com-google-android-gms.play-services-base.16.0.1.dex.jar;com-google-android-gms.play-services-basement.16.2.0.dex.jar;com-google-android-gms.play-services-gass.17.2.0.dex.jar;com-google-android-gms.play-services-identity.16.0.0.dex.jar;com-google-android-gms.play-services-maps.16.1.0.dex.jar;com-google-android-gms.play-services-measurement-base.16.4.0.dex.jar;com-google-android-gms.play-services-measurement-sdk-api.16.4.0.dex.jar;com-google-android-gms.play-services-stats.16.0.1.dex.jar;com-google-android-gms.play-services-tagmanager-v4-impl.16.0.8.dex.jar;com-google-android-gms.play-services-tasks.16.0.1.dex.jar;com-google-android-gms.play-services-wallet.16.0.1.dex.jar;com-google-firebase.firebase-analytics.16.4.0.dex.jar;com-google-firebase.firebase-common.16.1.0.dex.jar;com-google-firebase.firebase-iid-interop.16.0.1.dex.jar;com-google-firebase.firebase-iid.17.1.1.dex.jar;com-google-firebase.firebase-measurement-connector.17.0.1.dex.jar;com-google-firebase.firebase-messaging.17.5.0.dex.jar;fmx.dex.jar;google-play-billing.dex.jar;google-play-licensing.dex.jar</EnabledSysJars>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_iOSDevice64)'!=''">
+        <DCC_UsePackage>DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;tethering;bindcompfmx;TMSFMXPackPkgDXE13;FmxTeeUI;fmx;FireDACIBDriver;dbexpress;IndyCore;dsnap;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;inet;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;FMXTee;soaprtl;DbxCommonDriver;xmlrtl;soapmidas;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;dbrtl;IndyProtocols;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_iOSSimulator)'!=''">
+        <DCC_UsePackage>DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;tethering;bindcompfmx;FmxTeeUI;fmx;FireDACIBDriver;dbexpress;IndyCore;dsnap;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;inet;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;FMXTee;soaprtl;DbxCommonDriver;xmlrtl;soapmidas;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;dbrtl;IndyProtocols;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_OSX64)'!=''">
+        <DCC_UsePackage>DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;tethering;bindcompfmx;inetdb;FmxTeeUI;fmx;FireDACIBDriver;fmxdae;dbexpress;IndyCore;dsnap;FireDACCommon;RESTBackendComponents;soapserver;bindengine;DBXMySQLDriver;CloudService;FireDACMySQLDriver;FireDACCommonODBC;FireDACCommonDriver;inet;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;FireDACPgDriver;FMXTee;soaprtl;DbxCommonDriver;xmlrtl;soapmidas;fmxobj;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;dbrtl;IndyProtocols;inetdbxpress;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
+        <DCC_ConsoleTarget>true</DCC_ConsoleTarget>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Win32)'!=''">
+        <DCC_UsePackage>DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;vclactnband;vclFireDAC;FMXComponents;bindcompvclsmp;tethering;svnui;JvGlobus;FireDACADSDriver;JvPluginSystem;JvMM;PngComponentsD;vcltouch;JvBands;vcldb;bindcompfmx;svn;JvJans;JvNet;inetdb;JvAppFrm;TMSFMXPackPkgDXE13;FmxTeeUI;JvDotNetCtrls;TMSVCLUIPackPkgWizDXE13;fmx;FireDACIBDriver;fmxdae;vcledge;JvWizards;FlatButtonSet;dbexpress;IndyCore;TMSVCLUIPackPkgXlsDXE13;vclx;JvPageComps;dsnap;FireDACCommon;JvDB;RESTBackendComponents;VCLRESTComponents;soapserver;JclDeveloperTools;TMSVCLUIPackPkgDXE13;vclie;TMSVCLIWPkgDEDXE13;bindengine;DBXMySQLDriver;CloudService;JvCmp;FireDACMySQLDriver;JvHMI;FireDACCommonODBC;FireDACCommonDriver;FMXComponentEd;inet;TMSVCLUIPackPkgExDXE13;IndyIPCommon;bindcompdbx;JvCustom;vcl;IndyIPServer;JvXPCtrls;IndySystem;dsnapcon;TMSVCLIWPkgDXE13;FireDACMSAccDriver;fmxFireDAC;vclimg;TeeDB;FireDAC;Jcl;JvCore;JvCrypt;FireDACSqliteDriver;FireDACPgDriver;FMXTee;soaprtl;DbxCommonDriver;JvDlgs;JvRuntimeDesign;JvManagedThreads;Tee;xmlrtl;soapmidas;JvTimeFramework;fmxobj;vclwinx;rtl;DbxClientDriver;CustomIPTransport;vcldsnap;JvSystem;JvStdCtrls;bindcomp;appanalytics;IndyIPClient;bindcompvcl;TeeUI;JvDocking;dbxcds;VclSmp;JvPascalInterpreter;adortl;KernowSoftwareFMX;JclVcl;dsnapxml;dbrtl;IndyProtocols;inetdbxpress;JvControls;JvPrintPreview;JclContainers;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
+        <DCC_Namespace>Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
+        <BT_BuildType>Debug</BT_BuildType>
+        <VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
+        <VerInfo_Locale>1033</VerInfo_Locale>
+        <DCC_ConsoleTarget>true</DCC_ConsoleTarget>
+        <UWP_DelphiLogo44>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png</UWP_DelphiLogo44>
+        <UWP_DelphiLogo150>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png</UWP_DelphiLogo150>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Win64)'!=''">
+        <DCC_UsePackage>DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;vclactnband;vclFireDAC;bindcompvclsmp;tethering;FireDACADSDriver;PngComponentsD;vcltouch;vcldb;bindcompfmx;inetdb;FmxTeeUI;fmx;FireDACIBDriver;fmxdae;vcledge;FlatButtonSet;dbexpress;IndyCore;vclx;dsnap;FireDACCommon;RESTBackendComponents;VCLRESTComponents;soapserver;TMSVCLUIPackPkgDXE13;vclie;bindengine;DBXMySQLDriver;CloudService;FireDACMySQLDriver;FireDACCommonODBC;FireDACCommonDriver;inet;TMSVCLUIPackPkgExDXE13;IndyIPCommon;bindcompdbx;vcl;IndyIPServer;IndySystem;dsnapcon;TMSVCLIWPkgDXE13;FireDACMSAccDriver;fmxFireDAC;vclimg;TeeDB;FireDAC;FireDACSqliteDriver;FireDACPgDriver;FMXTee;soaprtl;DbxCommonDriver;Tee;xmlrtl;soapmidas;fmxobj;vclwinx;rtl;DbxClientDriver;CustomIPTransport;vcldsnap;bindcomp;appanalytics;IndyIPClient;bindcompvcl;TeeUI;dbxcds;VclSmp;adortl;dsnapxml;dbrtl;IndyProtocols;inetdbxpress;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
+        <DCC_ConsoleTarget>true</DCC_ConsoleTarget>
+        <UWP_DelphiLogo44>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png</UWP_DelphiLogo44>
+        <UWP_DelphiLogo150>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png</UWP_DelphiLogo150>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_1)'!=''">
+        <DCC_Define>DEBUG;$(DCC_Define)</DCC_Define>
+        <DCC_DebugDCUs>true</DCC_DebugDCUs>
+        <DCC_Optimize>false</DCC_Optimize>
+        <DCC_GenerateStackFrames>true</DCC_GenerateStackFrames>
+        <DCC_DebugInfoInExe>true</DCC_DebugInfoInExe>
+        <DCC_RemoteDebug>true</DCC_RemoteDebug>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_1_Win32)'!=''">
+        <DCC_RemoteDebug>false</DCC_RemoteDebug>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2)'!=''">
+        <DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
+        <DCC_Define>RELEASE;$(DCC_Define)</DCC_Define>
+        <DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo>
+        <DCC_DebugInformation>0</DCC_DebugInformation>
+    </PropertyGroup>
+    <ItemGroup>
+        <DelphiCompile Include="$(MainSource)">
+            <MainSource>MainSource</MainSource>
+        </DelphiCompile>
+        <BuildConfiguration Include="Release">
+            <Key>Cfg_2</Key>
+            <CfgParent>Base</CfgParent>
+        </BuildConfiguration>
+        <BuildConfiguration Include="Base">
+            <Key>Base</Key>
+        </BuildConfiguration>
+        <BuildConfiguration Include="Debug">
+            <Key>Cfg_1</Key>
+            <CfgParent>Base</CfgParent>
+        </BuildConfiguration>
+    </ItemGroup>
+    <ProjectExtensions>
+        <Borland.Personality>Delphi.Personality.12</Borland.Personality>
+        <Borland.ProjectType>Application</Borland.ProjectType>
+        <BorlandProject>
+            <Delphi.Personality>
+                <Source>
+                    <Source Name="MainSource">ExpressionsTest.dpr</Source>
+                </Source>
+            </Delphi.Personality>
+            <Deployment Version="3">
+                <DeployFile LocalName="$(BDS)\Redist\osx32\libcgunwind.1.0.dylib" Class="DependencyModule">
+                    <Platform Name="OSX32">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile LocalName="$(BDS)\Redist\iossimulator\libcgunwind.1.0.dylib" Class="DependencyModule">
+                    <Platform Name="iOSSimulator">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile LocalName="$(BDS)\Redist\iossimulator\libpcre.dylib" Class="DependencyModule">
+                    <Platform Name="iOSSimulator">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile LocalName="Win32\Debug\ExpressionsTest.exe" Configuration="Debug" Class="ProjectOutput">
+                    <Platform Name="Win32">
+                        <RemoteName>ExpressionsTest.exe</RemoteName>
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployClass Name="AdditionalDebugSymbols">
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidClassesDexFile">
+                    <Platform Name="Android">
+                        <RemoteDir>classes</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>classes</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidFileProvider">
+                    <Platform Name="Android">
+                        <RemoteDir>res\xml</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\xml</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidGDBServer">
+                    <Platform Name="Android">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidLibnativeArmeabiFile">
+                    <Platform Name="Android">
+                        <RemoteDir>library\lib\armeabi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\armeabi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidLibnativeArmeabiv7aFile">
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidLibnativeMipsFile">
+                    <Platform Name="Android">
+                        <RemoteDir>library\lib\mips</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\mips</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidServiceOutput">
+                    <Platform Name="Android">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\arm64-v8a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidServiceOutput_Android32">
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidSplashImageDef">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidSplashStyles">
+                    <Platform Name="Android">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidSplashStylesV21">
+                    <Platform Name="Android">
+                        <RemoteDir>res\values-v21</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\values-v21</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_Colors">
+                    <Platform Name="Android">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_DefaultAppIcon">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon144">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon36">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-ldpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-ldpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon48">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-mdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-mdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon72">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-hdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-hdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon96">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_NotificationIcon24">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-mdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-mdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_NotificationIcon36">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-hdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-hdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_NotificationIcon48">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_NotificationIcon72">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_NotificationIcon96">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xxxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xxxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_SplashImage426">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-small</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-small</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_SplashImage470">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-normal</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-normal</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_SplashImage640">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-large</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-large</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_SplashImage960">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xlarge</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xlarge</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_Strings">
+                    <Platform Name="Android">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="DebugSymbols">
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="DependencyFramework">
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.framework</Extensions>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.framework</Extensions>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="DependencyModule">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                        <Extensions>.dll;.bpl</Extensions>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Required="true" Name="DependencyPackage">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                        <Extensions>.bpl</Extensions>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="File">
+                    <Platform Name="Android">
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice32">
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\Resources\StartUp\</RemoteDir>
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\Resources\StartUp\</RemoteDir>
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iOS_AppStore1024">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_AppIcon152">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_AppIcon167">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_Launch2x">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_LaunchDark2x">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_Notification40">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_Setting58">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_SpotLight80">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_AppIcon120">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_AppIcon180">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch2x">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch3x">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_LaunchDark2x">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_LaunchDark3x">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Notification40">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Notification60">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Setting58">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Setting87">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Spotlight120">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Spotlight80">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectAndroidManifest">
+                    <Platform Name="Android">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectiOSDeviceDebug">
+                    <Platform Name="iOSDevice32">
+                        <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectiOSEntitlements">
+                    <Platform Name="iOSDevice32">
+                        <RemoteDir>..\</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectiOSInfoPList">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectiOSLaunchScreen">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen</RemoteDir>
+                        <Operation>64</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen</RemoteDir>
+                        <Operation>64</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectiOSResource">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectOSXDebug">
+                    <Platform Name="OSX64">
+                        <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectOSXEntitlements">
+                    <Platform Name="OSX32">
+                        <RemoteDir>..\</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>..\</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectOSXInfoPList">
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectOSXResource">
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\Resources</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\Resources</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Required="true" Name="ProjectOutput">
+                    <Platform Name="Android">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\arm64-v8a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Linux64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectOutput_Android32">
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectUWPManifest">
+                    <Platform Name="Win32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win64">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="UWP_DelphiLogo150">
+                    <Platform Name="Win32">
+                        <RemoteDir>Assets</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win64">
+                        <RemoteDir>Assets</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="UWP_DelphiLogo44">
+                    <Platform Name="Win32">
+                        <RemoteDir>Assets</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win64">
+                        <RemoteDir>Assets</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <ProjectRoot Platform="iOSDevice64" Name="$(PROJECTNAME).app"/>
+                <ProjectRoot Platform="Win64" Name="$(PROJECTNAME)"/>
+                <ProjectRoot Platform="iOSDevice32" Name="$(PROJECTNAME).app"/>
+                <ProjectRoot Platform="Linux64" Name="$(PROJECTNAME)"/>
+                <ProjectRoot Platform="Win32" Name="$(PROJECTNAME)"/>
+                <ProjectRoot Platform="OSX32" Name="$(PROJECTNAME).app"/>
+                <ProjectRoot Platform="Android" Name="$(PROJECTNAME)"/>
+                <ProjectRoot Platform="OSX64" Name="$(PROJECTNAME).app"/>
+                <ProjectRoot Platform="iOSSimulator" Name="$(PROJECTNAME).app"/>
+                <ProjectRoot Platform="Android64" Name="$(PROJECTNAME)"/>
+            </Deployment>
+            <Platforms>
+                <Platform value="Android">False</Platform>
+                <Platform value="Android64">False</Platform>
+                <Platform value="iOSDevice64">False</Platform>
+                <Platform value="iOSSimulator">False</Platform>
+                <Platform value="OSX64">False</Platform>
+                <Platform value="Win32">True</Platform>
+                <Platform value="Win64">False</Platform>
+            </Platforms>
+        </BorlandProject>
+        <ProjectFileVersion>12</ProjectFileVersion>
+    </ProjectExtensions>
+    <Import Project="$(BDS)\Bin\CodeGear.Delphi.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')"/>
+    <Import Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj" Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')"/>
+    <Import Project="$(MSBuildProjectName).deployproj" Condition="Exists('$(MSBuildProjectName).deployproj')"/>
+</Project>

+ 84 - 0
samples/delphi/QuickJsonSerializer/ComplexObjects/ComplexObjects.dpr

@@ -0,0 +1,84 @@
+program ComplexObjects;
+
+{$APPTYPE CONSOLE}
+
+{$R *.res}
+
+uses
+  Classes,
+  System.SysUtils,
+  Quick.Console,
+  Quick.Json.Serializer;
+
+type
+  TUser = class
+  private
+    fName : string;
+    fAge : Integer;
+    fPhoto : TMemoryStream;
+  public
+    constructor Create;
+    destructor Destroy; override;
+  published
+    property Name : string read fName write fName;
+    property Age : Integer read fAge write fAge;
+    property Photo : TMemoryStream read fPhoto write fPhoto;
+  end;
+
+var
+  json : string;
+  user : TUser;
+  photosize : Integer;
+  serializer : TJsonSerializer;
+{ TUser }
+
+constructor TUser.Create;
+begin
+  fPhoto := TMemoryStream.Create;
+end;
+
+destructor TUser.Destroy;
+begin
+  fPhoto.Free;
+  inherited;
+end;
+
+begin
+  try
+    user := TUser.Create;
+    user.Name := 'John';
+    user.Age := 30;
+    user.Photo.LoadFromFile('.\photo.jpg');
+    photosize := user.Photo.Size;
+    cout('Photo Size: ' + photosize.ToString,ccWhite);
+
+    serializer := TJsonSerializer.Create(TSerializeLevel.slPublicProperty,True);
+    try
+      //serializer.UseBase64Stream := False;
+      //serialize
+      cout('Serialize User:',ccYellow);
+      json := serializer.ObjectToJson(user);
+      //cout(json,ccWhite);
+      user.Free;
+      //deserialize
+      cout('Deserialize User:',ccYellow);
+      user := TUser.Create;
+      serializer.JsonToObject(user,json);
+      //check if deseralization is correct
+      Assert(user.Name = 'John','Name serialize error!');
+      Assert(user.Age = 30,'Age serialize error!');
+      Assert(user.Photo.Size = photosize,'Photo serialize error!');
+      user.Photo.SaveToFile('.\photo_new.jpg');
+      cout('Photo Size: ' + photosize.ToString,ccWhite);
+      cout(user.Name,ccWhite);
+    finally
+      serializer.Free;
+    end;
+    user.Free;
+    ConsoleWaitForEnterKey;
+  except
+    on E: Exception do
+      Writeln(E.ClassName, ': ', E.Message);
+  end;
+end.
+

+ 980 - 0
samples/delphi/QuickJsonSerializer/ComplexObjects/ComplexObjects.dproj

@@ -0,0 +1,980 @@
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+    <PropertyGroup>
+        <ProjectGuid>{81421C2A-B66D-45DC-87B4-66FED4AD644F}</ProjectGuid>
+        <ProjectVersion>19.1</ProjectVersion>
+        <FrameworkType>None</FrameworkType>
+        <Base>True</Base>
+        <Config Condition="'$(Config)'==''">Debug</Config>
+        <Platform Condition="'$(Platform)'==''">Win32</Platform>
+        <TargetedPlatforms>1</TargetedPlatforms>
+        <AppType>Console</AppType>
+        <MainSource>ComplexObjects.dpr</MainSource>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Android' and '$(Base)'=='true') or '$(Base_Android)'!=''">
+        <Base_Android>true</Base_Android>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Android64' and '$(Base)'=='true') or '$(Base_Android64)'!=''">
+        <Base_Android64>true</Base_Android64>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='iOSDevice64' and '$(Base)'=='true') or '$(Base_iOSDevice64)'!=''">
+        <Base_iOSDevice64>true</Base_iOSDevice64>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='iOSSimulator' and '$(Base)'=='true') or '$(Base_iOSSimulator)'!=''">
+        <Base_iOSSimulator>true</Base_iOSSimulator>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='OSX64' and '$(Base)'=='true') or '$(Base_OSX64)'!=''">
+        <Base_OSX64>true</Base_OSX64>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''">
+        <Base_Win32>true</Base_Win32>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Base)'=='true') or '$(Base_Win64)'!=''">
+        <Base_Win64>true</Base_Win64>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_1)'!=''">
+        <Cfg_1>true</Cfg_1>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_1)'=='true') or '$(Cfg_1_Win32)'!=''">
+        <Cfg_1_Win32>true</Cfg_1_Win32>
+        <CfgParent>Cfg_1</CfgParent>
+        <Cfg_1>true</Cfg_1>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_2)'!=''">
+        <Cfg_2>true</Cfg_2>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base)'!=''">
+        <DCC_DcuOutput>.\$(Platform)\$(Config)</DCC_DcuOutput>
+        <DCC_ExeOutput>.\$(Platform)\$(Config)</DCC_ExeOutput>
+        <DCC_E>false</DCC_E>
+        <DCC_N>false</DCC_N>
+        <DCC_S>false</DCC_S>
+        <DCC_F>false</DCC_F>
+        <DCC_K>false</DCC_K>
+        <DCC_Namespace>System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace)</DCC_Namespace>
+        <SanitizedProjectName>ComplexObjects</SanitizedProjectName>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Android)'!=''">
+        <DCC_UsePackage>DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;tethering;bindcompfmx;FmxTeeUI;fmx;FireDACIBDriver;FlatButtonSet;dbexpress;IndyCore;dsnap;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;inet;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;FMXTee;soaprtl;DbxCommonDriver;xmlrtl;soapmidas;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;dbrtl;IndyProtocols;$(DCC_UsePackage)</DCC_UsePackage>
+        <Android_LauncherIcon36>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_36x36.png</Android_LauncherIcon36>
+        <Android_LauncherIcon48>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_48x48.png</Android_LauncherIcon48>
+        <Android_LauncherIcon72>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_72x72.png</Android_LauncherIcon72>
+        <Android_LauncherIcon96>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_96x96.png</Android_LauncherIcon96>
+        <Android_LauncherIcon144>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_144x144.png</Android_LauncherIcon144>
+        <Android_SplashImage426>$(BDS)\bin\Artwork\Android\FM_SplashImage_426x320.png</Android_SplashImage426>
+        <Android_SplashImage470>$(BDS)\bin\Artwork\Android\FM_SplashImage_470x320.png</Android_SplashImage470>
+        <Android_SplashImage640>$(BDS)\bin\Artwork\Android\FM_SplashImage_640x480.png</Android_SplashImage640>
+        <Android_SplashImage960>$(BDS)\bin\Artwork\Android\FM_SplashImage_960x720.png</Android_SplashImage960>
+        <Android_NotificationIcon24>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_24x24.png</Android_NotificationIcon24>
+        <Android_NotificationIcon36>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_36x36.png</Android_NotificationIcon36>
+        <Android_NotificationIcon48>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_48x48.png</Android_NotificationIcon48>
+        <Android_NotificationIcon72>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_72x72.png</Android_NotificationIcon72>
+        <Android_NotificationIcon96>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_96x96.png</Android_NotificationIcon96>
+        <EnabledSysJars>android-support-v4.dex.jar;cloud-messaging.dex.jar;com-google-android-gms.play-services-ads-base.17.2.0.dex.jar;com-google-android-gms.play-services-ads-identifier.16.0.0.dex.jar;com-google-android-gms.play-services-ads-lite.17.2.0.dex.jar;com-google-android-gms.play-services-ads.17.2.0.dex.jar;com-google-android-gms.play-services-analytics-impl.16.0.8.dex.jar;com-google-android-gms.play-services-analytics.16.0.8.dex.jar;com-google-android-gms.play-services-base.16.0.1.dex.jar;com-google-android-gms.play-services-basement.16.2.0.dex.jar;com-google-android-gms.play-services-gass.17.2.0.dex.jar;com-google-android-gms.play-services-identity.16.0.0.dex.jar;com-google-android-gms.play-services-maps.16.1.0.dex.jar;com-google-android-gms.play-services-measurement-base.16.4.0.dex.jar;com-google-android-gms.play-services-measurement-sdk-api.16.4.0.dex.jar;com-google-android-gms.play-services-stats.16.0.1.dex.jar;com-google-android-gms.play-services-tagmanager-v4-impl.16.0.8.dex.jar;com-google-android-gms.play-services-tasks.16.0.1.dex.jar;com-google-android-gms.play-services-wallet.16.0.1.dex.jar;com-google-firebase.firebase-analytics.16.4.0.dex.jar;com-google-firebase.firebase-common.16.1.0.dex.jar;com-google-firebase.firebase-iid-interop.16.0.1.dex.jar;com-google-firebase.firebase-iid.17.1.1.dex.jar;com-google-firebase.firebase-measurement-connector.17.0.1.dex.jar;com-google-firebase.firebase-messaging.17.5.0.dex.jar;fmx.dex.jar;google-play-billing.dex.jar;google-play-licensing.dex.jar</EnabledSysJars>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Android64)'!=''">
+        <DCC_UsePackage>DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;tethering;bindcompfmx;FmxTeeUI;fmx;FireDACIBDriver;dbexpress;IndyCore;dsnap;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;inet;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;FMXTee;soaprtl;DbxCommonDriver;xmlrtl;soapmidas;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;dbrtl;IndyProtocols;$(DCC_UsePackage)</DCC_UsePackage>
+        <Android_LauncherIcon36>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_36x36.png</Android_LauncherIcon36>
+        <Android_LauncherIcon48>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_48x48.png</Android_LauncherIcon48>
+        <Android_LauncherIcon72>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_72x72.png</Android_LauncherIcon72>
+        <Android_LauncherIcon96>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_96x96.png</Android_LauncherIcon96>
+        <Android_LauncherIcon144>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_144x144.png</Android_LauncherIcon144>
+        <Android_SplashImage426>$(BDS)\bin\Artwork\Android\FM_SplashImage_426x320.png</Android_SplashImage426>
+        <Android_SplashImage470>$(BDS)\bin\Artwork\Android\FM_SplashImage_470x320.png</Android_SplashImage470>
+        <Android_SplashImage640>$(BDS)\bin\Artwork\Android\FM_SplashImage_640x480.png</Android_SplashImage640>
+        <Android_SplashImage960>$(BDS)\bin\Artwork\Android\FM_SplashImage_960x720.png</Android_SplashImage960>
+        <Android_NotificationIcon24>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_24x24.png</Android_NotificationIcon24>
+        <Android_NotificationIcon36>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_36x36.png</Android_NotificationIcon36>
+        <Android_NotificationIcon48>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_48x48.png</Android_NotificationIcon48>
+        <Android_NotificationIcon72>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_72x72.png</Android_NotificationIcon72>
+        <Android_NotificationIcon96>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_96x96.png</Android_NotificationIcon96>
+        <EnabledSysJars>android-support-v4.dex.jar;cloud-messaging.dex.jar;com-google-android-gms.play-services-ads-base.17.2.0.dex.jar;com-google-android-gms.play-services-ads-identifier.16.0.0.dex.jar;com-google-android-gms.play-services-ads-lite.17.2.0.dex.jar;com-google-android-gms.play-services-ads.17.2.0.dex.jar;com-google-android-gms.play-services-analytics-impl.16.0.8.dex.jar;com-google-android-gms.play-services-analytics.16.0.8.dex.jar;com-google-android-gms.play-services-base.16.0.1.dex.jar;com-google-android-gms.play-services-basement.16.2.0.dex.jar;com-google-android-gms.play-services-gass.17.2.0.dex.jar;com-google-android-gms.play-services-identity.16.0.0.dex.jar;com-google-android-gms.play-services-maps.16.1.0.dex.jar;com-google-android-gms.play-services-measurement-base.16.4.0.dex.jar;com-google-android-gms.play-services-measurement-sdk-api.16.4.0.dex.jar;com-google-android-gms.play-services-stats.16.0.1.dex.jar;com-google-android-gms.play-services-tagmanager-v4-impl.16.0.8.dex.jar;com-google-android-gms.play-services-tasks.16.0.1.dex.jar;com-google-android-gms.play-services-wallet.16.0.1.dex.jar;com-google-firebase.firebase-analytics.16.4.0.dex.jar;com-google-firebase.firebase-common.16.1.0.dex.jar;com-google-firebase.firebase-iid-interop.16.0.1.dex.jar;com-google-firebase.firebase-iid.17.1.1.dex.jar;com-google-firebase.firebase-measurement-connector.17.0.1.dex.jar;com-google-firebase.firebase-messaging.17.5.0.dex.jar;fmx.dex.jar;google-play-billing.dex.jar;google-play-licensing.dex.jar</EnabledSysJars>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_iOSDevice64)'!=''">
+        <DCC_UsePackage>DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;tethering;bindcompfmx;TMSFMXPackPkgDXE13;FmxTeeUI;fmx;FireDACIBDriver;dbexpress;IndyCore;dsnap;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;inet;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;FMXTee;soaprtl;DbxCommonDriver;xmlrtl;soapmidas;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;dbrtl;IndyProtocols;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_iOSSimulator)'!=''">
+        <DCC_UsePackage>DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;tethering;bindcompfmx;FmxTeeUI;fmx;FireDACIBDriver;dbexpress;IndyCore;dsnap;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;inet;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;FMXTee;soaprtl;DbxCommonDriver;xmlrtl;soapmidas;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;dbrtl;IndyProtocols;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_OSX64)'!=''">
+        <DCC_UsePackage>DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;tethering;bindcompfmx;inetdb;FmxTeeUI;fmx;FireDACIBDriver;fmxdae;dbexpress;IndyCore;dsnap;FireDACCommon;RESTBackendComponents;soapserver;bindengine;DBXMySQLDriver;CloudService;FireDACMySQLDriver;FireDACCommonODBC;FireDACCommonDriver;inet;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;FireDACPgDriver;FMXTee;soaprtl;DbxCommonDriver;xmlrtl;soapmidas;fmxobj;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;dbrtl;IndyProtocols;inetdbxpress;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
+        <DCC_ConsoleTarget>true</DCC_ConsoleTarget>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Win32)'!=''">
+        <DCC_UsePackage>DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;vclactnband;vclFireDAC;FMXComponents;bindcompvclsmp;tethering;svnui;JvGlobus;FireDACADSDriver;JvPluginSystem;JvMM;PngComponentsD;vcltouch;JvBands;vcldb;bindcompfmx;svn;JvJans;JvNet;inetdb;JvAppFrm;TMSFMXPackPkgDXE13;FmxTeeUI;JvDotNetCtrls;TMSVCLUIPackPkgWizDXE13;fmx;FireDACIBDriver;fmxdae;vcledge;JvWizards;FlatButtonSet;dbexpress;IndyCore;TMSVCLUIPackPkgXlsDXE13;vclx;JvPageComps;dsnap;FireDACCommon;JvDB;RESTBackendComponents;VCLRESTComponents;soapserver;JclDeveloperTools;TMSVCLUIPackPkgDXE13;vclie;TMSVCLIWPkgDEDXE13;bindengine;DBXMySQLDriver;CloudService;JvCmp;FireDACMySQLDriver;JvHMI;FireDACCommonODBC;FireDACCommonDriver;FMXComponentEd;inet;TMSVCLUIPackPkgExDXE13;IndyIPCommon;bindcompdbx;JvCustom;vcl;IndyIPServer;JvXPCtrls;IndySystem;dsnapcon;TMSVCLIWPkgDXE13;FireDACMSAccDriver;fmxFireDAC;vclimg;TeeDB;FireDAC;Jcl;JvCore;JvCrypt;FireDACSqliteDriver;FireDACPgDriver;FMXTee;soaprtl;DbxCommonDriver;JvDlgs;JvRuntimeDesign;JvManagedThreads;Tee;xmlrtl;soapmidas;JvTimeFramework;fmxobj;vclwinx;rtl;DbxClientDriver;CustomIPTransport;vcldsnap;JvSystem;JvStdCtrls;bindcomp;appanalytics;IndyIPClient;bindcompvcl;TeeUI;JvDocking;dbxcds;VclSmp;JvPascalInterpreter;adortl;KernowSoftwareFMX;JclVcl;dsnapxml;dbrtl;IndyProtocols;inetdbxpress;JvControls;JvPrintPreview;JclContainers;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
+        <DCC_Namespace>Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
+        <BT_BuildType>Debug</BT_BuildType>
+        <VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
+        <VerInfo_Locale>1033</VerInfo_Locale>
+        <DCC_ConsoleTarget>true</DCC_ConsoleTarget>
+        <UWP_DelphiLogo44>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png</UWP_DelphiLogo44>
+        <UWP_DelphiLogo150>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png</UWP_DelphiLogo150>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Win64)'!=''">
+        <DCC_UsePackage>DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;vclactnband;vclFireDAC;bindcompvclsmp;tethering;FireDACADSDriver;PngComponentsD;vcltouch;vcldb;bindcompfmx;inetdb;FmxTeeUI;fmx;FireDACIBDriver;fmxdae;vcledge;FlatButtonSet;dbexpress;IndyCore;vclx;dsnap;FireDACCommon;RESTBackendComponents;VCLRESTComponents;soapserver;TMSVCLUIPackPkgDXE13;vclie;bindengine;DBXMySQLDriver;CloudService;FireDACMySQLDriver;FireDACCommonODBC;FireDACCommonDriver;inet;TMSVCLUIPackPkgExDXE13;IndyIPCommon;bindcompdbx;vcl;IndyIPServer;IndySystem;dsnapcon;TMSVCLIWPkgDXE13;FireDACMSAccDriver;fmxFireDAC;vclimg;TeeDB;FireDAC;FireDACSqliteDriver;FireDACPgDriver;FMXTee;soaprtl;DbxCommonDriver;Tee;xmlrtl;soapmidas;fmxobj;vclwinx;rtl;DbxClientDriver;CustomIPTransport;vcldsnap;bindcomp;appanalytics;IndyIPClient;bindcompvcl;TeeUI;dbxcds;VclSmp;adortl;dsnapxml;dbrtl;IndyProtocols;inetdbxpress;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
+        <DCC_ConsoleTarget>true</DCC_ConsoleTarget>
+        <UWP_DelphiLogo44>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png</UWP_DelphiLogo44>
+        <UWP_DelphiLogo150>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png</UWP_DelphiLogo150>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_1)'!=''">
+        <DCC_Define>DEBUG;$(DCC_Define)</DCC_Define>
+        <DCC_DebugDCUs>true</DCC_DebugDCUs>
+        <DCC_Optimize>false</DCC_Optimize>
+        <DCC_GenerateStackFrames>true</DCC_GenerateStackFrames>
+        <DCC_DebugInfoInExe>true</DCC_DebugInfoInExe>
+        <DCC_RemoteDebug>true</DCC_RemoteDebug>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_1_Win32)'!=''">
+        <DCC_RemoteDebug>false</DCC_RemoteDebug>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2)'!=''">
+        <DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
+        <DCC_Define>RELEASE;$(DCC_Define)</DCC_Define>
+        <DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo>
+        <DCC_DebugInformation>0</DCC_DebugInformation>
+    </PropertyGroup>
+    <ItemGroup>
+        <DelphiCompile Include="$(MainSource)">
+            <MainSource>MainSource</MainSource>
+        </DelphiCompile>
+        <BuildConfiguration Include="Release">
+            <Key>Cfg_2</Key>
+            <CfgParent>Base</CfgParent>
+        </BuildConfiguration>
+        <BuildConfiguration Include="Base">
+            <Key>Base</Key>
+        </BuildConfiguration>
+        <BuildConfiguration Include="Debug">
+            <Key>Cfg_1</Key>
+            <CfgParent>Base</CfgParent>
+        </BuildConfiguration>
+    </ItemGroup>
+    <ProjectExtensions>
+        <Borland.Personality>Delphi.Personality.12</Borland.Personality>
+        <Borland.ProjectType>Application</Borland.ProjectType>
+        <BorlandProject>
+            <Delphi.Personality>
+                <Source>
+                    <Source Name="MainSource">ComplexObjects.dpr</Source>
+                </Source>
+            </Delphi.Personality>
+            <Deployment Version="3">
+                <DeployFile LocalName="$(BDS)\Redist\osx32\libcgunwind.1.0.dylib" Class="DependencyModule">
+                    <Platform Name="OSX32">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile LocalName="$(BDS)\Redist\iossimulator\libcgunwind.1.0.dylib" Class="DependencyModule">
+                    <Platform Name="iOSSimulator">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile LocalName="$(BDS)\Redist\iossimulator\libpcre.dylib" Class="DependencyModule">
+                    <Platform Name="iOSSimulator">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile LocalName="Win32\Debug\ComplexObjects.exe" Configuration="Debug" Class="ProjectOutput">
+                    <Platform Name="Win32">
+                        <RemoteName>ComplexObjects.exe</RemoteName>
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployClass Name="AdditionalDebugSymbols">
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidClassesDexFile">
+                    <Platform Name="Android">
+                        <RemoteDir>classes</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>classes</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidFileProvider">
+                    <Platform Name="Android">
+                        <RemoteDir>res\xml</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\xml</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidGDBServer">
+                    <Platform Name="Android">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidLibnativeArmeabiFile">
+                    <Platform Name="Android">
+                        <RemoteDir>library\lib\armeabi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\armeabi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidLibnativeArmeabiv7aFile">
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidLibnativeMipsFile">
+                    <Platform Name="Android">
+                        <RemoteDir>library\lib\mips</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\mips</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidServiceOutput">
+                    <Platform Name="Android">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\arm64-v8a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidServiceOutput_Android32">
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidSplashImageDef">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidSplashStyles">
+                    <Platform Name="Android">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidSplashStylesV21">
+                    <Platform Name="Android">
+                        <RemoteDir>res\values-v21</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\values-v21</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_Colors">
+                    <Platform Name="Android">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_DefaultAppIcon">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon144">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon36">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-ldpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-ldpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon48">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-mdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-mdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon72">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-hdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-hdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon96">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_NotificationIcon24">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-mdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-mdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_NotificationIcon36">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-hdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-hdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_NotificationIcon48">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_NotificationIcon72">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_NotificationIcon96">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xxxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xxxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_SplashImage426">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-small</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-small</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_SplashImage470">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-normal</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-normal</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_SplashImage640">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-large</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-large</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_SplashImage960">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xlarge</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xlarge</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_Strings">
+                    <Platform Name="Android">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="DebugSymbols">
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="DependencyFramework">
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.framework</Extensions>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.framework</Extensions>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="DependencyModule">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                        <Extensions>.dll;.bpl</Extensions>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Required="true" Name="DependencyPackage">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                        <Extensions>.bpl</Extensions>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="File">
+                    <Platform Name="Android">
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice32">
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\Resources\StartUp\</RemoteDir>
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\Resources\StartUp\</RemoteDir>
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iOS_AppStore1024">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_AppIcon152">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_AppIcon167">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_Launch2x">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_LaunchDark2x">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_Notification40">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_Setting58">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_SpotLight80">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_AppIcon120">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_AppIcon180">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch2x">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch3x">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_LaunchDark2x">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_LaunchDark3x">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Notification40">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Notification60">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Setting58">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Setting87">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Spotlight120">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Spotlight80">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectAndroidManifest">
+                    <Platform Name="Android">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectiOSDeviceDebug">
+                    <Platform Name="iOSDevice32">
+                        <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectiOSEntitlements">
+                    <Platform Name="iOSDevice32">
+                        <RemoteDir>..\</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectiOSInfoPList">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectiOSLaunchScreen">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen</RemoteDir>
+                        <Operation>64</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen</RemoteDir>
+                        <Operation>64</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectiOSResource">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectOSXDebug">
+                    <Platform Name="OSX64">
+                        <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectOSXEntitlements">
+                    <Platform Name="OSX32">
+                        <RemoteDir>..\</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>..\</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectOSXInfoPList">
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectOSXResource">
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\Resources</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\Resources</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Required="true" Name="ProjectOutput">
+                    <Platform Name="Android">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\arm64-v8a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Linux64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectOutput_Android32">
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectUWPManifest">
+                    <Platform Name="Win32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win64">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="UWP_DelphiLogo150">
+                    <Platform Name="Win32">
+                        <RemoteDir>Assets</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win64">
+                        <RemoteDir>Assets</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="UWP_DelphiLogo44">
+                    <Platform Name="Win32">
+                        <RemoteDir>Assets</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win64">
+                        <RemoteDir>Assets</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <ProjectRoot Platform="iOSDevice64" Name="$(PROJECTNAME).app"/>
+                <ProjectRoot Platform="Win64" Name="$(PROJECTNAME)"/>
+                <ProjectRoot Platform="iOSDevice32" Name="$(PROJECTNAME).app"/>
+                <ProjectRoot Platform="Linux64" Name="$(PROJECTNAME)"/>
+                <ProjectRoot Platform="Win32" Name="$(PROJECTNAME)"/>
+                <ProjectRoot Platform="OSX32" Name="$(PROJECTNAME).app"/>
+                <ProjectRoot Platform="Android" Name="$(PROJECTNAME)"/>
+                <ProjectRoot Platform="OSX64" Name="$(PROJECTNAME).app"/>
+                <ProjectRoot Platform="iOSSimulator" Name="$(PROJECTNAME).app"/>
+                <ProjectRoot Platform="Android64" Name="$(PROJECTNAME)"/>
+            </Deployment>
+            <Platforms>
+                <Platform value="Android">False</Platform>
+                <Platform value="Android64">False</Platform>
+                <Platform value="iOSDevice64">False</Platform>
+                <Platform value="iOSSimulator">False</Platform>
+                <Platform value="OSX64">False</Platform>
+                <Platform value="Win32">True</Platform>
+                <Platform value="Win64">False</Platform>
+            </Platforms>
+        </BorlandProject>
+        <ProjectFileVersion>12</ProjectFileVersion>
+    </ProjectExtensions>
+    <Import Project="$(BDS)\Bin\CodeGear.Delphi.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')"/>
+    <Import Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj" Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')"/>
+    <Import Project="$(MSBuildProjectName).deployproj" Condition="Exists('$(MSBuildProjectName).deployproj')"/>
+</Project>

+ 55 - 0
samples/delphi/QuickJsonSerializer/ObjectToJsonStream/ObjectToJsonStream.dpr

@@ -0,0 +1,55 @@
+program ObjectToJsonStream;
+
+{$APPTYPE CONSOLE}
+
+{$R *.res}
+
+uses
+  Classes,
+  System.SysUtils,
+  Quick.Console,
+  Quick.Json.Serializer;
+
+type
+  TUser = class
+  private
+    fName : string;
+    fAge : Integer;
+  public
+    property Name : string read fName write fName;
+    property Age : Integer read fAge write fAge;
+  end;
+
+var
+  ss : TStringStream;
+  user : TUser;
+  serializer : TJsonSerializer;
+begin
+  try
+    user := TUser.Create;
+    user.Name := 'John';
+    user.Age := 30;
+    ss := TStringStream.Create;
+    try
+      serializer := TJsonSerializer.Create(TSerializeLevel.slPublicProperty,True);
+      try
+        serializer.ObjectToJsonStream(user,ss);
+        cout(ss.DataString,ccWhite);
+
+        user.Name := 'Peter';
+        serializer.JsonStreamToObject(user,ss);
+        Assert(user.Name = 'John','Serializer not modified property!');
+        cout(user.Name,ccWhite);
+      finally
+        serializer.Free;
+      end;
+    finally
+      ss.Free;
+    end;
+    user.Free;
+    ConsoleWaitForEnterKey;
+  except
+    on E: Exception do
+      Writeln(E.ClassName, ': ', E.Message);
+  end;
+end.

+ 980 - 0
samples/delphi/QuickJsonSerializer/ObjectToJsonStream/ObjectToJsonStream.dproj

@@ -0,0 +1,980 @@
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+    <PropertyGroup>
+        <ProjectGuid>{0A4A0D77-5E76-4647-B4AA-CC89456B29F4}</ProjectGuid>
+        <ProjectVersion>19.1</ProjectVersion>
+        <FrameworkType>None</FrameworkType>
+        <Base>True</Base>
+        <Config Condition="'$(Config)'==''">Debug</Config>
+        <Platform Condition="'$(Platform)'==''">Win32</Platform>
+        <TargetedPlatforms>1</TargetedPlatforms>
+        <AppType>Console</AppType>
+        <MainSource>ObjectToJsonStream.dpr</MainSource>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Android' and '$(Base)'=='true') or '$(Base_Android)'!=''">
+        <Base_Android>true</Base_Android>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Android64' and '$(Base)'=='true') or '$(Base_Android64)'!=''">
+        <Base_Android64>true</Base_Android64>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='iOSDevice64' and '$(Base)'=='true') or '$(Base_iOSDevice64)'!=''">
+        <Base_iOSDevice64>true</Base_iOSDevice64>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='iOSSimulator' and '$(Base)'=='true') or '$(Base_iOSSimulator)'!=''">
+        <Base_iOSSimulator>true</Base_iOSSimulator>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='OSX64' and '$(Base)'=='true') or '$(Base_OSX64)'!=''">
+        <Base_OSX64>true</Base_OSX64>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''">
+        <Base_Win32>true</Base_Win32>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Base)'=='true') or '$(Base_Win64)'!=''">
+        <Base_Win64>true</Base_Win64>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_1)'!=''">
+        <Cfg_1>true</Cfg_1>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_1)'=='true') or '$(Cfg_1_Win32)'!=''">
+        <Cfg_1_Win32>true</Cfg_1_Win32>
+        <CfgParent>Cfg_1</CfgParent>
+        <Cfg_1>true</Cfg_1>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_2)'!=''">
+        <Cfg_2>true</Cfg_2>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base)'!=''">
+        <DCC_DcuOutput>.\$(Platform)\$(Config)</DCC_DcuOutput>
+        <DCC_ExeOutput>.\$(Platform)\$(Config)</DCC_ExeOutput>
+        <DCC_E>false</DCC_E>
+        <DCC_N>false</DCC_N>
+        <DCC_S>false</DCC_S>
+        <DCC_F>false</DCC_F>
+        <DCC_K>false</DCC_K>
+        <DCC_Namespace>System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace)</DCC_Namespace>
+        <SanitizedProjectName>ObjectToJsonStream</SanitizedProjectName>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Android)'!=''">
+        <DCC_UsePackage>DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;tethering;bindcompfmx;FmxTeeUI;fmx;FireDACIBDriver;FlatButtonSet;dbexpress;IndyCore;dsnap;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;inet;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;FMXTee;soaprtl;DbxCommonDriver;xmlrtl;soapmidas;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;dbrtl;IndyProtocols;$(DCC_UsePackage)</DCC_UsePackage>
+        <Android_LauncherIcon36>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_36x36.png</Android_LauncherIcon36>
+        <Android_LauncherIcon48>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_48x48.png</Android_LauncherIcon48>
+        <Android_LauncherIcon72>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_72x72.png</Android_LauncherIcon72>
+        <Android_LauncherIcon96>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_96x96.png</Android_LauncherIcon96>
+        <Android_LauncherIcon144>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_144x144.png</Android_LauncherIcon144>
+        <Android_SplashImage426>$(BDS)\bin\Artwork\Android\FM_SplashImage_426x320.png</Android_SplashImage426>
+        <Android_SplashImage470>$(BDS)\bin\Artwork\Android\FM_SplashImage_470x320.png</Android_SplashImage470>
+        <Android_SplashImage640>$(BDS)\bin\Artwork\Android\FM_SplashImage_640x480.png</Android_SplashImage640>
+        <Android_SplashImage960>$(BDS)\bin\Artwork\Android\FM_SplashImage_960x720.png</Android_SplashImage960>
+        <Android_NotificationIcon24>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_24x24.png</Android_NotificationIcon24>
+        <Android_NotificationIcon36>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_36x36.png</Android_NotificationIcon36>
+        <Android_NotificationIcon48>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_48x48.png</Android_NotificationIcon48>
+        <Android_NotificationIcon72>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_72x72.png</Android_NotificationIcon72>
+        <Android_NotificationIcon96>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_96x96.png</Android_NotificationIcon96>
+        <EnabledSysJars>android-support-v4.dex.jar;cloud-messaging.dex.jar;com-google-android-gms.play-services-ads-base.17.2.0.dex.jar;com-google-android-gms.play-services-ads-identifier.16.0.0.dex.jar;com-google-android-gms.play-services-ads-lite.17.2.0.dex.jar;com-google-android-gms.play-services-ads.17.2.0.dex.jar;com-google-android-gms.play-services-analytics-impl.16.0.8.dex.jar;com-google-android-gms.play-services-analytics.16.0.8.dex.jar;com-google-android-gms.play-services-base.16.0.1.dex.jar;com-google-android-gms.play-services-basement.16.2.0.dex.jar;com-google-android-gms.play-services-gass.17.2.0.dex.jar;com-google-android-gms.play-services-identity.16.0.0.dex.jar;com-google-android-gms.play-services-maps.16.1.0.dex.jar;com-google-android-gms.play-services-measurement-base.16.4.0.dex.jar;com-google-android-gms.play-services-measurement-sdk-api.16.4.0.dex.jar;com-google-android-gms.play-services-stats.16.0.1.dex.jar;com-google-android-gms.play-services-tagmanager-v4-impl.16.0.8.dex.jar;com-google-android-gms.play-services-tasks.16.0.1.dex.jar;com-google-android-gms.play-services-wallet.16.0.1.dex.jar;com-google-firebase.firebase-analytics.16.4.0.dex.jar;com-google-firebase.firebase-common.16.1.0.dex.jar;com-google-firebase.firebase-iid-interop.16.0.1.dex.jar;com-google-firebase.firebase-iid.17.1.1.dex.jar;com-google-firebase.firebase-measurement-connector.17.0.1.dex.jar;com-google-firebase.firebase-messaging.17.5.0.dex.jar;fmx.dex.jar;google-play-billing.dex.jar;google-play-licensing.dex.jar</EnabledSysJars>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Android64)'!=''">
+        <DCC_UsePackage>DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;tethering;bindcompfmx;FmxTeeUI;fmx;FireDACIBDriver;dbexpress;IndyCore;dsnap;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;inet;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;FMXTee;soaprtl;DbxCommonDriver;xmlrtl;soapmidas;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;dbrtl;IndyProtocols;$(DCC_UsePackage)</DCC_UsePackage>
+        <Android_LauncherIcon36>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_36x36.png</Android_LauncherIcon36>
+        <Android_LauncherIcon48>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_48x48.png</Android_LauncherIcon48>
+        <Android_LauncherIcon72>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_72x72.png</Android_LauncherIcon72>
+        <Android_LauncherIcon96>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_96x96.png</Android_LauncherIcon96>
+        <Android_LauncherIcon144>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_144x144.png</Android_LauncherIcon144>
+        <Android_SplashImage426>$(BDS)\bin\Artwork\Android\FM_SplashImage_426x320.png</Android_SplashImage426>
+        <Android_SplashImage470>$(BDS)\bin\Artwork\Android\FM_SplashImage_470x320.png</Android_SplashImage470>
+        <Android_SplashImage640>$(BDS)\bin\Artwork\Android\FM_SplashImage_640x480.png</Android_SplashImage640>
+        <Android_SplashImage960>$(BDS)\bin\Artwork\Android\FM_SplashImage_960x720.png</Android_SplashImage960>
+        <Android_NotificationIcon24>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_24x24.png</Android_NotificationIcon24>
+        <Android_NotificationIcon36>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_36x36.png</Android_NotificationIcon36>
+        <Android_NotificationIcon48>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_48x48.png</Android_NotificationIcon48>
+        <Android_NotificationIcon72>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_72x72.png</Android_NotificationIcon72>
+        <Android_NotificationIcon96>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_96x96.png</Android_NotificationIcon96>
+        <EnabledSysJars>android-support-v4.dex.jar;cloud-messaging.dex.jar;com-google-android-gms.play-services-ads-base.17.2.0.dex.jar;com-google-android-gms.play-services-ads-identifier.16.0.0.dex.jar;com-google-android-gms.play-services-ads-lite.17.2.0.dex.jar;com-google-android-gms.play-services-ads.17.2.0.dex.jar;com-google-android-gms.play-services-analytics-impl.16.0.8.dex.jar;com-google-android-gms.play-services-analytics.16.0.8.dex.jar;com-google-android-gms.play-services-base.16.0.1.dex.jar;com-google-android-gms.play-services-basement.16.2.0.dex.jar;com-google-android-gms.play-services-gass.17.2.0.dex.jar;com-google-android-gms.play-services-identity.16.0.0.dex.jar;com-google-android-gms.play-services-maps.16.1.0.dex.jar;com-google-android-gms.play-services-measurement-base.16.4.0.dex.jar;com-google-android-gms.play-services-measurement-sdk-api.16.4.0.dex.jar;com-google-android-gms.play-services-stats.16.0.1.dex.jar;com-google-android-gms.play-services-tagmanager-v4-impl.16.0.8.dex.jar;com-google-android-gms.play-services-tasks.16.0.1.dex.jar;com-google-android-gms.play-services-wallet.16.0.1.dex.jar;com-google-firebase.firebase-analytics.16.4.0.dex.jar;com-google-firebase.firebase-common.16.1.0.dex.jar;com-google-firebase.firebase-iid-interop.16.0.1.dex.jar;com-google-firebase.firebase-iid.17.1.1.dex.jar;com-google-firebase.firebase-measurement-connector.17.0.1.dex.jar;com-google-firebase.firebase-messaging.17.5.0.dex.jar;fmx.dex.jar;google-play-billing.dex.jar;google-play-licensing.dex.jar</EnabledSysJars>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_iOSDevice64)'!=''">
+        <DCC_UsePackage>DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;tethering;bindcompfmx;TMSFMXPackPkgDXE13;FmxTeeUI;fmx;FireDACIBDriver;dbexpress;IndyCore;dsnap;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;inet;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;FMXTee;soaprtl;DbxCommonDriver;xmlrtl;soapmidas;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;dbrtl;IndyProtocols;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_iOSSimulator)'!=''">
+        <DCC_UsePackage>DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;tethering;bindcompfmx;FmxTeeUI;fmx;FireDACIBDriver;dbexpress;IndyCore;dsnap;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;inet;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;FMXTee;soaprtl;DbxCommonDriver;xmlrtl;soapmidas;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;dbrtl;IndyProtocols;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_OSX64)'!=''">
+        <DCC_UsePackage>DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;tethering;bindcompfmx;inetdb;FmxTeeUI;fmx;FireDACIBDriver;fmxdae;dbexpress;IndyCore;dsnap;FireDACCommon;RESTBackendComponents;soapserver;bindengine;DBXMySQLDriver;CloudService;FireDACMySQLDriver;FireDACCommonODBC;FireDACCommonDriver;inet;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;FireDACPgDriver;FMXTee;soaprtl;DbxCommonDriver;xmlrtl;soapmidas;fmxobj;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;dbrtl;IndyProtocols;inetdbxpress;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
+        <DCC_ConsoleTarget>true</DCC_ConsoleTarget>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Win32)'!=''">
+        <DCC_UsePackage>DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;vclactnband;vclFireDAC;FMXComponents;bindcompvclsmp;tethering;svnui;JvGlobus;FireDACADSDriver;JvPluginSystem;JvMM;PngComponentsD;vcltouch;JvBands;vcldb;bindcompfmx;svn;JvJans;JvNet;inetdb;JvAppFrm;TMSFMXPackPkgDXE13;FmxTeeUI;JvDotNetCtrls;TMSVCLUIPackPkgWizDXE13;fmx;FireDACIBDriver;fmxdae;vcledge;JvWizards;FlatButtonSet;dbexpress;IndyCore;TMSVCLUIPackPkgXlsDXE13;vclx;JvPageComps;dsnap;FireDACCommon;JvDB;RESTBackendComponents;VCLRESTComponents;soapserver;JclDeveloperTools;TMSVCLUIPackPkgDXE13;vclie;TMSVCLIWPkgDEDXE13;bindengine;DBXMySQLDriver;CloudService;JvCmp;FireDACMySQLDriver;JvHMI;FireDACCommonODBC;FireDACCommonDriver;FMXComponentEd;inet;TMSVCLUIPackPkgExDXE13;IndyIPCommon;bindcompdbx;JvCustom;vcl;IndyIPServer;JvXPCtrls;IndySystem;dsnapcon;TMSVCLIWPkgDXE13;FireDACMSAccDriver;fmxFireDAC;vclimg;TeeDB;FireDAC;Jcl;JvCore;JvCrypt;FireDACSqliteDriver;FireDACPgDriver;FMXTee;soaprtl;DbxCommonDriver;JvDlgs;JvRuntimeDesign;JvManagedThreads;Tee;xmlrtl;soapmidas;JvTimeFramework;fmxobj;vclwinx;rtl;DbxClientDriver;CustomIPTransport;vcldsnap;JvSystem;JvStdCtrls;bindcomp;appanalytics;IndyIPClient;bindcompvcl;TeeUI;JvDocking;dbxcds;VclSmp;JvPascalInterpreter;adortl;KernowSoftwareFMX;JclVcl;dsnapxml;dbrtl;IndyProtocols;inetdbxpress;JvControls;JvPrintPreview;JclContainers;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
+        <DCC_Namespace>Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
+        <BT_BuildType>Debug</BT_BuildType>
+        <VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
+        <VerInfo_Locale>1033</VerInfo_Locale>
+        <DCC_ConsoleTarget>true</DCC_ConsoleTarget>
+        <UWP_DelphiLogo44>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png</UWP_DelphiLogo44>
+        <UWP_DelphiLogo150>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png</UWP_DelphiLogo150>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Win64)'!=''">
+        <DCC_UsePackage>DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;vclactnband;vclFireDAC;bindcompvclsmp;tethering;FireDACADSDriver;PngComponentsD;vcltouch;vcldb;bindcompfmx;inetdb;FmxTeeUI;fmx;FireDACIBDriver;fmxdae;vcledge;FlatButtonSet;dbexpress;IndyCore;vclx;dsnap;FireDACCommon;RESTBackendComponents;VCLRESTComponents;soapserver;TMSVCLUIPackPkgDXE13;vclie;bindengine;DBXMySQLDriver;CloudService;FireDACMySQLDriver;FireDACCommonODBC;FireDACCommonDriver;inet;TMSVCLUIPackPkgExDXE13;IndyIPCommon;bindcompdbx;vcl;IndyIPServer;IndySystem;dsnapcon;TMSVCLIWPkgDXE13;FireDACMSAccDriver;fmxFireDAC;vclimg;TeeDB;FireDAC;FireDACSqliteDriver;FireDACPgDriver;FMXTee;soaprtl;DbxCommonDriver;Tee;xmlrtl;soapmidas;fmxobj;vclwinx;rtl;DbxClientDriver;CustomIPTransport;vcldsnap;bindcomp;appanalytics;IndyIPClient;bindcompvcl;TeeUI;dbxcds;VclSmp;adortl;dsnapxml;dbrtl;IndyProtocols;inetdbxpress;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
+        <DCC_ConsoleTarget>true</DCC_ConsoleTarget>
+        <UWP_DelphiLogo44>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png</UWP_DelphiLogo44>
+        <UWP_DelphiLogo150>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png</UWP_DelphiLogo150>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_1)'!=''">
+        <DCC_Define>DEBUG;$(DCC_Define)</DCC_Define>
+        <DCC_DebugDCUs>true</DCC_DebugDCUs>
+        <DCC_Optimize>false</DCC_Optimize>
+        <DCC_GenerateStackFrames>true</DCC_GenerateStackFrames>
+        <DCC_DebugInfoInExe>true</DCC_DebugInfoInExe>
+        <DCC_RemoteDebug>true</DCC_RemoteDebug>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_1_Win32)'!=''">
+        <DCC_RemoteDebug>false</DCC_RemoteDebug>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2)'!=''">
+        <DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
+        <DCC_Define>RELEASE;$(DCC_Define)</DCC_Define>
+        <DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo>
+        <DCC_DebugInformation>0</DCC_DebugInformation>
+    </PropertyGroup>
+    <ItemGroup>
+        <DelphiCompile Include="$(MainSource)">
+            <MainSource>MainSource</MainSource>
+        </DelphiCompile>
+        <BuildConfiguration Include="Release">
+            <Key>Cfg_2</Key>
+            <CfgParent>Base</CfgParent>
+        </BuildConfiguration>
+        <BuildConfiguration Include="Base">
+            <Key>Base</Key>
+        </BuildConfiguration>
+        <BuildConfiguration Include="Debug">
+            <Key>Cfg_1</Key>
+            <CfgParent>Base</CfgParent>
+        </BuildConfiguration>
+    </ItemGroup>
+    <ProjectExtensions>
+        <Borland.Personality>Delphi.Personality.12</Borland.Personality>
+        <Borland.ProjectType>Application</Borland.ProjectType>
+        <BorlandProject>
+            <Delphi.Personality>
+                <Source>
+                    <Source Name="MainSource">ObjectToJsonStream.dpr</Source>
+                </Source>
+            </Delphi.Personality>
+            <Deployment Version="3">
+                <DeployFile LocalName="$(BDS)\Redist\osx32\libcgunwind.1.0.dylib" Class="DependencyModule">
+                    <Platform Name="OSX32">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile LocalName="$(BDS)\Redist\iossimulator\libcgunwind.1.0.dylib" Class="DependencyModule">
+                    <Platform Name="iOSSimulator">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile LocalName="$(BDS)\Redist\iossimulator\libpcre.dylib" Class="DependencyModule">
+                    <Platform Name="iOSSimulator">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile LocalName="Win32\Debug\ObjectToJsonStream.exe" Configuration="Debug" Class="ProjectOutput">
+                    <Platform Name="Win32">
+                        <RemoteName>ObjectToJsonStream.exe</RemoteName>
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployClass Name="AdditionalDebugSymbols">
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidClassesDexFile">
+                    <Platform Name="Android">
+                        <RemoteDir>classes</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>classes</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidFileProvider">
+                    <Platform Name="Android">
+                        <RemoteDir>res\xml</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\xml</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidGDBServer">
+                    <Platform Name="Android">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidLibnativeArmeabiFile">
+                    <Platform Name="Android">
+                        <RemoteDir>library\lib\armeabi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\armeabi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidLibnativeArmeabiv7aFile">
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidLibnativeMipsFile">
+                    <Platform Name="Android">
+                        <RemoteDir>library\lib\mips</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\mips</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidServiceOutput">
+                    <Platform Name="Android">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\arm64-v8a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidServiceOutput_Android32">
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidSplashImageDef">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidSplashStyles">
+                    <Platform Name="Android">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidSplashStylesV21">
+                    <Platform Name="Android">
+                        <RemoteDir>res\values-v21</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\values-v21</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_Colors">
+                    <Platform Name="Android">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_DefaultAppIcon">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon144">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon36">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-ldpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-ldpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon48">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-mdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-mdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon72">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-hdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-hdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon96">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_NotificationIcon24">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-mdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-mdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_NotificationIcon36">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-hdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-hdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_NotificationIcon48">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_NotificationIcon72">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_NotificationIcon96">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xxxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xxxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_SplashImage426">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-small</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-small</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_SplashImage470">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-normal</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-normal</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_SplashImage640">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-large</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-large</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_SplashImage960">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xlarge</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xlarge</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_Strings">
+                    <Platform Name="Android">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="DebugSymbols">
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="DependencyFramework">
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.framework</Extensions>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.framework</Extensions>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="DependencyModule">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                        <Extensions>.dll;.bpl</Extensions>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Required="true" Name="DependencyPackage">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                        <Extensions>.bpl</Extensions>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="File">
+                    <Platform Name="Android">
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice32">
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\Resources\StartUp\</RemoteDir>
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\Resources\StartUp\</RemoteDir>
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iOS_AppStore1024">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_AppIcon152">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_AppIcon167">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_Launch2x">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_LaunchDark2x">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_Notification40">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_Setting58">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_SpotLight80">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_AppIcon120">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_AppIcon180">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch2x">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch3x">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_LaunchDark2x">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_LaunchDark3x">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Notification40">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Notification60">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Setting58">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Setting87">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Spotlight120">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Spotlight80">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectAndroidManifest">
+                    <Platform Name="Android">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectiOSDeviceDebug">
+                    <Platform Name="iOSDevice32">
+                        <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectiOSEntitlements">
+                    <Platform Name="iOSDevice32">
+                        <RemoteDir>..\</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectiOSInfoPList">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectiOSLaunchScreen">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen</RemoteDir>
+                        <Operation>64</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen</RemoteDir>
+                        <Operation>64</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectiOSResource">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectOSXDebug">
+                    <Platform Name="OSX64">
+                        <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectOSXEntitlements">
+                    <Platform Name="OSX32">
+                        <RemoteDir>..\</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>..\</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectOSXInfoPList">
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectOSXResource">
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\Resources</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\Resources</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Required="true" Name="ProjectOutput">
+                    <Platform Name="Android">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\arm64-v8a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Linux64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectOutput_Android32">
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectUWPManifest">
+                    <Platform Name="Win32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win64">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="UWP_DelphiLogo150">
+                    <Platform Name="Win32">
+                        <RemoteDir>Assets</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win64">
+                        <RemoteDir>Assets</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="UWP_DelphiLogo44">
+                    <Platform Name="Win32">
+                        <RemoteDir>Assets</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win64">
+                        <RemoteDir>Assets</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <ProjectRoot Platform="iOSDevice64" Name="$(PROJECTNAME).app"/>
+                <ProjectRoot Platform="Win64" Name="$(PROJECTNAME)"/>
+                <ProjectRoot Platform="iOSDevice32" Name="$(PROJECTNAME).app"/>
+                <ProjectRoot Platform="Linux64" Name="$(PROJECTNAME)"/>
+                <ProjectRoot Platform="Win32" Name="$(PROJECTNAME)"/>
+                <ProjectRoot Platform="OSX32" Name="$(PROJECTNAME).app"/>
+                <ProjectRoot Platform="Android" Name="$(PROJECTNAME)"/>
+                <ProjectRoot Platform="OSX64" Name="$(PROJECTNAME).app"/>
+                <ProjectRoot Platform="iOSSimulator" Name="$(PROJECTNAME).app"/>
+                <ProjectRoot Platform="Android64" Name="$(PROJECTNAME)"/>
+            </Deployment>
+            <Platforms>
+                <Platform value="Android">False</Platform>
+                <Platform value="Android64">False</Platform>
+                <Platform value="iOSDevice64">False</Platform>
+                <Platform value="iOSSimulator">False</Platform>
+                <Platform value="OSX64">False</Platform>
+                <Platform value="Win32">True</Platform>
+                <Platform value="Win64">False</Platform>
+            </Platforms>
+        </BorlandProject>
+        <ProjectFileVersion>12</ProjectFileVersion>
+    </ProjectExtensions>
+    <Import Project="$(BDS)\Bin\CodeGear.Delphi.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')"/>
+    <Import Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj" Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')"/>
+    <Import Project="$(MSBuildProjectName).deployproj" Condition="Exists('$(MSBuildProjectName).deployproj')"/>
+</Project>

+ 2 - 2
samples/delphi/QuickOptions/Optionsdemo.dpr

@@ -63,7 +63,7 @@ type
   end;
 
 var
-  Options : TOptionsContainer;
+  Options : TFileOptionsContainer;
   LoggingOptions : TLoggingOptions;
   GlobalOptions : TGlobalOptions;
   UIOptions : TUIOptions;
@@ -84,7 +84,7 @@ end;
 begin
   try
     ReportMemoryLeaksOnShutdown := True;
-    Options := TOptionsContainer.Create('.\options.conf',TJsonOptionsSerializer.Create,True);
+    Options := TFileOptionsContainer.Create(TJsonOptionsSerializer.Create('.\options.conf'),True);
     Options.OnFileModified := procedure
                               begin
                                 cout('Detected config file modification!',etWarning);

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 8 - 27
samples/delphi/QuickOptions/Optionsdemo.dproj


+ 151 - 1
samples/delphi/QuickParameters/Parameters.dproj

@@ -1,7 +1,7 @@
 <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
     <PropertyGroup>
         <ProjectGuid>{720C5968-A995-48C1-B4EC-2DC16A29D2EF}</ProjectGuid>
-        <ProjectVersion>19.0</ProjectVersion>
+        <ProjectVersion>19.2</ProjectVersion>
         <FrameworkType>None</FrameworkType>
         <MainSource>Parameters.dpr</MainSource>
         <Base>True</Base>
@@ -92,6 +92,7 @@
         <Android_NotificationIcon72>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_72x72.png</Android_NotificationIcon72>
         <Android_NotificationIcon96>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_96x96.png</Android_NotificationIcon96>
         <EnabledSysJars>android-support-v4.dex.jar;cloud-messaging.dex.jar;com-google-android-gms.play-services-ads-base.17.2.0.dex.jar;com-google-android-gms.play-services-ads-identifier.16.0.0.dex.jar;com-google-android-gms.play-services-ads-lite.17.2.0.dex.jar;com-google-android-gms.play-services-ads.17.2.0.dex.jar;com-google-android-gms.play-services-analytics-impl.16.0.8.dex.jar;com-google-android-gms.play-services-analytics.16.0.8.dex.jar;com-google-android-gms.play-services-base.16.0.1.dex.jar;com-google-android-gms.play-services-basement.16.2.0.dex.jar;com-google-android-gms.play-services-gass.17.2.0.dex.jar;com-google-android-gms.play-services-identity.16.0.0.dex.jar;com-google-android-gms.play-services-maps.16.1.0.dex.jar;com-google-android-gms.play-services-measurement-base.16.4.0.dex.jar;com-google-android-gms.play-services-measurement-sdk-api.16.4.0.dex.jar;com-google-android-gms.play-services-stats.16.0.1.dex.jar;com-google-android-gms.play-services-tagmanager-v4-impl.16.0.8.dex.jar;com-google-android-gms.play-services-tasks.16.0.1.dex.jar;com-google-android-gms.play-services-wallet.16.0.1.dex.jar;com-google-firebase.firebase-analytics.16.4.0.dex.jar;com-google-firebase.firebase-common.16.1.0.dex.jar;com-google-firebase.firebase-iid-interop.16.0.1.dex.jar;com-google-firebase.firebase-iid.17.1.1.dex.jar;com-google-firebase.firebase-measurement-connector.17.0.1.dex.jar;com-google-firebase.firebase-messaging.17.5.0.dex.jar;fmx.dex.jar;google-play-billing.dex.jar;google-play-licensing.dex.jar</EnabledSysJars>
+        <Android_LauncherIcon192>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_192x192.png</Android_LauncherIcon192>
     </PropertyGroup>
     <PropertyGroup Condition="'$(Base_Android64)'!=''">
         <DCC_UsePackage>DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;tethering;bindcompfmx;FmxTeeUI;FireDACIBDriver;fmx;dbexpress;IndyCore;dsnap;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;inet;bindcompdbx;IndyIPCommon;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;ibmonitor;FMXTee;soaprtl;DbxCommonDriver;ibxpress;xmlrtl;soapmidas;ibxbindings;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;dbrtl;IndyProtocols;$(DCC_UsePackage)</DCC_UsePackage>
@@ -110,9 +111,11 @@
         <Android_NotificationIcon72>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_72x72.png</Android_NotificationIcon72>
         <Android_NotificationIcon96>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_96x96.png</Android_NotificationIcon96>
         <EnabledSysJars>android-support-v4.dex.jar;cloud-messaging.dex.jar;com-google-android-gms.play-services-ads-base.17.2.0.dex.jar;com-google-android-gms.play-services-ads-identifier.16.0.0.dex.jar;com-google-android-gms.play-services-ads-lite.17.2.0.dex.jar;com-google-android-gms.play-services-ads.17.2.0.dex.jar;com-google-android-gms.play-services-analytics-impl.16.0.8.dex.jar;com-google-android-gms.play-services-analytics.16.0.8.dex.jar;com-google-android-gms.play-services-base.16.0.1.dex.jar;com-google-android-gms.play-services-basement.16.2.0.dex.jar;com-google-android-gms.play-services-gass.17.2.0.dex.jar;com-google-android-gms.play-services-identity.16.0.0.dex.jar;com-google-android-gms.play-services-maps.16.1.0.dex.jar;com-google-android-gms.play-services-measurement-base.16.4.0.dex.jar;com-google-android-gms.play-services-measurement-sdk-api.16.4.0.dex.jar;com-google-android-gms.play-services-stats.16.0.1.dex.jar;com-google-android-gms.play-services-tagmanager-v4-impl.16.0.8.dex.jar;com-google-android-gms.play-services-tasks.16.0.1.dex.jar;com-google-android-gms.play-services-wallet.16.0.1.dex.jar;com-google-firebase.firebase-analytics.16.4.0.dex.jar;com-google-firebase.firebase-common.16.1.0.dex.jar;com-google-firebase.firebase-iid-interop.16.0.1.dex.jar;com-google-firebase.firebase-iid.17.1.1.dex.jar;com-google-firebase.firebase-measurement-connector.17.0.1.dex.jar;com-google-firebase.firebase-messaging.17.5.0.dex.jar;fmx.dex.jar;google-play-billing.dex.jar;google-play-licensing.dex.jar</EnabledSysJars>
+        <Android_LauncherIcon192>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_192x192.png</Android_LauncherIcon192>
     </PropertyGroup>
     <PropertyGroup Condition="'$(Base_iOSDevice64)'!=''">
         <DCC_UsePackage>DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;tethering;bindcompfmx;FmxTeeUI;FireDACIBDriver;fmx;dbexpress;IndyCore;dsnap;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;inet;bindcompdbx;IndyIPCommon;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;ibmonitor;FMXTee;soaprtl;DbxCommonDriver;ibxpress;xmlrtl;soapmidas;ibxbindings;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;dbrtl;IndyProtocols;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
+        <iOS_AppStore1024>$(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_1024x1024.png</iOS_AppStore1024>
     </PropertyGroup>
     <PropertyGroup Condition="'$(Base_iOSSimulator)'!=''">
         <DCC_UsePackage>DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;tethering;bindcompfmx;FmxTeeUI;FireDACIBDriver;fmx;dbexpress;IndyCore;dsnap;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;inet;bindcompdbx;IndyIPCommon;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;ibmonitor;FMXTee;soaprtl;DbxCommonDriver;ibxpress;xmlrtl;soapmidas;ibxbindings;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;dbrtl;IndyProtocols;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
@@ -351,6 +354,16 @@
                         <Operation>1</Operation>
                     </Platform>
                 </DeployClass>
+                <DeployClass Name="Android_LauncherIcon192">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xxxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xxxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
                 <DeployClass Name="Android_LauncherIcon36">
                     <Platform Name="Android">
                         <RemoteDir>res\drawable-ldpi</RemoteDir>
@@ -602,6 +615,32 @@
                         <Operation>0</Operation>
                     </Platform>
                 </DeployClass>
+                <DeployClass Name="iOS_AppStore1024">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_AppIcon152">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_AppIcon167">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
                 <DeployClass Name="iPad_Launch1024x768">
                     <Platform Name="iOSDevice32">
                         <Operation>1</Operation>
@@ -732,6 +771,56 @@
                         <Operation>1</Operation>
                     </Platform>
                 </DeployClass>
+                <DeployClass Name="iPad_Notification40">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_Setting58">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_SpotLight80">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_AppIcon120">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_AppIcon180">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
                 <DeployClass Name="iPhone_Launch1125">
                     <Platform Name="iOSDevice32">
                         <Operation>1</Operation>
@@ -926,6 +1015,66 @@
                         <Operation>1</Operation>
                     </Platform>
                 </DeployClass>
+                <DeployClass Name="iPhone_Notification40">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Notification60">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Setting58">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Setting87">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Spotlight120">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Spotlight80">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
                 <DeployClass Name="ProjectAndroidManifest">
                     <Platform Name="Android">
                         <Operation>1</Operation>
@@ -1113,6 +1262,7 @@
                 <Platform value="Android64">False</Platform>
                 <Platform value="iOSDevice64">False</Platform>
                 <Platform value="iOSSimulator">False</Platform>
+                <Platform value="Linux64">False</Platform>
                 <Platform value="OSX64">False</Platform>
                 <Platform value="Win32">True</Platform>
                 <Platform value="Win64">False</Platform>

+ 19 - 10
samples/delphi/QuickSMTP/SendEmail.dpr

@@ -13,16 +13,25 @@ var
   smtp : TSMTP;
 begin
   try
-    smtp := TSMTP.Create('mail.mydomain.com',25,True);
-    smtp.Username := '[email protected]';
-    smtp.Password := '1234';
-    smtp.SendEmail('[email protected]',
-                   'Test email',
-                   'A test message',
-                   '[email protected]',
-                   '[email protected]',
-                   '[email protected]',
-                   'This is the body message');
+    ReportMemoryLeaksOnShutdown := True;
+    smtp := TSMTP.Create('mail.domain.com',25,False);
+    try
+      smtp.Username := '[email protected]';
+      smtp.Password := '';
+      smtp.Mail.AddAttachment('output2.png','d:\output.png');
+      //smtp.Mail.AddAttachment('dell.gif','d:\dell.gif');
+      //smtp.Mail.AddAttachment('config.json','d:\config.json');
+      //smtp.Mail.Attachments.Add('d:\output.png');
+      //smtp.Mail.Attachments.Add('d:\config.json');
+      smtp.Mail.SenderName := 'Attachment Test';
+      smtp.Mail.From := '[email protected]';
+      smtp.Mail.Recipient := '[email protected]';
+      smtp.Mail.Subject := 'test adjuntos';
+      smtp.Mail.Body := 'Ver adjuntos';
+      smtp.SendMail;
+    finally
+      smtp.Free;
+    end;
     cout('Press <ENTER> to Exit',ccYellow);
     ConsoleWaitForEnterKey;
   except

+ 362 - 16
samples/delphi/QuickSMTP/SendEmail.dproj

@@ -1,7 +1,7 @@
 <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
     <PropertyGroup>
         <ProjectGuid>{3377CABB-5BC2-466B-BF70-B61D6042B649}</ProjectGuid>
-        <ProjectVersion>18.7</ProjectVersion>
+        <ProjectVersion>19.1</ProjectVersion>
         <FrameworkType>None</FrameworkType>
         <MainSource>SendEmail.dpr</MainSource>
         <Base>True</Base>
@@ -18,8 +18,8 @@
         <CfgParent>Base</CfgParent>
         <Base>true</Base>
     </PropertyGroup>
-    <PropertyGroup Condition="('$(Platform)'=='iOSDevice32' and '$(Base)'=='true') or '$(Base_iOSDevice32)'!=''">
-        <Base_iOSDevice32>true</Base_iOSDevice32>
+    <PropertyGroup Condition="('$(Platform)'=='Android64' and '$(Base)'=='true') or '$(Base_Android64)'!=''">
+        <Base_Android64>true</Base_Android64>
         <CfgParent>Base</CfgParent>
         <Base>true</Base>
     </PropertyGroup>
@@ -33,11 +33,6 @@
         <CfgParent>Base</CfgParent>
         <Base>true</Base>
     </PropertyGroup>
-    <PropertyGroup Condition="('$(Platform)'=='OSX32' and '$(Base)'=='true') or '$(Base_OSX32)'!=''">
-        <Base_OSX32>true</Base_OSX32>
-        <CfgParent>Base</CfgParent>
-        <Base>true</Base>
-    </PropertyGroup>
     <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''">
         <Base_Win32>true</Base_Win32>
         <CfgParent>Base</CfgParent>
@@ -93,19 +88,36 @@
         <Android_NotificationIcon96>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_96x96.png</Android_NotificationIcon96>
         <EnabledSysJars>android-support-v4.dex.jar;cloud-messaging.dex.jar;com-google-android-gms.play-services-ads-base.17.2.0.dex.jar;com-google-android-gms.play-services-ads-identifier.16.0.0.dex.jar;com-google-android-gms.play-services-ads-lite.17.2.0.dex.jar;com-google-android-gms.play-services-ads.17.2.0.dex.jar;com-google-android-gms.play-services-analytics-impl.16.0.8.dex.jar;com-google-android-gms.play-services-analytics.16.0.8.dex.jar;com-google-android-gms.play-services-base.16.0.1.dex.jar;com-google-android-gms.play-services-basement.16.2.0.dex.jar;com-google-android-gms.play-services-gass.17.2.0.dex.jar;com-google-android-gms.play-services-identity.16.0.0.dex.jar;com-google-android-gms.play-services-maps.16.1.0.dex.jar;com-google-android-gms.play-services-measurement-base.16.4.0.dex.jar;com-google-android-gms.play-services-measurement-sdk-api.16.4.0.dex.jar;com-google-android-gms.play-services-stats.16.0.1.dex.jar;com-google-android-gms.play-services-tagmanager-v4-impl.16.0.8.dex.jar;com-google-android-gms.play-services-tasks.16.0.1.dex.jar;com-google-android-gms.play-services-wallet.16.0.1.dex.jar;com-google-firebase.firebase-analytics.16.4.0.dex.jar;com-google-firebase.firebase-common.16.1.0.dex.jar;com-google-firebase.firebase-iid-interop.16.0.1.dex.jar;com-google-firebase.firebase-iid.17.1.1.dex.jar;com-google-firebase.firebase-measurement-connector.17.0.1.dex.jar;com-google-firebase.firebase-messaging.17.5.0.dex.jar;fmx.dex.jar;google-play-billing.dex.jar;google-play-licensing.dex.jar</EnabledSysJars>
     </PropertyGroup>
-    <PropertyGroup Condition="'$(Base_iOSDevice32)'!=''">
-        <DCC_UsePackage>DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;emsclientfiredac;DataSnapFireDAC;tethering;bindcompfmx;FmxTeeUI;FireDACIBDriver;fmx;RadiantShapesFmx;FireDACDBXDriver;dbexpress;IndyCore;dsnap;DataSnapCommon;emsclient;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;DataSnapClient;inet;bindcompdbx;IndyIPCommon;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;ibmonitor;FMXTee;soaprtl;DbxCommonDriver;ibxpress;xmlrtl;soapmidas;DataSnapNativeClient;ibxbindings;rtl;DbxClientDriver;FireDACDSDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;RadiantShapesFmx_Design;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
+    <PropertyGroup Condition="'$(Base_Android64)'!=''">
+        <VerInfo_Keys>package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=</VerInfo_Keys>
+        <BT_BuildType>Debug</BT_BuildType>
+        <Base_Android>true</Base_Android>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+        <DCC_UsePackage>DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;emsclientfiredac;DataSnapFireDAC;tethering;bindcompfmx;FmxTeeUI;FireDACIBDriver;fmx;RadiantShapesFmx;FlatButtonSet;FireDACDBXDriver;dbexpress;IndyCore;dsnap;DataSnapCommon;emsclient;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;DataSnapClient;inet;bindcompdbx;IndyIPCommon;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;ibmonitor;FMXTee;soaprtl;DbxCommonDriver;ibxpress;xmlrtl;soapmidas;DataSnapNativeClient;ibxbindings;rtl;DbxClientDriver;FireDACDSDriver;CustomIPTransport;bindcomp;CoolTrayIcon_D210_XE7;IndyIPClient;dbxcds;RadiantShapesFmx_Design;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;$(DCC_UsePackage);$(DCC_UsePackage)</DCC_UsePackage>
+        <Android_LauncherIcon36>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_36x36.png</Android_LauncherIcon36>
+        <Android_LauncherIcon48>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_48x48.png</Android_LauncherIcon48>
+        <Android_LauncherIcon72>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_72x72.png</Android_LauncherIcon72>
+        <Android_LauncherIcon96>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_96x96.png</Android_LauncherIcon96>
+        <Android_LauncherIcon144>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_144x144.png</Android_LauncherIcon144>
+        <Android_SplashImage426>$(BDS)\bin\Artwork\Android\FM_SplashImage_426x320.png</Android_SplashImage426>
+        <Android_SplashImage470>$(BDS)\bin\Artwork\Android\FM_SplashImage_470x320.png</Android_SplashImage470>
+        <Android_SplashImage640>$(BDS)\bin\Artwork\Android\FM_SplashImage_640x480.png</Android_SplashImage640>
+        <Android_SplashImage960>$(BDS)\bin\Artwork\Android\FM_SplashImage_960x720.png</Android_SplashImage960>
+        <Android_NotificationIcon24>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_24x24.png</Android_NotificationIcon24>
+        <Android_NotificationIcon36>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_36x36.png</Android_NotificationIcon36>
+        <Android_NotificationIcon48>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_48x48.png</Android_NotificationIcon48>
+        <Android_NotificationIcon72>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_72x72.png</Android_NotificationIcon72>
+        <Android_NotificationIcon96>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_96x96.png</Android_NotificationIcon96>
+        <EnabledSysJars>android-support-v4.dex.jar;cloud-messaging.dex.jar;com-google-android-gms.play-services-ads-base.17.2.0.dex.jar;com-google-android-gms.play-services-ads-identifier.16.0.0.dex.jar;com-google-android-gms.play-services-ads-lite.17.2.0.dex.jar;com-google-android-gms.play-services-ads.17.2.0.dex.jar;com-google-android-gms.play-services-analytics-impl.16.0.8.dex.jar;com-google-android-gms.play-services-analytics.16.0.8.dex.jar;com-google-android-gms.play-services-base.16.0.1.dex.jar;com-google-android-gms.play-services-basement.16.2.0.dex.jar;com-google-android-gms.play-services-gass.17.2.0.dex.jar;com-google-android-gms.play-services-identity.16.0.0.dex.jar;com-google-android-gms.play-services-maps.16.1.0.dex.jar;com-google-android-gms.play-services-measurement-base.16.4.0.dex.jar;com-google-android-gms.play-services-measurement-sdk-api.16.4.0.dex.jar;com-google-android-gms.play-services-stats.16.0.1.dex.jar;com-google-android-gms.play-services-tagmanager-v4-impl.16.0.8.dex.jar;com-google-android-gms.play-services-tasks.16.0.1.dex.jar;com-google-android-gms.play-services-wallet.16.0.1.dex.jar;com-google-firebase.firebase-analytics.16.4.0.dex.jar;com-google-firebase.firebase-common.16.1.0.dex.jar;com-google-firebase.firebase-iid-interop.16.0.1.dex.jar;com-google-firebase.firebase-iid.17.1.1.dex.jar;com-google-firebase.firebase-measurement-connector.17.0.1.dex.jar;com-google-firebase.firebase-messaging.17.5.0.dex.jar;fmx.dex.jar;google-play-billing.dex.jar;google-play-licensing.dex.jar</EnabledSysJars>
     </PropertyGroup>
     <PropertyGroup Condition="'$(Base_iOSDevice64)'!=''">
         <DCC_UsePackage>DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;emsclientfiredac;DataSnapFireDAC;tethering;bindcompfmx;FmxTeeUI;FireDACIBDriver;fmx;RadiantShapesFmx;FireDACDBXDriver;dbexpress;IndyCore;dsnap;DataSnapCommon;emsclient;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;DataSnapClient;inet;bindcompdbx;IndyIPCommon;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;ibmonitor;FMXTee;soaprtl;DbxCommonDriver;ibxpress;xmlrtl;soapmidas;DataSnapNativeClient;ibxbindings;rtl;DbxClientDriver;FireDACDSDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;TMSFMXPackPkgDXE12;RadiantShapesFmx_Design;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
+        <iOS_AppStore1024>$(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_1024x1024.png</iOS_AppStore1024>
     </PropertyGroup>
     <PropertyGroup Condition="'$(Base_iOSSimulator)'!=''">
         <DCC_UsePackage>DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;emsclientfiredac;DataSnapFireDAC;tethering;bindcompfmx;FmxTeeUI;FireDACIBDriver;fmx;RadiantShapesFmx;FireDACDBXDriver;dbexpress;IndyCore;dsnap;DataSnapCommon;emsclient;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;DataSnapClient;inet;bindcompdbx;IndyIPCommon;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;ibmonitor;FMXTee;soaprtl;DbxCommonDriver;ibxpress;xmlrtl;soapmidas;DataSnapNativeClient;ibxbindings;rtl;DbxClientDriver;FireDACDSDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;RadiantShapesFmx_Design;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
     </PropertyGroup>
-    <PropertyGroup Condition="'$(Base_OSX32)'!=''">
-        <DCC_UsePackage>DBXSqliteDriver;RESTComponents;DataSnapServerMidas;DBXInterBaseDriver;emsclientfiredac;DataSnapFireDAC;tethering;FireDACMSSQLDriver;bindcompfmx;DBXOracleDriver;inetdb;FmxTeeUI;FireDACIBDriver;fmx;fmxdae;RadiantShapesFmx;FireDACDBXDriver;dbexpress;IndyCore;dsnap;DataSnapCommon;emsclient;FireDACCommon;RESTBackendComponents;soapserver;bindengine;DBXMySQLDriver;FireDACOracleDriver;CloudService;FireDACMySQLDriver;DBXFirebirdDriver;FireDACCommonODBC;FireDACCommonDriver;DataSnapClient;inet;bindcompdbx;IndyIPCommon;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;FireDACPgDriver;ibmonitor;FireDACASADriver;FireDACTDataDriver;FMXTee;soaprtl;DbxCommonDriver;ibxpress;DataSnapServer;xmlrtl;soapmidas;DataSnapNativeClient;fmxobj;ibxbindings;rtl;DbxClientDriver;FireDACDSDriver;DBXSybaseASADriver;CustomIPTransport;bindcomp;DBXInformixDriver;IndyIPClient;dbxcds;FireDACODBCDriver;DataSnapIndy10ServerTransport;RadiantShapesFmx_Design;dsnapxml;DataSnapProviderClient;dbrtl;inetdbxpress;FireDACMongoDBDriver;IndyProtocols;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
-        <DCC_ConsoleTarget>true</DCC_ConsoleTarget>
-    </PropertyGroup>
     <PropertyGroup Condition="'$(Base_Win32)'!=''">
         <DCC_UsePackage>DBXSqliteDriver;RESTComponents;DataSnapServerMidas;DBXDb2Driver;DBXInterBaseDriver;UbuntuProgressPackage;vclactnband;vclFireDAC;emsclientfiredac;DataSnapFireDAC;svnui;tethering;JvGlobus;FireDACADSDriver;JvPluginSystem;tmswizdXE12;DBXMSSQLDriver;JvMM;DatasnapConnectorsFreePascal;FireDACMSSQLDriver;vcltouch;JvBands;vcldb;bindcompfmx;svn;JvJans;DBXOracleDriver;JvNet;inetdb;JvAppFrm;FmxTeeUI;emsedge;JvDotNetCtrls;FireDACIBDriver;fmx;fmxdae;RadiantShapesFmx;vclib;FlatButtonSet;JvWizards;FireDACDBXDriver;dbexpress;IndyCore;vclx;JvPageComps;dsnap;DataSnapCommon;emsclient;FireDACCommon;JvDB;RESTBackendComponents;DataSnapConnectors;VCLRESTComponents;soapserver;JclDeveloperTools;vclie;bindengine;DBXMySQLDriver;FireDACOracleDriver;CloudService;FireDACMySQLDriver;DBXFirebirdDriver;JvCmp;JvHMI;FireDACCommonODBC;FireDACCommonDriver;DataSnapClient;inet;bindcompdbx;IndyIPCommon;GR32_D;JvCustom;vcl;IndyIPServer;DBXSybaseASEDriver;JvXPCtrls;PngComponents;IndySystem;FireDACDb2Driver;dsnapcon;tmsxlsdXE12;FireDACMSAccDriver;fmxFireDAC;FireDACInfxDriver;vclimg;TeeDB;FireDAC;Jcl;JvCore;emshosting;JvCrypt;FireDACSqliteDriver;FireDACPgDriver;ibmonitor;FireDACASADriver;tmsdXE12;FireDACTDataDriver;DBXOdbcDriver;FMXTee;soaprtl;DbxCommonDriver;JvDlgs;JvRuntimeDesign;ibxpress;Tee;JvManagedThreads;DataSnapServer;xmlrtl;soapmidas;DataSnapNativeClient;fmxobj;vclwinx;ibxbindings;rtl;emsserverresource;DbxClientDriver;FireDACDSDriver;DBXSybaseASADriver;GR32_R;CustomIPTransport;vcldsnap;JvTimeFramework;JvSystem;JvStdCtrls;tmsexdXE12;bindcomp;appanalytics;CoolTrayIcon_D210_XE7;DBXInformixDriver;IndyIPClient;bindcompvcl;TeeUI;JvDocking;dbxcds;VclSmp;KernowSoftwareFMX;adortl;FireDACODBCDriver;JvPascalInterpreter;TMSFMXPackPkgDXE12;JclVcl;DataSnapIndy10ServerTransport;RadiantShapesFmx_Design;dsnapxml;DataSnapProviderClient;dbrtl;inetdbxpress;FireDACMongoDBDriver;IndyProtocols;JvControls;JvPrintPreview;Analog_XE7;JclContainers;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
         <DCC_Namespace>Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
@@ -203,12 +215,20 @@
                         <RemoteDir>classes</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>classes</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="AndroidFileProvider">
                     <Platform Name="Android">
                         <RemoteDir>res\xml</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\xml</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="AndroidGDBServer">
                     <Platform Name="Android">
@@ -221,138 +241,242 @@
                         <RemoteDir>library\lib\armeabi</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\armeabi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidLibnativeArmeabiv7aFile">
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="AndroidLibnativeMipsFile">
                     <Platform Name="Android">
                         <RemoteDir>library\lib\mips</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\mips</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="AndroidServiceOutput">
                     <Platform Name="Android">
                         <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\arm64-v8a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidServiceOutput_Android32">
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="AndroidSplashImageDef">
                     <Platform Name="Android">
                         <RemoteDir>res\drawable</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="AndroidSplashStyles">
                     <Platform Name="Android">
                         <RemoteDir>res\values</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="AndroidSplashStylesV21">
                     <Platform Name="Android">
                         <RemoteDir>res\values-v21</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\values-v21</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="Android_Colors">
                     <Platform Name="Android">
                         <RemoteDir>res\values</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="Android_DefaultAppIcon">
                     <Platform Name="Android">
                         <RemoteDir>res\drawable</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="Android_LauncherIcon144">
                     <Platform Name="Android">
                         <RemoteDir>res\drawable-xxhdpi</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="Android_LauncherIcon36">
                     <Platform Name="Android">
                         <RemoteDir>res\drawable-ldpi</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-ldpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="Android_LauncherIcon48">
                     <Platform Name="Android">
                         <RemoteDir>res\drawable-mdpi</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-mdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="Android_LauncherIcon72">
                     <Platform Name="Android">
                         <RemoteDir>res\drawable-hdpi</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-hdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="Android_LauncherIcon96">
                     <Platform Name="Android">
                         <RemoteDir>res\drawable-xhdpi</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="Android_NotificationIcon24">
                     <Platform Name="Android">
                         <RemoteDir>res\drawable-mdpi</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-mdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="Android_NotificationIcon36">
                     <Platform Name="Android">
                         <RemoteDir>res\drawable-hdpi</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-hdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="Android_NotificationIcon48">
                     <Platform Name="Android">
                         <RemoteDir>res\drawable-xhdpi</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="Android_NotificationIcon72">
                     <Platform Name="Android">
                         <RemoteDir>res\drawable-xxhdpi</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="Android_NotificationIcon96">
                     <Platform Name="Android">
                         <RemoteDir>res\drawable-xxxhdpi</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xxxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="Android_SplashImage426">
                     <Platform Name="Android">
                         <RemoteDir>res\drawable-small</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-small</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="Android_SplashImage470">
                     <Platform Name="Android">
                         <RemoteDir>res\drawable-normal</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-normal</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="Android_SplashImage640">
                     <Platform Name="Android">
                         <RemoteDir>res\drawable-large</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-large</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="Android_SplashImage960">
                     <Platform Name="Android">
                         <RemoteDir>res\drawable-xlarge</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xlarge</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="Android_Strings">
                     <Platform Name="Android">
                         <RemoteDir>res\values</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="DebugSymbols">
                     <Platform Name="iOSSimulator">
@@ -441,6 +565,9 @@
                     <Platform Name="Android">
                         <Operation>0</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <Operation>0</Operation>
+                    </Platform>
                     <Platform Name="iOSDevice32">
                         <Operation>0</Operation>
                     </Platform>
@@ -462,6 +589,32 @@
                         <Operation>0</Operation>
                     </Platform>
                 </DeployClass>
+                <DeployClass Name="iOS_AppStore1024">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_AppIcon152">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_AppIcon167">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
                 <DeployClass Name="iPad_Launch1024x768">
                     <Platform Name="iOSDevice32">
                         <Operation>1</Operation>
@@ -561,6 +714,16 @@
                         <Operation>1</Operation>
                     </Platform>
                 </DeployClass>
+                <DeployClass Name="iPad_Launch2x">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
                 <DeployClass Name="iPad_Launch768x1024">
                     <Platform Name="iOSDevice32">
                         <Operation>1</Operation>
@@ -572,6 +735,66 @@
                         <Operation>1</Operation>
                     </Platform>
                 </DeployClass>
+                <DeployClass Name="iPad_LaunchDark2x">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_Notification40">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_Setting58">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_SpotLight80">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_AppIcon120">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_AppIcon180">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
                 <DeployClass Name="iPhone_Launch1125">
                     <Platform Name="iOSDevice32">
                         <Operation>1</Operation>
@@ -671,6 +894,16 @@
                         <Operation>1</Operation>
                     </Platform>
                 </DeployClass>
+                <DeployClass Name="iPhone_Launch2x">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
                 <DeployClass Name="iPhone_Launch320">
                     <Platform Name="iOSDevice32">
                         <Operation>1</Operation>
@@ -682,6 +915,16 @@
                         <Operation>1</Operation>
                     </Platform>
                 </DeployClass>
+                <DeployClass Name="iPhone_Launch3x">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
                 <DeployClass Name="iPhone_Launch640">
                     <Platform Name="iOSDevice32">
                         <Operation>1</Operation>
@@ -726,10 +969,93 @@
                         <Operation>1</Operation>
                     </Platform>
                 </DeployClass>
+                <DeployClass Name="iPhone_LaunchDark2x">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_LaunchDark3x">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Notification40">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Notification60">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Setting58">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Setting87">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Spotlight120">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Spotlight80">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
                 <DeployClass Name="ProjectAndroidManifest">
                     <Platform Name="Android">
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="ProjectiOSDeviceDebug">
                     <Platform Name="iOSDevice32">
@@ -770,6 +1096,16 @@
                         <Operation>1</Operation>
                     </Platform>
                 </DeployClass>
+                <DeployClass Name="ProjectiOSLaunchScreen">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen</RemoteDir>
+                        <Operation>64</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen</RemoteDir>
+                        <Operation>64</Operation>
+                    </Platform>
+                </DeployClass>
                 <DeployClass Name="ProjectiOSResource">
                     <Platform Name="iOSDevice32">
                         <Operation>1</Operation>
@@ -822,6 +1158,10 @@
                         <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\arm64-v8a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                     <Platform Name="iOSDevice32">
                         <Operation>1</Operation>
                     </Platform>
@@ -846,6 +1186,12 @@
                         <Operation>0</Operation>
                     </Platform>
                 </DeployClass>
+                <DeployClass Name="ProjectOutput_Android32">
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
                 <DeployClass Name="ProjectUWPManifest">
                     <Platform Name="Win32">
                         <Operation>1</Operation>
@@ -883,13 +1229,13 @@
                 <ProjectRoot Platform="Android" Name="$(PROJECTNAME)"/>
                 <ProjectRoot Platform="OSX64" Name="$(PROJECTNAME).app"/>
                 <ProjectRoot Platform="iOSSimulator" Name="$(PROJECTNAME).app"/>
+                <ProjectRoot Platform="Android64" Name="$(PROJECTNAME)"/>
             </Deployment>
             <Platforms>
                 <Platform value="Android">False</Platform>
-                <Platform value="iOSDevice32">False</Platform>
+                <Platform value="Android64">False</Platform>
                 <Platform value="iOSDevice64">False</Platform>
                 <Platform value="iOSSimulator">False</Platform>
-                <Platform value="OSX32">False</Platform>
                 <Platform value="Win32">True</Platform>
                 <Platform value="Win64">False</Platform>
             </Platforms>

Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio