Browse Source

Merge branch 'refs/heads/develop'

Exilon 5 years ago
parent
commit
733da5cd98
64 changed files with 12809 additions and 95 deletions
  1. 121 2
      Quick.Arrays.pas
  2. 19 2
      Quick.AutoMapper.pas
  3. 72 3
      Quick.Azure.pas
  4. 67 0
      Quick.Cache.Intf.pas
  5. 31 0
      Quick.CloudStorage.Provider.Amazon.pas
  6. 161 2
      Quick.CloudStorage.Provider.Azure.pas
  7. 31 0
      Quick.CloudStorage.pas
  8. 360 15
      Quick.Commons.pas
  9. 141 0
      Quick.Compression.LZO.pas
  10. 311 0
      Quick.HttpServer.Request.pas
  11. 190 0
      Quick.HttpServer.Response.pas
  12. 562 0
      Quick.HttpServer.Types.pas
  13. 318 0
      Quick.HttpServer.pas
  14. 570 0
      Quick.IOC.pas
  15. 193 28
      Quick.Json.Serializer.pas
  16. 62 0
      Quick.MemoryCache.Compressor.GZip.pas
  17. 76 0
      Quick.MemoryCache.Compressor.LZO.pas
  18. 107 0
      Quick.MemoryCache.Serializer.Json.pas
  19. 77 0
      Quick.MemoryCache.Types.pas
  20. 764 0
      Quick.MemoryCache.pas
  21. 124 0
      Quick.Options.Serializer.Json.pas
  22. 123 0
      Quick.Options.Serializer.Yaml.pas
  23. 552 0
      Quick.Options.pas
  24. 35 2
      Quick.RTTI.Utils.pas
  25. 1 0
      Quick.Value.RTTI.pas
  26. 16 0
      Quick.Value.pas
  27. 308 41
      README.md
  28. 39 0
      samples/delphi/QuickCompression/CompressionTest.dpr
  29. 906 0
      samples/delphi/QuickCompression/CompressionTest.dproj
  30. BIN
      samples/delphi/QuickCompression/CompressionTest.res
  31. 144 0
      samples/delphi/QuickHttpServer/HttpServer/HttpServerService.Logger.pas
  32. 79 0
      samples/delphi/QuickHttpServer/HttpServer/HttpServerService.dpr
  33. 902 0
      samples/delphi/QuickHttpServer/HttpServer/HttpServerService.dproj
  34. BIN
      samples/delphi/QuickHttpServer/HttpServer/HttpServerService.res
  35. 43 0
      samples/delphi/QuickIOC/AndroidManifest.template.xml
  36. 279 0
      samples/delphi/QuickIOC/IOCdemo.dpr
  37. 109 0
      samples/delphi/QuickIOC/IOCdemo.dproj
  38. BIN
      samples/delphi/QuickIOC/IOCdemo.res
  39. 153 0
      samples/delphi/QuickMemoryCache/MemoryCache/MemCacheTest.dpr
  40. 916 0
      samples/delphi/QuickMemoryCache/MemoryCache/MemCacheTest.dproj
  41. BIN
      samples/delphi/QuickMemoryCache/MemoryCache/MemCacheTest.res
  42. 119 0
      samples/delphi/QuickMemoryCache/MemoryCache/MemCacheTest2.dpr
  43. 922 0
      samples/delphi/QuickMemoryCache/MemoryCache/MemCacheTest2.dproj
  44. BIN
      samples/delphi/QuickMemoryCache/MemoryCache/MemCacheTest2.res
  45. 172 0
      samples/delphi/QuickMemoryCache/MemoryCacheVariant/MemCacheVariantTest.dpr
  46. 916 0
      samples/delphi/QuickMemoryCache/MemoryCacheVariant/MemCacheVariantTest.dproj
  47. BIN
      samples/delphi/QuickMemoryCache/MemoryCacheVariant/MemCacheVariantTest.res
  48. 109 0
      samples/delphi/QuickOptions/Optionsdemo.dpr
  49. 109 0
      samples/delphi/QuickOptions/Optionsdemo.dproj
  50. BIN
      samples/delphi/QuickOptions/Optionsdemo.res
  51. 105 0
      samples/delphi/QuickValue/QuickValue.dpr
  52. 109 0
      samples/delphi/QuickValue/QuickValue.dproj
  53. BIN
      samples/delphi/QuickValue/QuickValue.res
  54. 43 0
      samples/firemonkey/QuickIOC/IOCDemo/AndroidManifest.template.xml
  55. 171 0
      samples/firemonkey/QuickIOC/IOCDemo/Dependencies.pas
  56. 286 0
      samples/firemonkey/QuickIOC/IOCDemo/IOCDemo.deployproj
  57. 14 0
      samples/firemonkey/QuickIOC/IOCDemo/IOCDemo.dpr
  58. 305 0
      samples/firemonkey/QuickIOC/IOCDemo/IOCDemo.dproj
  59. BIN
      samples/firemonkey/QuickIOC/IOCDemo/IOCDemo.res
  60. 42 0
      samples/firemonkey/QuickIOC/IOCDemo/Main.fmx
  61. 142 0
      samples/firemonkey/QuickIOC/IOCDemo/Main.pas
  62. 144 0
      samples/fpc/QuickHttpServer/HttpServerService.Logger.pas
  63. 66 0
      samples/fpc/QuickHttpServer/HttpServerService.lpi
  64. 73 0
      samples/fpc/QuickHttpServer/HttpServerService.pas

+ 121 - 2
Quick.Arrays.pas

@@ -7,7 +7,7 @@
   Author      : Kike Pérez
   Author      : Kike Pérez
   Version     : 1.2
   Version     : 1.2
   Created     : 24/03/2019
   Created     : 24/03/2019
-  Modified    : 31/08/2019
+  Modified    : 16/10/2019
 
 
   This file is part of QuickLib: https://github.com/exilon/QuickLib
   This file is part of QuickLib: https://github.com/exilon/QuickLib
 
 
@@ -84,24 +84,40 @@ type
 
 
   TPairArray = TArray<TPair>;
   TPairArray = TArray<TPair>;
 
 
+  PPairArray = ^TPairArray;
+
   TPairXArray = TXArray<TPair>;
   TPairXArray = TXArray<TPair>;
 
 
   TFlexArray = TXArray<TFlexValue>;
   TFlexArray = TXArray<TFlexValue>;
 
 
   TFlexPairArray = TArray<TFlexPair>;
   TFlexPairArray = TArray<TFlexPair>;
 
 
+  TPairArrayHelper = record helper for TPairArray
+  public
+    function GetValue(const aName : string) : string;
+    function GetPair(const aName : string) : TPair;
+    function Add(aPair : TPair) : Integer; overload;
+    function Add(const aName, aValue : string) : Integer; overload;
+    procedure AddOrUpdate(const aName, aValue : string);
+    function Exists(const aName : string) : Boolean;
+    function Remove(const aName : string) : Boolean;
+    function Count : Integer;
+    property Items[const aName : string] : string read GetValue write AddOrUpdate;
+  end;
+
   TFlexPairArrayHelper = record helper for TFlexPairArray
   TFlexPairArrayHelper = record helper for TFlexPairArray
   public
   public
     function GetValue(const aName : string) : TFlexValue;
     function GetValue(const aName : string) : TFlexValue;
     function GetPair(const aName : string) : TFlexPair;
     function GetPair(const aName : string) : TFlexPair;
     function Add(aFlexPair : TFlexPair) : Integer; overload;
     function Add(aFlexPair : TFlexPair) : Integer; overload;
     function Add(const aName: string; aValue : TFlexValue): Integer; overload;
     function Add(const aName: string; aValue : TFlexValue): Integer; overload;
+    procedure AddOrUpdate(const aName : string; aValue : TFlexValue);
     function Exists(const aName : string) : Boolean;
     function Exists(const aName : string) : Boolean;
     function Remove(const aName : string) : Boolean;
     function Remove(const aName : string) : Boolean;
     function Count : Integer;
     function Count : Integer;
+    property Items[const aName : string] : TFlexValue read GetValue write AddOrUpdate;
   end;
   end;
 
 
-
 implementation
 implementation
 
 
 
 
@@ -268,6 +284,7 @@ function TFlexPairArrayHelper.GetValue(const aName: string): TFlexValue;
 var
 var
   i : Integer;
   i : Integer;
 begin
 begin
+  Result.Clear;
   for i := Low(Self) to High(Self) do
   for i := Low(Self) to High(Self) do
   begin
   begin
     if CompareText(Self[i].Name,aName) = 0 then Exit(Self[i].Value);
     if CompareText(Self[i].Name,aName) = 0 then Exit(Self[i].Value);
@@ -286,6 +303,23 @@ begin
       Exit(True);
       Exit(True);
     end;
     end;
   end;
   end;
+  Result := False;
+end;
+
+procedure TFlexPairArrayHelper.AddOrUpdate(const aName : string; aValue : TFlexValue);
+var
+  i : Integer;
+begin
+  for i := Low(Self) to High(Self) do
+  begin
+    if CompareText(Self[i].Name,aName) = 0 then
+    begin
+      Self[i].Value := aValue;
+      Exit;
+    end;
+  end;
+  //if not exists add it
+  Self.Add(aName,aValue);
 end;
 end;
 
 
 { TPair }
 { TPair }
@@ -296,4 +330,89 @@ begin
   Value := aValue;
   Value := aValue;
 end;
 end;
 
 
+{ TPairArrayHelper }
+
+function TPairArrayHelper.Add(aPair: TPair): Integer;
+begin
+  SetLength(Self,Length(Self)+1);
+  Self[High(Self)] := aPair;
+  Result := High(Self);
+end;
+
+function TPairArrayHelper.Add(const aName, aValue: string): Integer;
+begin
+  SetLength(Self,Length(Self)+1);
+  Self[High(Self)].Name := aName;
+  Self[High(Self)].Value := aValue;
+  Result := High(Self);
+end;
+
+procedure TPairArrayHelper.AddOrUpdate(const aName, aValue: string);
+var
+  i : Integer;
+begin
+  for i := Low(Self) to High(Self) do
+  begin
+    if CompareText(Self[i].Name,aName) = 0 then
+    begin
+      Self[i].Value := aValue;
+      Exit;
+    end;
+  end;
+  //if not exists add it
+  Self.Add(aName,aValue);
+end;
+
+function TPairArrayHelper.Count: Integer;
+begin
+  Result := High(Self) + 1;
+end;
+
+function TPairArrayHelper.Exists(const aName: string): Boolean;
+var
+  i : Integer;
+begin
+  Result := False;
+  for i := Low(Self) to High(Self) do
+  begin
+    if CompareText(Self[i].Name,aName) = 0 then Exit(True)
+  end;
+end;
+
+function TPairArrayHelper.GetPair(const aName: string): TPair;
+var
+  i : Integer;
+begin
+  for i := Low(Self) to High(Self) do
+  begin
+    if CompareText(Self[i].Name,aName) = 0 then Exit(Self[i]);
+  end;
+end;
+
+function TPairArrayHelper.GetValue(const aName: string): string;
+var
+  i : Integer;
+begin
+  Result := '';
+  for i := Low(Self) to High(Self) do
+  begin
+    if CompareText(Self[i].Name,aName) = 0 then Exit(Self[i].Value);
+  end;
+end;
+
+function TPairArrayHelper.Remove(const aName: string): Boolean;
+var
+  i : Integer;
+begin
+  for i := Low(Self) to High(Self) do
+  begin
+    if CompareText(Self[i].Name,aName) = 0 then
+    begin
+      System.Delete(Self,i,1);
+      Exit(True);
+    end;
+  end;
+  Result := False;
+end;
+
 end.
 end.

+ 19 - 2
Quick.AutoMapper.pas

@@ -5,9 +5,9 @@
   Unit        : Quick.AutoMapper
   Unit        : Quick.AutoMapper
   Description : Auto Mapper object properties
   Description : Auto Mapper object properties
   Author      : Kike Pérez
   Author      : Kike Pérez
-  Version     : 1.4
+  Version     : 1.5
   Created     : 25/08/2018
   Created     : 25/08/2018
-  Modified    : 10/05/2019
+  Modified    : 16/10/2019
 
 
   This file is part of QuickLib: https://github.com/exilon/QuickLib
   This file is part of QuickLib: https://github.com/exilon/QuickLib
 
 
@@ -98,6 +98,13 @@ type
     {$ENDIF}
     {$ENDIF}
   end;
   end;
 
 
+  {$IFNDEF FPC}
+  TMapper = class
+  public
+    class function Map<T : class, constructor>(aSrcObj : TObject) : T;
+  end;
+  {$ENDIF}
+
   TMapper<T : class, constructor> = class
   TMapper<T : class, constructor> = class
   public
   public
     class function Map(aSrcObj : TObject; aCustomMapping: TCustomMapping = nil): T; overload;
     class function Map(aSrcObj : TObject; aCustomMapping: TCustomMapping = nil): T; overload;
@@ -497,4 +504,14 @@ end;
 
 
 {$ENDIF}
 {$ENDIF}
 
 
+{ TMapper }
+
+{$IFNDEF FPC}
+class function TMapper.Map<T>(aSrcObj: TObject): T;
+begin
+  Result := T.Create;
+  TObjMapper.Map(aSrcObj,Result,nil);
+end;
+{$ENDIF}
+
 end.
 end.

+ 72 - 3
Quick.Azure.pas

@@ -5,9 +5,9 @@
   Unit        : Quick.Azure
   Unit        : Quick.Azure
   Description : Azure blobs operations
   Description : Azure blobs operations
   Author      : Kike Pérez
   Author      : Kike Pérez
-  Version     : 1.2
+  Version     : 1.4
   Created     : 27/08/2015
   Created     : 27/08/2015
-  Modified    : 11/03/2019
+  Modified    : 08/10/2019
 
 
   This file is part of QuickLib: https://github.com/exilon/QuickLib
   This file is part of QuickLib: https://github.com/exilon/QuickLib
 
 
@@ -29,6 +29,8 @@
 
 
 unit Quick.Azure;
 unit Quick.Azure;
 
 
+{$i QuickLib.inc}
+
 interface
 interface
 
 
 uses
 uses
@@ -38,7 +40,8 @@ uses
   IPPeerClient,
   IPPeerClient,
   IdURI,
   IdURI,
   Data.Cloud.CloudAPI,
   Data.Cloud.CloudAPI,
-  Data.Cloud.AzureAPI;
+  Data.Cloud.AzureAPI,
+  Quick.Commons;
 
 
 type
 type
 
 
@@ -54,6 +57,7 @@ type
   TAzureBlobObject = class
   TAzureBlobObject = class
     Name : string;
     Name : string;
     Size : Int64;
     Size : Int64;
+    IsDir : Boolean;
     LastModified : TDateTime;
     LastModified : TDateTime;
   end;
   end;
 
 
@@ -565,6 +569,70 @@ begin
   end;
   end;
 end;
 end;
 
 
+{$IFDEF DELPHITOKYO_UP}
+function TQuickAzure.ListBlobs(const azContainer, azBlobsStartWith : string; Recursive : Boolean; out azResponseInfo : TAzureResponseInfo) : TBlobList;
+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>;
+begin
+  Result := TBlobList.Create(True);
+  cNextMarker := '';
+  container := CheckContainer(azContainer);
+  BlobService := TAzureBlobService.Create(fconAzure);
+  try
+    if Recursive then prefix := ''
+      else prefix := '/';
+    BlobService.Timeout := fTimeout;
+    repeat
+      CloudResponseInfo := TCloudResponseInfo.Create;
+      try
+        azBlobList := BlobService.ListBlobs(azContainer,azBlobsStartWith,'/',cNextMarker,100,[],cNextMarker,blobprefix,xmlresp,CloudResponseInfo);
+        azResponseInfo := GetResponseInfo(CloudResponseInfo);
+        //get folders (prefix)
+        for folder in blobprefix do
+        begin
+          Blob := TAzureBlobObject.Create;
+          if folder.EndsWith('/') then Blob.Name := RemoveLastChar(folder)
+            else Blob.Name := folder;
+          Blob.Name := Copy(Blob.Name,Blob.Name.LastDelimiter('/')+2,Blob.Name.Length);
+          Blob.IsDir := True;
+          Result.Add(Blob);
+        end;
+        //get files (blobs)
+        if Assigned(azBlobList) then
+        begin
+          for azBlob in azBlobList do
+          begin
+            Blob := TAzureBlobObject.Create;
+            Blob.Name := azBlob.Name;
+            for prop in azBlob.Properties do
+            begin
+              if prop.Key = 'Content-Length' then Blob.Size := StrToInt64Def(prop.Value,0)
+                else if prop.Key = 'Last-Modified' then Blob.LastModified := GMT2DateTime(prop.Value);
+            end;
+            Blob.IsDir := False;
+            Result.Add(Blob);
+          end;
+        end;
+      finally
+        CloudResponseInfo.Free;
+      end;
+    until (cNextMarker = '') or (azResponseInfo.StatusCode <> 200);
+  finally
+    BlobService.Free;
+  end;
+end;
+{$ELSE}
 function TQuickAzure.ListBlobs(const azContainer, azBlobsStartWith : string; Recursive : Boolean; out azResponseInfo : TAzureResponseInfo) : TBlobList;
 function TQuickAzure.ListBlobs(const azContainer, azBlobsStartWith : string; Recursive : Boolean; out azResponseInfo : TAzureResponseInfo) : TBlobList;
 var
 var
   BlobService : TAzureBlobService;
   BlobService : TAzureBlobService;
@@ -620,6 +688,7 @@ begin
     BlobService.Free;
     BlobService.Free;
   end;
   end;
 end;
 end;
+{$ENDIF}
 
 
 function TQuickAzure.ListBlobsNames(const azContainer, azBlobsStartWith : string; Recursive : Boolean; out azResponseInfo : TAzureResponseInfo) : TStrings;
 function TQuickAzure.ListBlobsNames(const azContainer, azBlobsStartWith : string; Recursive : Boolean; out azResponseInfo : TAzureResponseInfo) : TStrings;
 var
 var

+ 67 - 0
Quick.Cache.Intf.pas

@@ -0,0 +1,67 @@
+{ ***************************************************************************
+
+  Copyright (c) 2016-2019 Kike Pérez
+
+  Unit        : Quick.HttpServer.Intf.Cache
+  Description : Http Server Cache Interface
+  Author      : Kike Pérez
+  Version     : 1.0
+  Created     : 12/10/2019
+  Modified    : 27/10/2019
+
+  This file is part of QuickLib: https://github.com/exilon/QuickLib
+
+ ***************************************************************************
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+ *************************************************************************** }
+
+unit Quick.Cache.Intf;
+
+{$i QuickLib.inc}
+
+interface
+
+type
+  ICache = interface
+  ['{CF5061E1-BEAC-4CCC-8469-5020968116B9}']
+    function GetCompression: Boolean;
+    procedure SetCompression(const Value: Boolean);
+    function GetCachedObjects: Integer;
+    function GetCacheSize: Integer;
+    property Compression : Boolean read GetCompression write SetCompression;
+    property CachedObjects : Integer read GetCachedObjects;
+    property CacheSize : Integer read GetCacheSize;
+    procedure SetValue(const aKey : string; aValue : TObject; aExpirationMilliseconds : Integer = 0); overload;
+    procedure SetValue(const aKey : string; aValue : TObject; aExpirationDate : TDateTime); overload;
+    procedure SetValue(const aKey, aValue : string; aExpirationMilliseconds : Integer = 0); overload;
+    procedure SetValue(const aKey, aValue : string; aExpirationDate : TDateTime); overload;
+    procedure SetValue(const aKey : string; aValue : TArray<string>; aExpirationMilliseconds : Integer = 0); overload;
+    procedure SetValue(const aKey : string; aValue : TArray<string>; aExpirationDate : TDateTime); overload;
+    procedure SetValue(const aKey : string; aValue : TArray<TObject>; aExpirationMilliseconds : Integer = 0); overload;
+    procedure SetValue(const aKey : string; aValue : TArray<TObject>; aExpirationDate : TDateTime); overload;
+    function GetValue(const aKey : string) : string; overload;
+    function TryGetValue(const aKey : string; aValue : TObject) : Boolean; overload;
+    function TryGetValue(const aKey : string; out aValue : string) : Boolean; overload;
+    function TryGetValue(const aKey : string; out aValue : TArray<string>) : Boolean; overload;
+    function TryGetValue(const aKey : string; out aValue : TArray<TObject>) : Boolean; overload;
+    procedure RemoveValue(const aKey : string);
+    procedure Flush;
+  end;
+
+  IMemoryCache = ICache;
+
+implementation
+
+end.

+ 31 - 0
Quick.CloudStorage.Provider.Amazon.pas

@@ -1,5 +1,36 @@
+{ ***************************************************************************
+
+  Copyright (c) 2016-2019 Kike Pérez
+
+  Unit        : Quick.CloudStorage.Provider.Amazon
+  Description : CloudStorage Amazon provider
+  Author      : Kike Pérez
+  Version     : 1.8
+  Created     : 14/10/2018
+  Modified    : 07/10/2019
+
+  This file is part of QuickLib: https://github.com/exilon/QuickLib
+
+ ***************************************************************************
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+ *************************************************************************** }
+
 unit Quick.CloudStorage.Provider.Amazon;
 unit Quick.CloudStorage.Provider.Amazon;
 
 
+{$i QuickLib.inc}
+
 interface
 interface
 
 
 uses
 uses

+ 161 - 2
Quick.CloudStorage.Provider.Azure.pas

@@ -1,14 +1,45 @@
+{ ***************************************************************************
+
+  Copyright (c) 2016-2019 Kike Pérez
+
+  Unit        : Quick.CloudStorage.Provider.Azure
+  Description : CloudStorage Azure provider
+  Author      : Kike Pérez
+  Version     : 1.8
+  Created     : 14/10/2018
+  Modified    : 07/10/2019
+
+  This file is part of QuickLib: https://github.com/exilon/QuickLib
+
+ ***************************************************************************
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+ *************************************************************************** }
+
 unit Quick.CloudStorage.Provider.Azure;
 unit Quick.CloudStorage.Provider.Azure;
 
 
+{$i QuickLib.inc}
+
 interface
 interface
 
 
 uses
 uses
   Classes,
   Classes,
   System.SysUtils,
   System.SysUtils,
   System.Generics.Collections,
   System.Generics.Collections,
+  IPPeerClient,
   Quick.Commons,
   Quick.Commons,
   Quick.CloudStorage,
   Quick.CloudStorage,
-  IPPeerClient,
   Data.Cloud.CloudAPI,
   Data.Cloud.CloudAPI,
   Data.Cloud.AzureAPI;
   Data.Cloud.AzureAPI;
 
 
@@ -135,14 +166,141 @@ begin
   end;
   end;
 end;
 end;
 
 
+{$IFDEF DELPHITOKYO_UP}
+procedure TCloudStorageAzureProvider.OpenDir(const aPath: string);
+var
+  BlobService : TAzureBlobService;
+  azBlob : TAzureBlobItem;
+  DirItem : TCloudItem;
+  CloudResponseInfo : TCloudResponseInfo;
+  cNextMarker : string;
+  azBlobList : TArray<TAzureBlobItem>;
+  blobprefix : TArray<string>;
+  xmlresp : string;
+  azResponseInfo : TResponseInfo;
+  azContainer : string;
+  folder : string;
+  prop : TPair<string,string>;
+begin
+  Status := stSearching;
+  cNextMarker := '';
+  if aPath = '..' then
+  begin
+    CurrentPath := RemoveLastPathSegment(CurrentPath);
+  end
+  else
+  begin
+    if (CurrentPath = '') or (aPath.StartsWith('/')) then CurrentPath := aPath
+      else CurrentPath := CurrentPath + aPath;
+  end;
+  if Assigned(OnBeginReadDir) then OnBeginReadDir(CurrentPath);
+  if CurrentPath.StartsWith('/') then CurrentPath := Copy(CurrentPath,2,CurrentPath.Length);
+  if (not CurrentPath.IsEmpty) and (not CurrentPath.EndsWith('/')) then CurrentPath := CurrentPath + '/';
+
+  azContainer := RootFolder;
+  if azContainer = '' then azContainer := '$root';
+  BlobService := TAzureBlobService.Create(fAzureConnection);
+  try
+    BlobService.Timeout := Timeout;
+    Status := stRetrieving;
+    if Assigned(OnGetListItem) then
+    begin
+      DirItem := TCloudItem.Create;
+      try
+        DirItem.Name := '..';
+        DirItem.IsDir := True;
+        DirItem.Date := 0;
+        OnGetListItem(DirItem);
+      finally
+        DirItem.Free;
+      end;
+    end;
+    repeat
+      if not (Status in [stSearching,stRetrieving]) then Exit;
+      if fCancelOperation then
+      begin
+        fCancelOperation := False;
+        Exit;
+      end;
+      CloudResponseInfo := TCloudResponseInfo.Create;
+      try
+        azBlobList := BlobService.ListBlobs(azContainer,CurrentPath,'/',cNextMarker,100,[],cNextMarker,blobprefix,xmlresp,CloudResponseInfo);
+        azResponseInfo.Get(CloudResponseInfo);
+        if azResponseInfo.StatusCode = 200 then
+        begin
+          //get folders (prefix)
+          for folder in blobprefix do
+          begin
+            if not (Status in [stSearching,stRetrieving]) then Exit;
+            DirItem := TCloudItem.Create;
+            try
+              if folder.EndsWith('/') then DirItem.Name := RemoveLastChar(folder)
+                else DirItem.Name := folder;
+              DirItem.Name := Copy(DirItem.Name,DirItem.Name.LastDelimiter('/')+2,DirItem.Name.Length);
+              DirItem.IsDir := True;
+              if Assigned(OnGetListItem) then OnGetListItem(DirItem);
+            finally
+              DirItem.Free;
+            end;
+          end;
+          //get files (blobs)
+          for azBlob in azBlobList do
+          begin
+            if not (Status in [stSearching,stRetrieving]) then Exit;
+            if fCancelOperation then
+            begin
+              fCancelOperation := False;
+              Exit;
+            end;
+            DirItem := TCloudItem.Create;
+            try
+              DirItem.Name := azBlob.Name;
+              if DirItem.Name.StartsWith(CurrentPath) then DirItem.Name := StringReplace(DirItem.Name,CurrentPath,'',[]);
+              if DirItem.Name.Contains('/') then
+              begin
+                DirItem.IsDir := True;
+                DirItem.Name := Copy(DirItem.Name,1,DirItem.Name.IndexOf('/'));
+              end
+              else
+              begin
+                DirItem.IsDir := False;
+                for prop in azBlob.Properties do
+                begin
+                  if prop.Key = 'Content-Length' then DirItem.Size := StrToInt64Def(prop.Value,0)
+                    else if prop.Key = 'Last-Modified' then DirItem.Date := GMT2DateTime(prop.Value);
+                end;
+              end;
+              if Assigned(OnGetListItem) then OnGetListItem(DirItem);
+            finally
+              DirItem.Free;
+            end;
+          end;
+        end
+        else
+        begin
+          Status := stFailed;
+          Exit;
+        end;
+      finally
+        CloudResponseInfo.Free;
+      end;
+      if Assigned(OnRefreshReadDir) then OnRefreshReadDir(CurrentPath);
+    until (cNextMarker = '') or (azResponseInfo.StatusCode <> 200);
+    Status := stDone;
+  finally
+    BlobService.Free;
+    if Assigned(OnEndReadDir) then OnEndReadDir(CurrentPath);
+  end;
+end;
+{$ELSE}
 procedure TCloudStorageAzureProvider.OpenDir(const aPath: string);
 procedure TCloudStorageAzureProvider.OpenDir(const aPath: string);
 var
 var
   BlobService : TAzureBlobService;
   BlobService : TAzureBlobService;
   azBlob : TAzureBlob;
   azBlob : TAzureBlob;
-  azBlobList : TList<TAzureBlob>;
   DirItem : TCloudItem;
   DirItem : TCloudItem;
   CloudResponseInfo : TCloudResponseInfo;
   CloudResponseInfo : TCloudResponseInfo;
   cNextMarker : string;
   cNextMarker : string;
+  azBlobList : TList<TAzureBlob>;
   AzParams : TStrings;
   AzParams : TStrings;
   azResponseInfo : TResponseInfo;
   azResponseInfo : TResponseInfo;
   azContainer : string;
   azContainer : string;
@@ -255,6 +413,7 @@ begin
     if Assigned(OnEndReadDir) then OnEndReadDir(CurrentPath);
     if Assigned(OnEndReadDir) then OnEndReadDir(CurrentPath);
   end;
   end;
 end;
 end;
+{$ENDIF}
 
 
 {procedure TCloudStorageAzureProvider.OpenDir(const aPath : string);
 {procedure TCloudStorageAzureProvider.OpenDir(const aPath : string);
 var
 var

+ 31 - 0
Quick.CloudStorage.pas

@@ -1,5 +1,36 @@
+{ ***************************************************************************
+
+  Copyright (c) 2016-2019 Kike Pérez
+
+  Unit        : Quick.CloudStorage
+  Description : CloudStorage
+  Author      : Kike Pérez
+  Version     : 1.8
+  Created     : 14/10/2018
+  Modified    : 07/10/2019
+
+  This file is part of QuickLib: https://github.com/exilon/QuickLib
+
+ ***************************************************************************
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+ *************************************************************************** }
+
 unit Quick.CloudStorage;
 unit Quick.CloudStorage;
 
 
+{$i QuickLib.inc}
+
 interface
 interface
 
 
 uses
 uses

+ 360 - 15
Quick.Commons.pas

@@ -5,9 +5,9 @@
   Unit        : Quick.Commons
   Unit        : Quick.Commons
   Description : Common functions
   Description : Common functions
   Author      : Kike Pérez
   Author      : Kike Pérez
-  Version     : 1.8
+  Version     : 1.9
   Created     : 14/07/2017
   Created     : 14/07/2017
-  Modified    : 15/09/2019
+  Modified    : 10/11/2019
 
 
   This file is part of QuickLib: https://github.com/exilon/QuickLib
   This file is part of QuickLib: https://github.com/exilon/QuickLib
 
 
@@ -169,6 +169,52 @@ type
     procedure Reset;
     procedure Reset;
   end;
   end;
 
 
+  {$IFNDEF FPC}
+  TArrayOfStringHelper = record helper for TArray<string>
+  public
+    function Add(const aValue : string) : Integer;
+    function AddIfNotExists(const aValue : string; aCaseSense : Boolean = False) : Integer;
+    function Remove(const aValue : string) : Boolean;
+    function Exists(const aValue : string) : Boolean;
+    function Count : Integer;
+  end;
+  {$ENDIF}
+
+  TPairItem = record
+    Name : string;
+    Value : string;
+    constructor Create(const aName, aValue : string);
+  end;
+
+  TPairList = class
+  type
+    TPairEnumerator = class
+      private
+        fArray : ^TArray<TPairItem>;
+        fIndex : Integer;
+        function GetCurrent: TPairItem;
+      public
+        constructor Create(var aArray: TArray<TPairItem>);
+        property Current : TPairItem read GetCurrent;
+        function MoveNext: Boolean;
+      end;
+  private
+    fItems : TArray<TPairItem>;
+  public
+    function GetEnumerator : TPairEnumerator;
+    function GetValue(const aName : string) : string;
+    function GetPair(const aName : string) : TPairItem;
+    function Add(aPair : TPairItem) : Integer; overload;
+    function Add(const aName, aValue : string) : Integer; overload;
+    procedure AddOrUpdate(const aName, aValue : string);
+    function Exists(const aName : string) : Boolean;
+    function Remove(const aName : string) : Boolean;
+    function Count : Integer;
+    property Items[const aName : string] : string read GetValue write AddOrUpdate;
+    function ToArray : TArray<TPairItem>;
+    procedure FromArray(aValue : TArray<TPairItem>);
+  end;
+
   EEnvironmentPath = class(Exception);
   EEnvironmentPath = class(Exception);
   EShellError = class(Exception);
   EShellError = class(Exception);
 
 
@@ -249,6 +295,12 @@ type
   function NormalizePathDelim(const cPath : string; const Delim : Char) : string;
   function NormalizePathDelim(const cPath : string; const Delim : Char) : string;
   //Removes last segment of a path
   //Removes last segment of a path
   function RemoveLastPathSegment(cDir : string) : string;
   function RemoveLastPathSegment(cDir : string) : string;
+  //returns path delimiter if found
+  function GetPathDelimiter(const aPath : string) : string;
+  //returns first segment of a path
+  function GetFirstPathSegment(const aPath : string) : string;
+  //returns last segment of a path
+  function GetLastPathSegment(const aPath : string) : string;
   //finds swith in commandline params
   //finds swith in commandline params
   function ParamFindSwitch(const Switch : string) : Boolean;
   function ParamFindSwitch(const Switch : string) : Boolean;
   //gets value for a switch if exists
   //gets value for a switch if exists
@@ -273,10 +325,16 @@ type
   function JsonDateToDateTime(const aJsonDate : string) : TDateTime;
   function JsonDateToDateTime(const aJsonDate : string) : TDateTime;
   //count number of digits of a Integer
   //count number of digits of a Integer
   function CountDigits(anInt: Cardinal): Cardinal; inline;
   function CountDigits(anInt: Cardinal): Cardinal; inline;
+  //count times a string is present in other string
+  function CountStr(const aFindStr, aSourceStr : string) : Integer;
   //save stream to file
   //save stream to file
-  procedure SaveStreamToFile(stream : TStream; const filename : string);
+  procedure SaveStreamToFile(aStream : TStream; const aFilename : string);
   //save stream to string
   //save stream to string
-  function StreamToString(stream : TStream) : string;
+  function StreamToString(aStream : TStream) : string;
+  function StreamToString2(const aStream: TStream; const aEncoding: TEncoding): string;
+  //save string to stream
+  procedure StringToStream(const aStr : string; aStream : TStream);
+  procedure StringToStream2(const aStr : string; aStream : TStream);
   //returns a real comma separated text from stringlist
   //returns a real comma separated text from stringlist
   function CommaText(aList : TStringList) : string; overload;
   function CommaText(aList : TStringList) : string; overload;
   //returns a real comma separated text from array of string
   //returns a real comma separated text from array of string
@@ -902,6 +960,37 @@ begin
   if (Result <> '') and (EndsWithDelim) then Result := Result + delim;
   if (Result <> '') and (EndsWithDelim) then Result := Result + delim;
 end;
 end;
 
 
+function GetPathDelimiter(const aPath : string) : string;
+begin
+  if aPath.Contains('/') then Result := '/'
+    else if aPath.Contains('\') then Result := '\'
+    else Result := '';
+end;
+
+function GetFirstPathSegment(const aPath : string) : string;
+var
+  delimiter : string;
+  spath : string;
+begin
+  delimiter := GetPathDelimiter(aPath);
+  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));
+end;
+
+function GetLastPathSegment(const aPath : string) : string;
+var
+  delimiter : string;
+  spath : string;
+begin
+  delimiter := GetPathDelimiter(aPath);
+  if delimiter.IsEmpty then Exit(aPath);
+  if aPath.EndsWith(delimiter) then spath := Copy(aPath,0,aPath.Length - 1)
+    else spath := aPath;
+  Result := spath.Substring(spath.LastDelimiter(delimiter)+1);
+end;
+
 function ParamFindSwitch(const Switch : string) : Boolean;
 function ParamFindSwitch(const Switch : string) : Boolean;
 begin
 begin
   Result := FindCmdLineSwitch(Switch,['-', '/'],True);
   Result := FindCmdLineSwitch(Switch,['-', '/'],True);
@@ -1225,31 +1314,94 @@ begin
   end;
   end;
 end;
 end;
 
 
-procedure SaveStreamToFile(stream : TStream; const filename : string);
+function CountStr(const aFindStr, aSourceStr : string) : Integer;
+var
+  i : Integer;
+  found : Integer;
+  findstr : string;
+  mainstr : string;
+begin
+  findstr := aFindStr.ToLower;
+  mainstr := aSourceStr.ToLower;
+  Result := 0;
+  i := 0;
+  while i < mainstr.Length do
+  begin
+    found := Pos(findstr,mainstr,i);
+    if found > 0 then
+    begin
+      i := found;
+      Inc(Result);
+    end
+    else Break;
+  end;
+end;
+
+procedure SaveStreamToFile(aStream : TStream; const aFileName : string);
 var
 var
   fs : TFileStream;
   fs : TFileStream;
 begin
 begin
-  fs := TFileStream.Create(filename,fmCreate);
+  fs := TFileStream.Create(aFileName,fmCreate);
   try
   try
-    stream.Seek(0,soBeginning);
-    fs.CopyFrom(stream,stream.Size);
+    aStream.Seek(0,soBeginning);
+    fs.CopyFrom(aStream,aStream.Size);
   finally
   finally
     fs.Free;
     fs.Free;
   end;
   end;
 end;
 end;
 
 
-function StreamToString(stream : TStream) : string;
+function StreamToString(aStream : TStream) : string;
 var
 var
   ss : TStringStream;
   ss : TStringStream;
 begin
 begin
-  if stream = nil then Exit;
-  ss := TStringStream.Create;
+  aStream.Position := 0;
+  if aStream = nil then Exit;
+  if aStream is TMemoryStream then
+  begin
+    SetString(Result, PChar(TMemoryStream(aStream).Memory), TMemoryStream(aStream).Size div SizeOf(Char));
+  end
+  else if aStream is TStringStream then
+  begin
+    Result := TStringStream(aStream).DataString;
+  end
+  else
+  begin
+    ss := TStringStream.Create;
+    try
+      aStream.Seek(0,soBeginning);
+      ss.CopyFrom(aStream,aStream.Size);
+      Result := ss.DataString;
+    finally
+      ss.Free;
+    end;
+  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);
+var
+  stream : TStringStream;
+begin
+  stream := TStringStream.Create(aStr,TEncoding.UTF8);
   try
   try
-    stream.Seek(0,soBeginning);
-    ss.CopyFrom(stream,stream.Size);
-    Result := ss.DataString;
+    aStream.CopyFrom(stream,stream.Size);
   finally
   finally
-    ss.Free;
+    stream.Free;
   end;
   end;
 end;
 end;
 
 
@@ -1363,6 +1515,199 @@ begin
   fCurrentTime := Now();
   fCurrentTime := Now();
 end;
 end;
 
 
+{ TArrayOfStringHelper}
+
+{$IFNDEF FPC}
+function TArrayOfStringHelper.Add(const aValue : string) : Integer;
+begin
+  SetLength(Self,Length(Self)+1);
+  Self[High(Self)] := aValue;
+  Result := High(Self);
+end;
+
+function TArrayOfStringHelper.AddIfNotExists(const aValue : string; aCaseSense : Boolean = False) : Integer;
+var
+  i : Integer;
+  found : Boolean;
+begin
+  found := False;
+  for i := Low(Self) to High(Self) do
+  begin
+    if aCaseSense then found := Self[i] = aValue
+    else
+    begin
+      found := CompareText(Self[i],aValue) = 0;
+      Exit(i)
+    end;
+  end;
+  if not found then
+  begin
+    //if not exists add it
+    i := Self.Add(aValue);
+    Exit(i);
+  end;
+  Result := -1;
+end;
+
+function TArrayOfStringHelper.Remove(const aValue : string) : Boolean;
+var
+  i : Integer;
+begin
+  for i := Low(Self) to High(Self) do
+  begin
+    if CompareText(Self[i],aValue) = 0 then
+    begin
+      System.Delete(Self,i,1);
+      Exit(True);
+    end;
+  end;
+  Result := False;
+end;
+
+function TArrayOfStringHelper.Exists(const aValue : string) : Boolean;
+var
+  value : string;
+begin
+  Result := False;
+  for value in Self do
+  begin
+    if CompareText(value,aValue) = 0 then Exit(True)
+  end;
+end;
+
+function TArrayOfStringHelper.Count : Integer;
+begin
+  Result := High(Self) + 1;
+end;
+{$ENDIF}
+
+{ TPairItem }
+
+constructor TPairItem.Create(const aName, aValue: string);
+begin
+  Name := aName;
+  Value := aValue;
+end;
+
+{ TPairList }
+
+function TPairList.GetEnumerator : TPairEnumerator;
+begin
+  Result := TPairEnumerator.Create(fItems);
+end;
+
+function TPairList.Add(aPair: TPairItem): Integer;
+begin
+  SetLength(fItems,Length(fItems)+1);
+  fItems[High(fItems)] := aPair;
+  Result := High(fItems);
+end;
+
+function TPairList.Add(const aName, aValue: string): Integer;
+begin
+  SetLength(fItems,Length(fItems)+1);
+  fItems[High(fItems)].Name := aName;
+  fItems[High(fItems)].Value := aValue;
+  Result := High(fItems);
+end;
+
+procedure TPairList.AddOrUpdate(const aName, aValue: string);
+var
+  i : Integer;
+begin
+  for i := Low(fItems) to High(fItems) do
+  begin
+    if CompareText(fItems[i].Name,aName) = 0 then
+    begin
+      fItems[i].Value := aValue;
+      Exit;
+    end;
+  end;
+  //if not exists add it
+  Self.Add(aName,aValue);
+end;
+
+function TPairList.Count: Integer;
+begin
+  Result := High(fItems) + 1;
+end;
+
+function TPairList.Exists(const aName: string): Boolean;
+var
+  i : Integer;
+begin
+  Result := False;
+  for i := Low(fItems) to High(fItems) do
+  begin
+    if CompareText(fItems[i].Name,aName) = 0 then Exit(True)
+  end;
+end;
+
+function TPairList.GetPair(const aName: string): TPairItem;
+var
+  i : Integer;
+begin
+  for i := Low(fItems) to High(fItems) do
+  begin
+    if CompareText(fItems[i].Name,aName) = 0 then Exit(fItems[i]);
+  end;
+end;
+
+function TPairList.GetValue(const aName: string): string;
+var
+  i : Integer;
+begin
+  Result := '';
+  for i := Low(fItems) to High(fItems) do
+  begin
+    if CompareText(fItems[i].Name,aName) = 0 then Exit(fItems[i].Value);
+  end;
+end;
+
+function TPairList.Remove(const aName: string): Boolean;
+var
+  i : Integer;
+begin
+  for i := Low(fItems) to High(fItems) do
+  begin
+    if CompareText(fItems[i].Name,aName) = 0 then
+    begin
+      System.Delete(fItems,i,1);
+      Exit(True);
+    end;
+  end;
+  Result := False;
+end;
+
+function TPairList.ToArray : TArray<TPairItem>;
+begin
+  Result := fItems;
+end;
+
+procedure TPairList.FromArray(aValue : TArray<TPairItem>);
+begin
+  fItems := aValue;
+end;
+
+{ TPairList.TPairEnumerator}
+
+constructor TPairList.TPairEnumerator.Create(var aArray: TArray<TPairItem>);
+begin
+  fIndex := -1;
+  fArray := @aArray;
+end;
+
+function TPairList.TPairEnumerator.GetCurrent : TPairItem;
+begin
+  Result := TArray<TPairItem>(fArray^)[fIndex];
+end;
+
+function TPairList.TPairEnumerator.MoveNext: Boolean;
+begin
+  Inc(fIndex);
+  Result := fIndex < High(TArray<TPairItem>(fArray^))+1;
+end;
+
 {$IFDEF MSWINDOWS}
 {$IFDEF MSWINDOWS}
 procedure ProcessMessages;
 procedure ProcessMessages;
 var
 var

+ 141 - 0
Quick.Compression.LZO.pas

@@ -0,0 +1,141 @@
+{ ***************************************************************************
+
+  Copyright (c) 2016-2019 Kike Pérez
+
+  Unit        : Quick.Compression.LZO
+  Description : LZO Compressor
+  Author      : Kike Pérez
+  Version     : 1.8
+  Created     : 15/09/2019
+  Modified    : 22/09/2019
+
+  This file is part of QuickLib: https://github.com/exilon/QuickLib
+
+ ***************************************************************************
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+ *************************************************************************** }
+
+unit Quick.Compression.LZO;
+
+{$i QuickLib.inc}
+
+interface
+
+uses
+  SysUtils;
+
+const
+
+  {$IFDEF MSWINDOWS}
+  LIBPATH = '.\lzo.dll';
+  {$ELSE}
+  LIBPATH = './lzo.so';
+  {$ENDIF}
+
+type
+
+  TLZOCompressor = class
+  private
+    fWorkMemory : Pointer;
+  public
+    constructor Create;
+    destructor Destroy; override;
+    function Version : string;
+    function VersionDate : string;
+    function Compress(const aUncompressed : string) : string;
+    function Decompress(const aCompressed : string) : string;
+  end;
+
+  ELZOCompressor = class(Exception);
+
+implementation
+
+function __lzo_init3 : Integer; stdcall; external LIBPATH;
+function lzo_version_string : PChar; stdcall; external LIBPATH;
+function lzo_version_date : PChar; stdcall; external LIBPATH;
+function lzo1x_1_compress(src : Pointer; src_len : LongWord; dest : Pointer; var dest_len : LongWord; wrkmem : Pointer) : Integer; stdcall; external LIBPATH;
+function lzo1x_decompress(src : Pointer; src_len : LongWord; dest : Pointer; var dest_len : LongWord; wrkmem : Pointer) : Integer; stdcall; external LIBPATH;
+
+
+{ TLZOCompressor }
+
+function TLZOCompressor.Compress(const aUncompressed: string): string;
+var
+  srclen : Integer;
+  outlen : LongWord;
+  uncompressed : TBytes;
+  compressed : TBytes;
+  byteslen : array[1.. sizeof(integer)] of byte;
+begin
+  outlen := 0;
+  try
+    SetLength(compressed, Round(aUncompressed.Length + aUncompressed.Length / 64 + 16 + 3 + 4));
+    uncompressed := TEncoding.UTF8.GetBytes(aUncompressed);
+    lzo1x_1_compress(uncompressed, High(uncompressed)+1, compressed, outlen, fWorkMemory);
+    Finalize(uncompressed);
+    srclen := aUncompressed.Length;
+    Move(srclen,byteslen[1], SizeOf(Integer));
+    SetLength(compressed,outlen + 4);
+    Move(byteslen,compressed[outlen],4);
+    Result := TEncoding.ANSI.GetString(compressed,0,outlen + 4);
+  except
+    on E : Exception do raise ELZOCompressor.CreateFmt('LZO Compression error: %s',[e.Message]);
+  end;
+end;
+
+constructor TLZOCompressor.Create;
+begin
+  if __lzo_init3 <> 0 then raise Exception.Create('Initialization LZO-Compressor failed');
+  GetMem(fWorkMemory,16384 * 4);
+end;
+
+function TLZOCompressor.Decompress(const aCompressed: string): string;
+var
+  srclen : LongWord;
+  dstlen : LongWord;
+  uncompressed : TBytes;
+  compressed : TBytes;
+  i : Integer;
+begin
+  try
+    compressed := TEncoding.ANSI.GetBytes(aCompressed);
+    //get src length
+    srclen := PLongInt(@compressed[High(compressed)-3])^;
+    SetLength(uncompressed,srclen);
+    dstlen := 0;
+    lzo1x_decompress(compressed, High(compressed) - 4, uncompressed, dstlen, fWorkMemory);
+    Result := TEncoding.UTF8.GetString(uncompressed,0,dstlen);
+  except
+    on E : Exception do raise ELZOCompressor.CreateFmt('LZO Descompression error: %s',[e.Message]);
+  end;
+end;
+
+destructor TLZOCompressor.Destroy;
+begin
+  FreeMem(fWorkMemory);
+  inherited;
+end;
+
+function TLZOCompressor.Version: string;
+begin
+  Result := string(lzo_version_string);
+end;
+
+function TLZOCompressor.VersionDate: string;
+begin
+  Result := string(lzo_version_date^);
+end;
+
+end.

+ 311 - 0
Quick.HttpServer.Request.pas

@@ -0,0 +1,311 @@
+{ ***************************************************************************
+
+  Copyright (c) 2016-2019 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
+
+  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.HttpServer.Request;
+
+{$i QuickLib.inc}
+
+interface
+
+uses
+  Classes,
+  SysUtils,
+  Quick.Commons,
+  Quick.Arrays,
+  Quick.Value,
+  Quick.HttpServer.Types;
+
+type
+  EHttpRequestError = class(Exception);
+
+type
+  IHttpRequest = interface
+  ['{D6B236A5-9D04-4380-8A89-5BD4CC60A1A6}']
+    function GetPathSegment(aIndex : Integer) : string;
+    function GetQuery(const aName : string) : TFlexValue;
+    function GetURL: string;
+    function GetMethod: TMethodVerb;
+    function GetCacheControl: string;
+    function GetClientIP: string;
+    function GetContent: TStream;
+    function GetHeaders: TPairList;
+    function GetHost: string;
+    function GetPort: Integer;
+    function GetReferer: string;
+    function GetUnparsedParams: string;
+    function GetUserAgent: string;
+    property URL : string read GetURL;
+    property Method : TMethodVerb read GetMethod;
+    property Host : string read GetHost;
+    property Port : Integer read GetPort;
+    property Referer : string read GetReferer;
+    property UserAgent : string read GetUserAgent;
+    property CacheControl : string read GetCacheControl;
+    property PathSegment[aIndex : Integer] : string read GetPathSegment;
+    property UnparsedParams : string read GetUnparsedParams;
+    property Query[const aName : string] : TFlexValue read GetQuery;
+    property ClientIP : string read GetClientIP;
+    property Headers : TPairList read GetHeaders;
+    property Content : TStream read GetContent;
+    function ContentAsString : string;
+    function GetMethodAsString: string;
+  end;
+
+  THttpRequest = class(TInterfacedObject,IHttpRequest)
+  private
+    fURL : string;
+    fMethod : TMethodVerb;
+    fHost : string;
+    fPort : Integer;
+    fReferer : string;
+    fUserAgent : string;
+    fCacheControl : string;
+    fUnparsedParams : string;
+    fParsedQuery : TFlexPairArray;
+    fClientIP : string;
+    fHeaders : TPairList;
+    fContent : TStream;
+    fContentType : string;
+    fContentEncoding : string;
+    fContentLength : Int64;
+    function GetPathSegment(aIndex : Integer) : string;
+    function GetQuery(const aName : string) : TFlexValue;
+    procedure ParseQuery;
+    function GetURL: string;
+    function GetMethod: TMethodVerb;
+    function GetCacheControl: string;
+    function GetClientIP: string;
+    function GetContent: TStream;
+    function GetHeaders: TPairList;
+    function GetHost: string;
+    function GetPort: Integer;
+    function GetReferer: string;
+    function GetUnparsedParams: string;
+    function GetUserAgent: string;
+    procedure SetURL(const Value: string);
+    function GetContentEncoding: string;
+    function GetContentLength: Int64;
+    function GetContentType: string;
+    procedure SetContentEncoding(const Value: string);
+    procedure SetContentLength(const Value: Int64);
+    procedure SetContentType(const Value: string);
+  public
+    constructor Create;
+    destructor Destroy; override;
+    property URL : string read GetURL write SetURL;
+    property Method : TMethodVerb read GetMethod write fMethod;
+    property Host : string read GetHost write fHost;
+    property Port : Integer read GetPort write fPort;
+    property Referer : string read GetReferer write fReferer;
+    property UserAgent : string read GetUserAgent write fUserAgent;
+    property CacheControl : string read GetCacheControl write fCacheControl;
+    property PathSegment[aIndex : Integer] : string read GetPathSegment;
+    property UnparsedParams : string read GetUnparsedParams write fUnparsedParams;
+    property Query[const aName : string] : TFlexValue read GetQuery;
+    property ClientIP : string read GetClientIP write fClientIP;
+    property Headers : TPairList read GetHeaders write fHeaders;
+    property Content : TStream read GetContent write fContent;
+    property ContentType : string read GetContentType write SetContentType;
+    property ContentEncoding : string read GetContentEncoding write SetContentEncoding;
+    property ContentLength : Int64 read GetContentLength write SetContentLength;
+    procedure SetMethodFromString(const aVerbMethod : string);
+    function GetMethodAsString: string;
+    function ContentAsString : string;
+  end;
+
+implementation
+
+function THttpRequest.ContentAsString: string;
+begin
+  if fContent <> nil then Result := StreamToString2(fContent,TEncoding.UTF8);
+end;
+
+constructor THttpRequest.Create;
+begin
+  fHeaders := TPairList.Create;
+end;
+
+destructor THttpRequest.Destroy;
+begin
+  fHeaders.Free;
+  inherited;
+end;
+
+function THttpRequest.GetCacheControl: string;
+begin
+  Result := fCacheControl;
+end;
+
+function THttpRequest.GetClientIP: string;
+begin
+  Result := fClientIP;
+end;
+
+function THttpRequest.GetContent: TStream;
+begin
+  Result := fContent;
+end;
+
+function THttpRequest.GetContentEncoding: string;
+begin
+  Result := fContentEncoding;
+end;
+
+function THttpRequest.GetContentLength: Int64;
+begin
+  Result := fContentLength;
+end;
+
+function THttpRequest.GetContentType: string;
+begin
+  Result := fContentType;
+end;
+
+function THttpRequest.GetHeaders: TPairList;
+begin
+  Result := fHeaders;
+end;
+
+function THttpRequest.GetHost: string;
+begin
+  Result := fHost;
+end;
+
+function THttpRequest.GetMethod: TMethodVerb;
+begin
+  Result := fMethod;
+end;
+
+function THttpRequest.GetMethodAsString: string;
+begin
+  Result := MethodVerbStr[Integer(fMethod)];
+end;
+
+function THttpRequest.GetPathSegment(aIndex: Integer): string;
+var
+  upath : string;
+  segment : TArray<string>;
+begin
+  try
+    if fURL.StartsWith('/') then upath := furl.Substring(1)
+      else upath := fURL;
+    segment := upath.Split(['/']);
+    if (High(segment) < aIndex) or (aIndex < 0) then raise EHttpRequestError.CreateFmt('param out of bounds (%d)',[aIndex]);
+    Result := segment[aIndex];
+  except
+    on E : Exception do raise EHttpRequestError.CreateFmt('Error getting url path param : %s',[e.message]);
+  end;
+end;
+
+function THttpRequest.GetPort: Integer;
+begin
+  Result := fPort;
+end;
+
+function THttpRequest.GetQuery(const aName: string): TFlexValue;
+begin
+  if fParsedQuery.Count = 0 then ParseQuery;
+  Result := fParsedQuery.GetValue(aName);
+end;
+
+function THttpRequest.GetReferer: string;
+begin
+  Result := fReferer;
+end;
+
+function THttpRequest.GetUnparsedParams: string;
+begin
+  Result := fUnparsedParams;
+end;
+
+function THttpRequest.GetURL: string;
+begin
+  Result := fURL;
+end;
+
+function THttpRequest.GetUserAgent: string;
+begin
+  Result := fUserAgent;
+end;
+
+procedure THttpRequest.ParseQuery;
+var
+  param : string;
+  pair : TFlexPair;
+  posi : Integer;
+begin
+  for param in fUnparsedParams.Split(['&']) do
+  begin
+    posi := Pos('=',param);
+    pair.Name := Copy(param,1,posi - 1);
+    pair.Value := param.Substring(posi);
+    fParsedQuery.Add(pair);
+  end;
+end;
+
+procedure THttpRequest.SetContentEncoding(const Value: string);
+begin
+  fContentEncoding := Value;
+end;
+
+procedure THttpRequest.SetContentLength(const Value: Int64);
+begin
+  fContentLength := Value;
+end;
+
+procedure THttpRequest.SetContentType(const Value: string);
+begin
+  fContentType := Value;
+end;
+
+procedure THttpRequest.SetMethodFromString(const aVerbMethod: string);
+var
+  i : Integer;
+begin
+  fMethod := TMethodVerb.mUNKNOWN;
+  for i := 0 to Ord(High(TMethodVerb)) do
+  begin
+    if CompareText(aVerbMethod,MethodVerbStr[i]) = 0 then
+    begin
+      fMethod := TMethodVerb(i);
+      Exit;
+    end;
+  end;
+end;
+
+procedure THttpRequest.SetURL(const Value: string);
+begin
+  //remove first slash
+  if Value.StartsWith('/') then fURL := Value.Substring(1)
+    else fURL := Value;
+  //remove last slash
+  if fURL.EndsWith('/') then fURL := Copy(fURL,0,fURL.Length -1);
+end;
+
+end.

+ 190 - 0
Quick.HttpServer.Response.pas

@@ -0,0 +1,190 @@
+{ ***************************************************************************
+
+  Copyright (c) 2016-2019 Kike Pérez
+
+  Unit        : Quick.HttpServer.Response
+  Description : Http Server Response
+  Author      : Kike Pérez
+  Version     : 1.0
+  Created     : 30/08/2019
+  Modified    : 06/10/2019
+
+  This file is part of QuickLib: https://github.com/exilon/QuickLib
+
+ ***************************************************************************
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+ *************************************************************************** }
+
+unit Quick.HttpServer.Response;
+
+{$i QuickLib.inc}
+
+interface
+
+uses
+  Classes,
+  SysUtils,
+  Quick.Value,
+  Quick.Commons;
+
+type
+  IHttpResponse = interface
+  ['{3E90F34D-5F4D-41E5-89C5-CA9832C7405E}']
+    procedure SetStatusCode(const Value: Cardinal);
+    procedure SetStatusText(const Value: string);
+    function GetStatusCode: Cardinal;
+    function GetStatusText: string;
+    function GetHeaders: TPairList;
+    procedure SetHeaders(const Value: TPairList);
+    function GetContentStream: TStream;
+    procedure SetContentStream(const Value: TStream);
+    function GetContentText: string;
+    procedure SetContentText(const Value: string);
+    function GetContentType: string;
+    procedure SetContentType(const Value: string);
+    property Headers : TPairList read GetHeaders write SetHeaders;
+    property StatusCode : Cardinal read GetStatusCode write SetStatusCode;
+    property StatusText : string read GetStatusText write SetStatusText;
+    property Content : TStream read GetContentStream write SetContentStream;
+    property ContentText : string read GetContentText write SetContentText;
+    property ContentType : string read GetContentType write SetContentType;
+  end;
+
+  THttpResponse = class(TInterfacedObject,IHttpResponse)
+  private
+    fHeaders : TPairList;
+    fStatusText: string;
+    fStatusCode: Cardinal;
+    fContentText : string;
+    fContent : TStream;
+    fContentType : string;
+    procedure SetStatusCode(const Value: Cardinal);
+    procedure SetStatusText(const Value: string);
+    function GetStatusCode: Cardinal;
+    function GetStatusText: string;
+    function GetContentText: string;
+    function GetContentStream: TStream;
+    procedure SetContentText(const Value: string);
+    procedure SetContentStream(const Value: TStream);
+    function GetHeaders: TPairList;
+    procedure SetHeaders(const Value: TPairList);
+    function GetContentType: string;
+    procedure SetContentType(const Value: string);
+  public
+    constructor Create;
+    destructor Destroy; override;
+    procedure ContentFromStream(const Value: TStream);
+  published
+    property Headers : TPairList read GetHeaders write SetHeaders;
+    property StatusCode : Cardinal read GetStatusCode write SetStatusCode;
+    property StatusText : string read GetStatusText write SetStatusText;
+    property Content : TStream read GetContentStream write SetContentStream;
+    property ContentText : string read GetContentText write SetContentText;
+    property ContentType : string read GetContentType write SetContentType;
+  end;
+
+implementation
+
+{ THttpResponse }
+
+constructor THttpResponse.Create;
+begin
+  fContentText := '';
+  fContent := nil;
+  fStatusCode := 200;
+  fStatusText := '';
+  //add custom header to response
+  fHeaders := TPairList.Create;
+  fHeaders.Add('Server','QuickHttpServer');
+end;
+
+destructor THttpResponse.Destroy;
+begin
+  fHeaders.Free;
+  if Assigned(fContent) and (fContent <> nil) then fContent.Free;
+  inherited;
+end;
+
+function THttpResponse.GetContentStream: TStream;
+begin
+  Result := fContent;
+end;
+
+function THttpResponse.GetContentText: string;
+begin
+  Result := fContentText;
+end;
+
+function THttpResponse.GetContentType: string;
+begin
+  Result := fContentType;
+end;
+
+function THttpResponse.GetHeaders: TPairList;
+begin
+  Result := fHeaders;
+end;
+
+function THttpResponse.GetStatusCode: Cardinal;
+begin
+  Result := fStatusCode;
+end;
+
+function THttpResponse.GetStatusText: string;
+begin
+  Result := fStatusText;
+end;
+
+procedure THttpResponse.SetStatusCode(const Value: Cardinal);
+begin
+  fStatusCode := Value;
+end;
+
+procedure THttpResponse.SetStatusText(const Value: string);
+begin
+  fStatusText := Value;
+end;
+
+procedure THttpResponse.SetContentStream(const Value: TStream);
+begin
+  fContent := Value;
+end;
+
+procedure THttpResponse.SetContentText(const Value: string);
+begin
+  fContentText := Value;
+end;
+
+procedure THttpResponse.SetContentType(const Value: string);
+begin
+  fContentType := Value;
+end;
+
+procedure THttpResponse.SetHeaders(const Value: TPairList);
+begin
+  fHeaders := Value;
+end;
+
+procedure THttpResponse.ContentFromStream(const Value: TStream);
+begin
+  if Value <> nil then
+  begin
+    if fContent = nil then fContent := TMemoryStream.Create;
+    fContent.CopyFrom(Value,Value.Size);
+  end
+  else fContent := nil;
+end;
+
+end.

+ 562 - 0
Quick.HttpServer.Types.pas

@@ -0,0 +1,562 @@
+{ ***************************************************************************
+
+  Copyright (c) 2016-2019 Kike Pérez
+
+  Unit        : Quick.HttpServer.Types
+  Description : Http Server Types
+  Author      : Kike Pérez
+  Version     : 1.8
+  Created     : 30/08/2019
+  Modified    : 17/10/2019
+
+  This file is part of QuickLib: https://github.com/exilon/QuickLib
+
+ ***************************************************************************
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+ *************************************************************************** }
+
+unit Quick.HttpServer.Types;
+
+{$i QuickLib.inc}
+
+interface
+
+uses
+  SysUtils,
+  Generics.Collections;
+
+type
+
+  EControlledException = class(Exception)
+  private
+    fCallerClass : TClass;
+  public
+    constructor Create(aCaller : TObject; aMessage : string);
+    property CallerClass : TClass read fCallerClass write fCallerClass;
+  end;
+
+  TController = class(TInterfacedObject);
+
+  TControllerClass = class of TController;
+
+  TMethodVerb = (mUNKNOWN, mGET, mHEAD, mPOST, mPUT, mDELETE, mOPTIONS, mTRACE, mPATCH);
+
+  TMethodVerbs = set of TMethodVerb;
+
+  THttpStatusCode = (Accepted  = 202,
+                     Ambiguous = 300,
+                     BadGateway = 502,
+                     BadRequest = 400,
+                     Conflict = 409,
+                     Continue = 100,
+                     Created = 201,
+                     ExpectationFailed = 417,
+                     Forbidden = 403,
+                     Found = 302,
+                     GatewayTimeout = 504,
+                     Gone = 410,
+                     HttpVersionNotSupported = 505,
+                     InternalServerError = 500,
+                     LengthRequired = 411,
+                     MethodNotAllowed = 405,
+                     Moved = 301,
+                     MovedPermanently = 301,
+                     MultipleChoices = 300,
+                     NoContent = 204,
+                     NonAuthoritativeInformation = 203,
+                     NotAcceptable = 406,
+                     NotFound = 404,
+                     NotImplemented = 501,
+                     NotModified = 304,
+                     OK = 200,
+                     PartialContent = 206,
+                     PaymentRequired = 402,
+                     PreconditionFailed = 412,
+                     ProxyAuthenticationRequired = 407,
+                     Redirect = 302,
+                     RedirectKeepVerb = 307,
+                     RedirectMethod = 303,
+                     RequestedRangeNotSatisfiable = 416,
+                     RequestEntityTooLarge = 413,
+                     RequestTimeout = 408,
+                     RequestUriTooLong = 414,
+                     ResetContent = 205,
+                     SeeOther = 303,
+                     ServiceUnavailable = 503,
+                     SwitchingProtocols = 101,
+                     TemporaryRedirect = 307,
+                     Unauthorized = 401,
+                     UnsupportedMediaType = 415,
+                     Unused = 306,
+                     UpgradeRequired = 426,
+                     UseProxy = 305);
+
+  TMIMETypes = class
+  private
+    fMIMEList : TDictionary<string,string>;
+    procedure FillMIME;
+  public
+    constructor Create;
+    destructor Destroy; override;
+    function GetExtensionMIMEType(const aExtension : string) : string;
+    function GetFileMIMEType(const aFilename : string) : string;
+    procedure AddMIME(const aExtension, aMIMEType : string);
+  end;
+
+var
+  MIMETypes : TMIMETypes;
+
+const
+  MethodVerbStr: array[0..Ord(High(TMethodVerb))] of string = ('UNKNOWN','HEAD','GET','POST','PUT','DELETE','OPTIONS','TRACE','PATCH');
+
+implementation
+
+procedure TMIMETypes.AddMIME(const aExtension, aMIMEType: string);
+begin
+  if not fMIMEList.ContainsKey(aExtension.ToLower) then fMIMEList.Add(aExtension.ToLower,aMIMEType.ToLower);
+end;
+
+constructor TMIMETypes.Create;
+begin
+  fMIMEList := TDictionary<string,string>.Create(375);
+  FillMIME;
+end;
+
+destructor TMIMETypes.Destroy;
+begin
+  fMIMEList.Free;
+  inherited;
+end;
+
+procedure TMIMETypes.FillMIME;
+begin
+  { Animation }
+  fMIMEList.Add('.nml','animation/narrative');
+
+  { Audio }
+  fMIMEList.Add('.aac','audio/mp4');
+  fMIMEList.Add('.aif','audio/x-aiff');
+  fMIMEList.Add('.aifc','audio/x-aiff');
+  fMIMEList.Add('.aiff','audio/x-aiff');
+  fMIMEList.Add('.au','audio/basic');
+  fMIMEList.Add('.gsm','audio/x-gsm');
+  fMIMEList.Add('.kar','audio/midi');
+  fMIMEList.Add('.m3u','audio/mpegurl');
+  fMIMEList.Add('.m4a','audio/x-mpg');
+  fMIMEList.Add('.mid','audio/midi');
+  fMIMEList.Add('.midi','audio/midi');
+  fMIMEList.Add('.mpega','audio/x-mpg');
+  fMIMEList.Add('.mp2','audio/x-mpg');
+  fMIMEList.Add('.mp3','audio/x-mpg');
+  fMIMEList.Add('.mpga','audio/x-mpg');
+  fMIMEList.Add('.pls','audio/x-scpls');
+  fMIMEList.Add('.qcp','audio/vnd.qcelp');
+  fMIMEList.Add('.ra','audio/x-realaudio');
+  fMIMEList.Add('.ram','audio/x-pn-realaudio');
+  fMIMEList.Add('.rm','audio/x-pn-realaudio');
+  fMIMEList.Add('.sd2','audio/x-sd2');
+  fMIMEList.Add('.sid','audio/prs.sid');
+  fMIMEList.Add('.snd','audio/basic');
+  fMIMEList.Add('.wav','audio/x-wav');
+  fMIMEList.Add('.wax','audio/x-ms-wax');
+  fMIMEList.Add('.wma','audio/x-ms-wma');
+  fMIMEList.Add('.mjf','audio/x-vnd.AudioExplosion.MjuiceMediaFile');
+
+  { Image }
+  fMIMEList.Add('.art','image/x-jg');
+  fMIMEList.Add('.bmp','image/bmp');
+  fMIMEList.Add('.cdr','image/x-coreldraw');
+  fMIMEList.Add('.cdt','image/x-coreldrawtemplate');
+  fMIMEList.Add('.cpt','image/x-corelphotopaint');
+  fMIMEList.Add('.djv','image/vnd.djvu');
+  fMIMEList.Add('.djvu','image/vnd.djvu');
+  fMIMEList.Add('.gif','image/gif');
+  fMIMEList.Add('.ief','image/ief');
+  fMIMEList.Add('.ico','image/x-icon');
+  fMIMEList.Add('.jng','image/x-jng');
+  fMIMEList.Add('.jpg','image/jpeg');
+  fMIMEList.Add('.jpeg','image/jpeg');
+  fMIMEList.Add('.jpe','image/jpeg');
+  fMIMEList.Add('.pat','image/x-coreldrawpattern');
+  fMIMEList.Add('.pcx','image/pcx');
+  fMIMEList.Add('.pbm','image/x-portable-bitmap');
+  fMIMEList.Add('.pgm','image/x-portable-graymap');
+  fMIMEList.Add('.pict','image/x-pict');
+  fMIMEList.Add('.png','image/x-png');
+  fMIMEList.Add('.pnm','image/x-portable-anymap');
+  fMIMEList.Add('.pntg','image/x-macpaint');
+  fMIMEList.Add('.ppm','image/x-portable-pixmap');
+  fMIMEList.Add('.psd','image/x-psd');
+  fMIMEList.Add('.qtif','image/x-quicktime');
+  fMIMEList.Add('.ras','image/x-cmu-raster');
+  fMIMEList.Add('.rf','image/vnd.rn-realflash');
+  fMIMEList.Add('.rgb','image/x-rgb');
+  fMIMEList.Add('.rp','image/vnd.rn-realpix');
+  fMIMEList.Add('.sgi','image/x-sgi');
+  fMIMEList.Add('.svg','image/svg+xml');
+  fMIMEList.Add('.svgz','image/svg+xml');
+  fMIMEList.Add('.targa','image/x-targa');
+  fMIMEList.Add('.tif','image/x-tiff');
+  fMIMEList.Add('.webp','image/webp');
+  fMIMEList.Add('.xbm','image/xbm');
+  fMIMEList.Add('.xpm','image/x-xpixmap');
+  fMIMEList.Add('.xwd','image/x-xwindowdump');
+
+  { Text }
+  fMIMEList.Add('.323','text/h323');
+  fMIMEList.Add('.xml','text/xml');
+  fMIMEList.Add('.uls','text/iuls');
+  fMIMEList.Add('.txt','text/plain');
+  fMIMEList.Add('.rtx','text/richtext');
+  fMIMEList.Add('.wsc','text/scriptlet');
+  fMIMEList.Add('.rt','text/vnd.rn-realtext');
+  fMIMEList.Add('.htt','text/webviewhtml');
+  fMIMEList.Add('.htc','text/x-component');
+  fMIMEList.Add('.vcf','text/x-vcard');
+
+  { Video }
+  fMIMEList.Add('.asf','video/x-ms-asf');
+  fMIMEList.Add('.asx','video/x-ms-asf');
+  fMIMEList.Add('.avi','video/x-msvideo');
+  fMIMEList.Add('.dl','video/dl');
+  fMIMEList.Add('.dv','video/dv');
+  fMIMEList.Add('.flc','video/flc');
+  fMIMEList.Add('.fli','video/fli');
+  fMIMEList.Add('.gl','video/gl');
+  fMIMEList.Add('.lsf','video/x-la-asf');
+  fMIMEList.Add('.lsx','video/x-la-asf');
+  fMIMEList.Add('.mng','video/x-mng');
+  fMIMEList.Add('.mp4','video/mpeg');
+  fMIMEList.Add('.mpeg','video/x-mpeg2a');
+  fMIMEList.Add('.mpa','video/mpeg');
+  fMIMEList.Add('.mpe','video/mpeg');
+  fMIMEList.Add('.mpg','video/mpeg');
+  fMIMEList.Add('.ogv','video/ogg');
+  fMIMEList.Add('.moov','video/quicktime');
+  fMIMEList.Add('.mov','video/quicktime');
+  fMIMEList.Add('.mxu','video/vnd.mpegurl');
+  fMIMEList.Add('.qt','video/quicktime');
+  fMIMEList.Add('.qtc','video/x-qtc');
+  fMIMEList.Add('.rv','video/vnd.rn-realvideo');
+  fMIMEList.Add('.ivf','video/x-ivf');
+  fMIMEList.Add('.webm','video/webm');
+  fMIMEList.Add('.wm','video/x-ms-wm');
+  fMIMEList.Add('.wmp','video/x-ms-wmp');
+  fMIMEList.Add('.wmv','video/x-ms-wmv');
+  fMIMEList.Add('.wmx','video/x-ms-wmx');
+  fMIMEList.Add('.wvx','video/x-ms-wvx');
+  fMIMEList.Add('.rms','video/vnd.rn-realvideo-secure');
+  fMIMEList.Add('.movie','video/x-sgi-movie');
+
+  { Application }
+  fMIMEList.Add('.7z','application/x-7z-compressed');
+  fMIMEList.Add('.a','application/x-archive');
+  fMIMEList.Add('.aab','application/x-authorware-bin');
+  fMIMEList.Add('.aam','application/x-authorware-map');
+  fMIMEList.Add('.aas','application/x-authorware-seg');
+  fMIMEList.Add('.abw','application/x-abiword');
+  fMIMEList.Add('.ace','application/x-ace-compressed');
+  fMIMEList.Add('.ai','application/postscript');
+  fMIMEList.Add('.alz','application/x-alz-compressed');
+  fMIMEList.Add('.ani','application/x-navi-animation');
+  fMIMEList.Add('.arj','application/x-arj');
+  fMIMEList.Add('.bat','application/x-msdos-program');
+  fMIMEList.Add('.bcpio','application/x-bcpio');
+  fMIMEList.Add('.boz','application/x-bzip2');
+  fMIMEList.Add('.bz','application/x-bzip');
+  fMIMEList.Add('.bz2','application/x-bzip2');
+  fMIMEList.Add('.cab','application/vnd.ms-cab-compressed');
+  fMIMEList.Add('.cat','application/vnd.ms-pki.seccat');
+  fMIMEList.Add('.ccn','application/x-cnc');
+  fMIMEList.Add('.cco','application/x-cocoa');
+  fMIMEList.Add('.cdf','application/x-cdf');
+  fMIMEList.Add('.cer','application/x-x509-ca-cert');
+  fMIMEList.Add('.chm','application/vnd.ms-htmlhelp');
+  fMIMEList.Add('.chrt','application/vnd.kde.kchart');
+  fMIMEList.Add('.cil','application/vnd.ms-artgalry');
+  fMIMEList.Add('.class','application/java-vm');
+  fMIMEList.Add('.com','application/x-msdos-program');
+  fMIMEList.Add('.clp','application/x-msclip');
+  fMIMEList.Add('.cpio','application/x-cpio');
+  fMIMEList.Add('.cqk','application/x-calquick');
+  fMIMEList.Add('.crd','application/x-mscardfile');
+  fMIMEList.Add('.crl','application/pkix-crl');
+  fMIMEList.Add('.csh','application/x-csh');
+  fMIMEList.Add('.dar','application/x-dar');
+  fMIMEList.Add('.dbf','application/x-dbase');
+  fMIMEList.Add('.dcr','application/x-director');
+  fMIMEList.Add('.deb','application/x-debian-package');
+  fMIMEList.Add('.dir','application/x-director');
+  fMIMEList.Add('.dist','vnd.apple.installer+xml');
+  fMIMEList.Add('.distz','vnd.apple.installer+xml');
+  fMIMEList.Add('.dll','application/x-msdos-program');
+  fMIMEList.Add('.dmg','application/x-apple-diskimage');
+  fMIMEList.Add('.doc','application/msword');
+  fMIMEList.Add('.dot','application/msword');
+  fMIMEList.Add('.dvi','application/x-dvi');
+  fMIMEList.Add('.dxr','application/x-director');
+  fMIMEList.Add('.ebk','application/x-expandedbook');
+  fMIMEList.Add('.eps','application/postscript');
+  fMIMEList.Add('.evy','application/envoy');
+  fMIMEList.Add('.exe','application/x-msdos-program');
+  fMIMEList.Add('.fdf','application/vnd.fdf');
+  fMIMEList.Add('.fif','application/fractals');
+  fMIMEList.Add('.flm','application/vnd.kde.kivio');
+  fMIMEList.Add('.fml','application/x-file-mirror-list');
+  fMIMEList.Add('.gzip','application/x-gzip');
+  fMIMEList.Add('.gnumeric','application/x-gnumeric');
+  fMIMEList.Add('.gtar','application/x-gtar');
+  fMIMEList.Add('.gz','application/x-gzip');
+  fMIMEList.Add('.hdf','application/x-hdf');
+  fMIMEList.Add('.hlp','application/winhlp');
+  fMIMEList.Add('.hpf','application/x-icq-hpf');
+  fMIMEList.Add('.hqx','application/mac-binhex40');
+  fMIMEList.Add('.hta','application/hta');
+  fMIMEList.Add('.ims','application/vnd.ms-ims');
+  fMIMEList.Add('.ins','application/x-internet-signup');
+  fMIMEList.Add('.iii','application/x-iphone');
+  fMIMEList.Add('.iso','application/x-iso9660-image');
+  fMIMEList.Add('.jar','application/java-archive');
+  fMIMEList.Add('.karbon','application/vnd.kde.karbon');
+  fMIMEList.Add('.kfo','application/vnd.kde.kformula');
+  fMIMEList.Add('.kon','application/vnd.kde.kontour');
+  fMIMEList.Add('.kpr','application/vnd.kde.kpresenter');
+  fMIMEList.Add('.kpt','application/vnd.kde.kpresenter');
+  fMIMEList.Add('.kwd','application/vnd.kde.kword');
+  fMIMEList.Add('.kwt','application/vnd.kde.kword');
+  fMIMEList.Add('.latex','application/x-latex');
+  fMIMEList.Add('.lha','application/x-lzh');
+  fMIMEList.Add('.lcc','application/fastman');
+  fMIMEList.Add('.lrm','application/vnd.ms-lrm');
+  fMIMEList.Add('.lz','application/x-lzip');
+  fMIMEList.Add('.lzh','application/x-lzh');
+  fMIMEList.Add('.lzma','application/x-lzma');
+  fMIMEList.Add('.lzo','application/x-lzop');
+  fMIMEList.Add('.lzx','application/x-lzx');
+  fMIMEList.Add('.m13','application/x-msmediaview');
+  fMIMEList.Add('.m14','application/x-msmediaview');
+  fMIMEList.Add('.mpp','application/vnd.ms-project');
+  fMIMEList.Add('.mvb','application/x-msmediaview');
+  fMIMEList.Add('.man','application/x-troff-man');
+  fMIMEList.Add('.mdb','application/x-msaccess');
+  fMIMEList.Add('.me','application/x-troff-me');
+  fMIMEList.Add('.ms','application/x-troff-ms');
+  fMIMEList.Add('.msi','application/x-msi');
+  fMIMEList.Add('.mpkg','vnd.apple.installer+xml');
+  fMIMEList.Add('.mny','application/x-msmoney');
+  fMIMEList.Add('.nix','application/x-mix-transfer');
+  fMIMEList.Add('.o','application/x-object');
+  fMIMEList.Add('.oda','application/oda');
+  fMIMEList.Add('.odb','application/vnd.oasis.opendocument.database');
+  fMIMEList.Add('.odc','application/vnd.oasis.opendocument.chart');
+  fMIMEList.Add('.odf','application/vnd.oasis.opendocument.formula');
+  fMIMEList.Add('.odg','application/vnd.oasis.opendocument.graphics');
+  fMIMEList.Add('.odi','application/vnd.oasis.opendocument.image');
+  fMIMEList.Add('.odm','application/vnd.oasis.opendocument.text-master');
+  fMIMEList.Add('.odp','application/vnd.oasis.opendocument.presentation');
+  fMIMEList.Add('.ods','application/vnd.oasis.opendocument.spreadsheet');
+  fMIMEList.Add('.ogg','application/ogg');
+  fMIMEList.Add('.odt','application/vnd.oasis.opendocument.text');
+  fMIMEList.Add('.otg','application/vnd.oasis.opendocument.graphics-template');
+  fMIMEList.Add('.oth','application/vnd.oasis.opendocument.text-web');
+  fMIMEList.Add('.otp','application/vnd.oasis.opendocument.presentation-template');
+  fMIMEList.Add('.ots','application/vnd.oasis.opendocument.spreadsheet-template');
+  fMIMEList.Add('.ott','application/vnd.oasis.opendocument.text-template');
+  fMIMEList.Add('.p10','application/pkcs10');
+  fMIMEList.Add('.p12','application/x-pkcs12');
+  fMIMEList.Add('.p7b','application/x-pkcs7-certificates');
+  fMIMEList.Add('.p7m','application/pkcs7-mime');
+  fMIMEList.Add('.p7r','application/x-pkcs7-certreqresp');
+  fMIMEList.Add('.p7s','application/pkcs7-signature');
+  fMIMEList.Add('.package','application/vnd.autopackage');
+  fMIMEList.Add('.pfr','application/font-tdpfr');
+  fMIMEList.Add('.pkg','vnd.apple.installer+xml');
+  fMIMEList.Add('.pdf','application/pdf');
+  fMIMEList.Add('.pko','application/vnd.ms-pki.pko');
+  fMIMEList.Add('.pl','application/x-perl');
+  fMIMEList.Add('.pnq','application/x-icq-pnq');
+  fMIMEList.Add('.pot','application/mspowerpoint');
+  fMIMEList.Add('.pps','application/mspowerpoint');
+  fMIMEList.Add('.ppt','application/mspowerpoint');
+  fMIMEList.Add('.ppz','application/mspowerpoint');
+  fMIMEList.Add('.ps','application/postscript');
+  fMIMEList.Add('.pub','application/x-mspublisher');
+  fMIMEList.Add('.qpw','application/x-quattropro');
+  fMIMEList.Add('.qtl','application/x-quicktimeplayer');
+  fMIMEList.Add('.rar','application/rar');
+  fMIMEList.Add('.rjs','application/vnd.rn-realsystem-rjs');
+  fMIMEList.Add('.rmf','application/vnd.rmf');
+  fMIMEList.Add('.rmp','application/vnd.rn-rn_music_package');
+  fMIMEList.Add('.rmx','application/vnd.rn-realsystem-rmx');
+  fMIMEList.Add('.rnx','application/vnd.rn-realplayer');
+  fMIMEList.Add('.rpm','application/x-redhat-package-manager');
+  fMIMEList.Add('.rsml','application/vnd.rn-rsml');
+  fMIMEList.Add('.rtsp','application/x-rtsp');
+  fMIMEList.Add('.scm','application/x-icq-scm');
+  fMIMEList.Add('.ser','application/java-serialized-object');
+  fMIMEList.Add('.scd','application/x-msschedule');
+  fMIMEList.Add('.sda','application/vnd.stardivision.draw');
+  fMIMEList.Add('.sdc','application/vnd.stardivision.calc');
+  fMIMEList.Add('.sdd','application/vnd.stardivision.impress');
+  fMIMEList.Add('.sdp','application/x-sdp');
+  fMIMEList.Add('.setpay','application/set-payment-initiation');
+  fMIMEList.Add('.setreg','application/set-registration-initiation');
+  fMIMEList.Add('.sh','application/x-sh');
+  fMIMEList.Add('.shar','application/x-shar');
+  fMIMEList.Add('.shw','application/presentations');
+  fMIMEList.Add('.sit','application/x-stuffit');
+  fMIMEList.Add('.sitx','application/x-stuffitx');
+  fMIMEList.Add('.skd','application/x-koan');
+  fMIMEList.Add('.skm','application/x-koan');
+  fMIMEList.Add('.skp','application/x-koan');
+  fMIMEList.Add('.skt','application/x-koan');
+  fMIMEList.Add('.smf','application/vnd.stardivision.math');
+  fMIMEList.Add('.smi','application/smil');
+  fMIMEList.Add('.smil','application/smil');
+  fMIMEList.Add('.spl','application/futuresplash');
+  fMIMEList.Add('.ssm','application/streamingmedia');
+  fMIMEList.Add('.sst','application/vnd.ms-pki.certstore');
+  fMIMEList.Add('.stc','application/vnd.sun.xml.calc.template');
+  fMIMEList.Add('.std','application/vnd.sun.xml.draw.template');
+  fMIMEList.Add('.sti','application/vnd.sun.xml.impress.template');
+  fMIMEList.Add('.stl','application/vnd.ms-pki.stl');
+  fMIMEList.Add('.stw','application/vnd.sun.xml.writer.template');
+  fMIMEList.Add('.svi','application/softvision');
+  fMIMEList.Add('.sv4cpio','application/x-sv4cpio');
+  fMIMEList.Add('.sv4crc','application/x-sv4crc');
+  fMIMEList.Add('.swf','application/x-shockwave-flash');
+  fMIMEList.Add('.swf1','application/x-shockwave-flash');
+  fMIMEList.Add('.sxc','application/vnd.sun.xml.calc');
+  fMIMEList.Add('.sxi','application/vnd.sun.xml.impress');
+  fMIMEList.Add('.sxm','application/vnd.sun.xml.math');
+  fMIMEList.Add('.sxw','application/vnd.sun.xml.writer');
+  fMIMEList.Add('.sxg','application/vnd.sun.xml.writer.global');
+  fMIMEList.Add('.t','application/x-troff');
+  fMIMEList.Add('.tar','application/x-tar');
+  fMIMEList.Add('.tcl','application/x-tcl');
+  fMIMEList.Add('.tex','application/x-tex');
+  fMIMEList.Add('.texi','application/x-texinfo');
+  fMIMEList.Add('.texinfo','application/x-texinfo');
+  fMIMEList.Add('.tbz','application/x-bzip-compressed-tar');
+  fMIMEList.Add('.tbz2','application/x-bzip-compressed-tar');
+  fMIMEList.Add('.tgz','application/x-compressed-tar');
+  fMIMEList.Add('.tlz','application/x-lzma-compressed-tar');
+  fMIMEList.Add('.tr','application/x-troff');
+  fMIMEList.Add('.trm','application/x-msterminal');
+  fMIMEList.Add('.troff','application/x-troff');
+  fMIMEList.Add('.tsp','application/dsptype');
+  fMIMEList.Add('.torrent','application/x-bittorrent');
+  fMIMEList.Add('.ttz','application/t-time');
+  fMIMEList.Add('.txz','application/x-xz-compressed-tar');
+  fMIMEList.Add('.udeb','application/x-debian-package');
+  fMIMEList.Add('.uin','application/x-icq');
+  fMIMEList.Add('.urls','application/x-url-list');
+  fMIMEList.Add('.ustar','application/x-ustar');
+  fMIMEList.Add('.vcd','application/x-cdlink');
+  fMIMEList.Add('.vor','application/vnd.stardivision.writer');
+  fMIMEList.Add('.vsl','application/x-cnet-vsl');
+  fMIMEList.Add('.wcm','application/vnd.ms-works');
+  fMIMEList.Add('.wb1','application/x-quattropro');
+  fMIMEList.Add('.wb2','application/x-quattropro');
+  fMIMEList.Add('.wb3','application/x-quattropro');
+  fMIMEList.Add('.wdb','application/vnd.ms-works');
+  fMIMEList.Add('.wks','application/vnd.ms-works');
+  fMIMEList.Add('.wmd','application/x-ms-wmd');
+  fMIMEList.Add('.wms','application/x-ms-wms');
+  fMIMEList.Add('.wmz','application/x-ms-wmz');
+  fMIMEList.Add('.wp5','application/wordperfect5.1');
+  fMIMEList.Add('.wpd','application/wordperfect');
+  fMIMEList.Add('.wpl','application/vnd.ms-wpl');
+  fMIMEList.Add('.wps','application/vnd.ms-works');
+  fMIMEList.Add('.wri','application/x-mswrite');
+  fMIMEList.Add('.xfdf','application/vnd.adobe.xfdf');
+  fMIMEList.Add('.xls','application/x-msexcel');
+  fMIMEList.Add('.xlb','application/x-msexcel');
+  fMIMEList.Add('.xpi','application/x-xpinstall');
+  fMIMEList.Add('.xps','application/vnd.ms-xpsdocument');
+  fMIMEList.Add('.xsd','application/vnd.sun.xml.draw');
+  fMIMEList.Add('.xul','application/vnd.mozilla.xul+xml');
+  fMIMEList.Add('.z','application/x-compress');
+  fMIMEList.Add('.zoo','application/x-zoo');
+  fMIMEList.Add('.zip','application/x-zip-compressed');
+
+  { WAP }
+  fMIMEList.Add('.wbmp','image/vnd.wap.wbmp');
+  fMIMEList.Add('.wml','text/vnd.wap.wml');
+  fMIMEList.Add('.wmlc','application/vnd.wap.wmlc');
+  fMIMEList.Add('.wmls','text/vnd.wap.wmlscript');
+  fMIMEList.Add('.wmlsc','application/vnd.wap.wmlscriptc');
+
+  { Non-web text}
+  fMIMEList.Add('.asm','text/x-asm');
+  fMIMEList.Add('.p','text/x-pascal');
+  fMIMEList.Add('.pas','text/x-pascal');
+  fMIMEList.Add('.cs','text/x-csharp');
+  fMIMEList.Add('.c','text/x-csrc');
+  fMIMEList.Add('.c++','text/x-c++src');
+  fMIMEList.Add('.cpp','text/x-c++src');
+  fMIMEList.Add('.cxx','text/x-c++src');
+  fMIMEList.Add('.cc','text/x-c++src');
+  fMIMEList.Add('.h','text/x-chdr');
+  fMIMEList.Add('.h++','text/x-c++hdr');
+  fMIMEList.Add('.hpp','text/x-c++hdr');
+  fMIMEList.Add('.hxx','text/x-c++hdr');
+  fMIMEList.Add('.hh','text/x-c++hdr');
+  fMIMEList.Add('.java','text/x-java');
+
+  { WEB }
+  fMIMEList.Add('.css','text/css');
+  fMIMEList.Add('.js','text/javascript');
+  fMIMEList.Add('.htm','text/html');
+  fMIMEList.Add('.html','text/html');
+  fMIMEList.Add('.xhtml','application/xhtml+xml');
+  fMIMEList.Add('.xht','application/xhtml+xml');
+  fMIMEList.Add('.rdf','application/rdf+xml');
+  fMIMEList.Add('.rss','application/rss+xml');
+  fMIMEList.Add('.ls','text/javascript');
+  fMIMEList.Add('.mocha','text/javascript');
+  fMIMEList.Add('.shtml','server-parsed-html');
+  fMIMEList.Add('.sgm','text/sgml');
+  fMIMEList.Add('.sgml','text/sgml');
+
+  { Message }
+  fMIMEList.Add('.mht','message/rfc822');
+end;
+
+function TMIMETypes.GetExtensionMIMEType(const aExtension: string): string;
+begin
+  if not fMIMEList.TryGetValue(aExtension,Result) then Result := 'text/html';
+end;
+
+function TMIMETypes.GetFileMIMEType(const aFilename: string): string;
+begin
+  if not fMIMEList.TryGetValue(ExtractFileExt(aFilename),Result) then Result := 'text/html';
+end;
+
+{ EControlledException }
+
+constructor EControlledException.Create(aCaller: TObject; aMessage: string);
+begin
+  inherited Create(aMessage);
+  fCallerClass := aCaller.ClassType;
+end;
+
+initialization
+  MIMETypes := TMIMETypes.Create;
+
+finalization
+  MIMETypes.Free;
+
+end.

+ 318 - 0
Quick.HttpServer.pas

@@ -0,0 +1,318 @@
+{ ***************************************************************************
+
+  Copyright (c) 2016-2019 Kike Pérez
+
+  Unit        : Quick.HttpServer
+  Description : Http Server
+  Author      : Kike Pérez
+  Version     : 1.8
+  Created     : 30/08/2019
+  Modified    : 16/10/2019
+
+  This file is part of QuickLib: https://github.com/exilon/QuickLib
+
+ ***************************************************************************
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+ *************************************************************************** }
+
+unit Quick.HttpServer;
+
+{$i QuickLib.inc}
+
+interface
+
+uses
+  SysUtils,
+  IdHTTPServer,
+  IdCustomHTTPServer,
+  IdSSLOpenSSL,
+  IdContext,
+  Quick.Commons,
+  Quick.Value,
+  Quick.Logger.Intf,
+  Quick.HttpServer.Types,
+  Quick.HttpServer.Request,
+  Quick.HttpServer.Response;
+
+type
+  EHttpProtocolError = class(Exception);
+
+  TRequestEvent = procedure(aRequest : IHttpRequest; aResponse : IHttpResponse) of object;
+  TOnConnectEvent = procedure of object;
+  TOnDisconnectEvent = procedure of object;
+
+
+  IHttpServer = interface
+  ['{3B48198A-49F7-40A5-BBFD-39C78B6FA1EA}']
+    procedure SetOnRequest(aRequestEvent : TRequestEvent);
+    function GetOnRequest : TRequestEvent;
+    property OnNewRequest : TRequestEvent read GetOnRequest write SetOnRequest;
+    function Logger : ILogger;
+    procedure Start;
+    procedure Stop;
+  end;
+
+  TCustomHttpServer = class(TInterfacedObject,IHttpServer)
+  private
+    fLogger : ILogger;
+    fOnConnect : TOnConnectEvent;
+    fOnDisconnect : TOnDisconnectEvent;
+    procedure SetOnRequest(aRequestEvent : TRequestEvent);
+    function GetOnRequest : TRequestEvent;
+  protected
+    fOnRequest : TRequestEvent;
+    fHost : string;
+    fPort : Integer;
+    fSSLSecured : Boolean;
+  public
+    constructor Create(const aHost : string; aPort : Integer; aSSLEnabled : Boolean; aLogger : ILogger = nil); virtual;
+    property Host : string read fHost;
+    property Port : Integer read fPort;
+    property OnNewRequest : TRequestEvent read GetOnRequest write SetOnRequest;
+    property OnConnect : TOnConnectEvent read fOnConnect write fOnConnect;
+    property OnDisconnect : TOnDisconnectEvent read fOnDisconnect write fOnDisconnect;
+    function Logger : ILogger;
+    procedure Start; virtual; abstract;
+    procedure Stop; virtual; abstract;
+  end;
+
+  THttpServer = class(TCustomHttpServer)
+  private
+    fHTTPServer : TidHTTPServer;
+    procedure OnGetRequest(aContext: TIdContext; aRequestInfo: TIdHTTPRequestInfo; aResponseInfo: TIdHTTPResponseInfo);
+    function GetSSLIOHandler : TIdServerIOHandlerSSLOpenSSL;
+    function OnVerifyPeer(aCertificate: TIdX509; aOk: Boolean; aDepth, aError: Integer): Boolean;
+    function GetRequestInfo(aRequestInfo : TIdHTTPRequestInfo) : THttpRequest;
+    procedure SetResponseInfo(aResponseInfo : TIdHTTPResponseInfo; aResponse : IHttpResponse);
+    procedure DoOnQuerySSLPort(aPort: Word; var vUseSSL: Boolean);
+    procedure DoConnect(aContext: TIdContext);
+    procedure DoDisconnect;
+    procedure OnConnect(aContext: TIdContext);
+    procedure OnDisconnect;
+  protected
+    procedure ProcessRequest(aRequest: IHttpRequest; aResponse: IHttpResponse); virtual;
+  public
+    constructor Create(const aHost : string; aPort : Integer; aSSLEnabled : Boolean; aLogger : ILogger = nil); override;
+    destructor Destroy; override;
+    procedure Start; override;
+    procedure Stop; override;
+  end;
+
+implementation
+
+{ TCustomHttpServer }
+
+constructor TCustomHttpServer.Create(const aHost : string; aPort : Integer; aSSLEnabled : Boolean; aLogger : ILogger = nil);
+begin
+  if aHost.IsEmpty then fHost := '127.0.0.1'
+    else fHost := aHost;
+  fPort := aPort;
+  if aLogger = nil then
+  begin
+    fLogger := TNullLogger.Create;
+  end
+  else fLogger := aLogger;
+  fSSLSecured := aSSLEnabled;
+end;
+
+function TCustomHttpServer.GetOnRequest: TRequestEvent;
+begin
+  Result := fOnRequest;
+end;
+
+procedure TCustomHttpServer.SetOnRequest(aRequestEvent: TRequestEvent);
+begin
+  fOnRequest := aRequestEvent;
+end;
+
+function TCustomHttpServer.Logger: ILogger;
+begin
+  Result := fLogger;
+end;
+
+{ THTTPServer }
+
+constructor THTTPServer.Create(const aHost : string; aPort : Integer; aSSLEnabled : Boolean; aLogger : ILogger = nil);
+begin
+  inherited Create(aHost, aPort, aSSLEnabled, aLogger);
+  Logger.Info('HTTPServer: Indy');
+  fHTTPServer := TIdHTTPServer.Create(nil);
+  fHTTPServer.Bindings.Clear; //make sure there's no other bindings
+  with fHTTPServer.Bindings.Add do
+  begin
+    IP := fHost;
+    Port := fPort;
+  end;
+  if fSSLSecured then fHTTPServer.IOHandler := GetSSLIOHandler;
+  fHTTPServer.OnCommandGet := OnGetRequest;
+  //fHTTPServer.OnExecute := DoConnect;
+  fHTTPServer.OnQuerySSLPort := DoOnQuerySSLPort;
+end;
+
+destructor THTTPServer.Destroy;
+begin
+  if Assigned(fHTTPServer) then
+  begin
+    if Assigned(fHTTPServer.IOHandler) then fHTTPServer.IOHandler.Free;
+    fHTTPServer.Free;
+  end;
+  inherited;
+end;
+
+function THTTPServer.GetSSLIOHandler : TIdServerIOHandlerSSLOpenSSL;
+begin
+  Result := TIdServerIOHandlerSSLOpenSSL.Create(nil);
+  //Result.SSLOptions.RootCertFile := '.\ca.cert.pem';
+  Result.SSLOptions.CertFile := '.\server.cert.pem';
+  Result.SSLOptions.KeyFile := '.\server.key.pem';
+  Result.SSLOptions.Method := sslvSSLv23;
+  Result.SSLOptions.Mode := sslmServer;
+  Result.OnVerifyPeer := OnVerifyPeer;
+end;
+
+function THTTPServer.OnVerifyPeer(aCertificate: TIdX509; aOk: Boolean; aDepth, aError: Integer): Boolean;
+begin
+  Result := aOk;
+end;
+
+function THttpServer.GetRequestInfo(aRequestInfo: TIdHTTPRequestInfo): THttpRequest;
+var
+  i : Integer;
+  uhost : TArray<string>;
+begin
+  Result := THttpRequest.Create;
+  if aRequestInfo.Host.Contains(':') then
+  begin
+    uhost := aRequestInfo.Host.Split([':']);
+    Result.Host := uhost[0];
+    Result.Port := StrToIntDef(uhost[1],80);
+  end
+  else Result.Host := aRequestInfo.Host;
+  Result.URL := aRequestInfo.URI;
+  Result.ClientIP := aRequestInfo.RemoteIP;
+  Result.UnParsedParams := aRequestInfo.QueryParams;
+  Result.SetMethodFromString(aRequestInfo.Command);
+  Result.UserAgent := aRequestInfo.UserAgent;
+  Result.CacheControl := aRequestInfo.CacheControl;
+  Result.Referer := aRequestInfo.Referer;
+  Result.Content := aRequestInfo.PostStream;
+  Result.ContentType := aRequestInfo.ContentType;
+  Result.ContentEncoding := aRequestInfo.ContentEncoding;
+  Result.ContentLength := aRequestInfo.ContentLength;
+  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
+    begin
+      Result.Headers.Add(aRequestInfo.RawHeaders.Names[i],aRequestInfo.RawHeaders.ValueFromIndex[i]);
+    end;
+  end;
+end;
+
+procedure THttpServer.SetResponseInfo(aResponseInfo: TIdHTTPResponseInfo; aResponse: IHttpResponse);
+var
+  pair : TPairItem;
+begin
+  for pair in aResponse.Headers do
+  begin
+    aResponseInfo.CustomHeaders.AddValue(pair.Name,pair.Value);
+  end;
+  aResponseInfo.ResponseNo := aResponse.StatusCode;
+  aResponseInfo.ResponseText := aResponse.StatusText;
+  aResponseInfo.ContentStream := aResponse.Content;
+  aResponseInfo.ContentText := aResponse.ContentText;
+  aResponseInfo.ContentType := aResponse.ContentType;
+  //delegate stream to responseinfo
+  aResponse.Content := nil;
+end;
+
+procedure THttpServer.ProcessRequest(aRequest: IHttpRequest; aResponse: IHttpResponse);
+begin
+  if Assigned(fOnRequest) then fOnRequest(aRequest,aResponse);
+end;
+
+procedure THttpServer.DoConnect(aContext: TIdContext);
+begin
+  if Assigned(fOnConnect) then fOnConnect;
+end;
+
+procedure THttpServer.DoDisconnect;
+begin
+  if Assigned(fOnDisconnect) then fOnDisconnect;
+end;
+
+procedure THTTPServer.DoOnQuerySSLPort(aPort: Word; var vUseSSL: Boolean);
+begin
+  vUseSSL := (aPort <> 443);
+end;
+
+procedure THTTPServer.OnConnect(aContext: TIdContext);
+begin
+  Logger.Debug('Client connected');
+end;
+
+procedure THTTPServer.OnDisconnect;
+begin
+  Logger.Debug('Client disconnected!');
+end;
+
+procedure THTTPServer.OnGetRequest(aContext: TIdContext; aRequestInfo: TIdHTTPRequestInfo; aResponseInfo: TIdHTTPResponseInfo);
+var
+  request : IHttpRequest;
+  response : IHttpResponse;
+begin
+  Logger.Debug('Request: %s',[aRequestInfo.RawHTTPCommand]);
+  request := GetRequestInfo(aRequestInfo);
+  response := THttpResponse.Create;
+  //process incoming Request
+  try
+    ProcessRequest(request,response);
+  except
+    on E : Exception do
+    begin
+      //get unexpected exception
+      if E.ClassType <> EControlledException then
+      begin
+        if response.StatusCode = 200 then
+        begin
+          response.StatusCode := 500;
+          response.StatusText := 'Internal server error';
+        end;
+        response.ContentText := e.Message;
+      end
+      else response.ContentText := response.ContentText + '<BR>' + e.Message;
+    end;
+  end;
+  //check if need return error page
+  if response.StatusCode > 399 then
+  begin
+    response.ContentText := Format('<h2>%d Error: %s</h2>',[response.StatusCode,response.StatusText])
+          + Format('<h4>Message: %s</h4>',[response.ContentText]);
+  end;
+  //return response to client
+  SetResponseInfo(aResponseInfo,response);
+  aResponseInfo.WriteContent;
+end;
+
+procedure THttpServer.Start;
+begin
+  fHTTPServer.Active := True;
+end;
+
+procedure THttpServer.Stop;
+begin
+  fHTTPServer.Active := False;
+end;
+
+end.

+ 570 - 0
Quick.IOC.pas

@@ -0,0 +1,570 @@
+{ ***************************************************************************
+
+  Copyright (c) 2016-2019 Kike Pérez
+
+  Unit        : Quick.IoC
+  Description : IoC Dependency Injector
+  Author      : Kike Pérez
+  Version     : 1.0
+  Created     : 19/10/2019
+  Modified    : 12/11/2019
+
+  This file is part of QuickLib: https://github.com/exilon/QuickLib
+
+ ***************************************************************************
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+ *************************************************************************** }
+
+unit Quick.IoC;
+
+{$i QuickLib.inc}
+
+interface
+
+uses
+  System.SysUtils,
+  RTTI,
+  System.TypInfo,
+  System.Generics.Collections,
+  Quick.Logger.Intf,
+  Quick.Options;
+
+type
+  TActivatorDelegate<T> = reference to function: T;
+
+  TIocRegistration = class
+  type
+    TRegisterMode = (rmTransient, rmSingleton, rmScoped);
+  private
+    fRegisterMode : TRegisterMode;
+    fIntfInfo : PTypeInfo;
+    fImplementation : TClass;
+    fActivatorDelegate : TActivatorDelegate<TValue>;
+  public
+    constructor Create;
+    property IntfInfo : PTypeInfo read fIntfInfo write fIntfInfo;
+    property &Implementation : TClass read fImplementation write fImplementation;
+    function IsSingleton : Boolean;
+    function IsTransient : Boolean;
+    function IsScoped : Boolean;
+    function AsSingleton : TIocRegistration;
+    function AsTransient : TIocRegistration;
+    function AsScoped : TIocRegistration;
+    property ActivatorDelegate : TActivatorDelegate<TValue> read fActivatorDelegate write fActivatorDelegate;
+  end;
+
+  TIocRegistrationInterface = class(TIocRegistration)
+  private
+    fInstance : IInterface;
+  public
+    property Instance : IInterface read fInstance write fInstance;
+  end;
+
+  TIocRegistrationInstance = class(TIocRegistration)
+  private
+    fInstance : TObject;
+  public
+    property Instance : TObject read fInstance write fInstance;
+  end;
+
+  TIocRegistration<T> = record
+  private
+    fRegistration : TIocRegistration;
+  public
+    constructor Create(aRegistration : TIocRegistration);
+    function AsSingleton : TIocRegistration<T>;
+    function AsTransient : TIocRegistration<T>;
+    function AsScoped : TIocRegistration<T>;
+    function DelegateTo(aDelegate : TActivatorDelegate<T>) : TIocRegistration<T>;
+  end;
+
+  IIocRegistrator = interface
+  ['{F3B79B15-2874-4B66-9B7F-06E2EBFED1AE}']
+    function GetKey(aPInfo : PTypeInfo; const aName : string = ''): string;
+    function RegisterType(aTypeInfo : PTypeInfo; aImplementation : TClass; const aName : string = '') : TIocRegistration;
+    function RegisterInstance(aTypeInfo : PTypeInfo; const aName : string = '') : TIocRegistration;
+  end;
+
+  TIocRegistrator = class(TInterfacedObject,IIocRegistrator)
+  private
+    fDependencies : TDictionary<string,TIocRegistration>;
+  public
+    constructor Create;
+    destructor Destroy; override;
+    property Dependencies : TDictionary<string,TIocRegistration> read fDependencies write fDependencies;
+    function GetKey(aPInfo : PTypeInfo; const aName : string = ''): string;
+    function RegisterType<TInterface: IInterface; TImplementation: class>(const aName : string = '') : TIocRegistration<TImplementation>; overload;
+    function RegisterType(aTypeInfo : PTypeInfo; aImplementation : TClass; const aName : string = '') : TIocRegistration; overload;
+    function RegisterInstance(aTypeInfo : PTypeInfo; const aName : string = '') : TIocRegistration; overload;
+    function RegisterInstance<T : class>(const aName : string = '') : TIocRegistration<T>; overload;
+    function RegisterOptions<T : TOptions>(aOptions : T) : TIocRegistration<T>;
+  end;
+
+  IIocContainer = interface
+  ['{6A486E3C-C5E8-4BE5-8382-7B9BCCFC1BC3}']
+    function RegisterType(aInterface: PTypeInfo; aImplementation : TClass; const aName : string = '') : TIocRegistration;
+    function RegisterInstance(aTypeInfo : PTypeInfo; const aName : string = '') : TIocRegistration;
+    function Resolve(aServiceType: PTypeInfo; const aName : string = ''): TValue;
+    //procedure Build;
+  end;
+
+  IIocInjector = interface
+  ['{F78E6BBC-2A95-41C9-B231-D05A586B4B49}']
+  end;
+
+  TIocInjector = class(TInterfacedObject,IIocInjector)
+  end;
+
+  IIocResolver = interface
+  ['{B7C07604-B862-46B2-BF33-FF941BBE53CA}']
+    function Resolve(aServiceType: PTypeInfo; const aName : string = ''): TValue; overload;
+  end;
+
+  TIocResolver = class(TInterfacedObject,IIocResolver)
+  private
+    fRegistrator : TIocRegistrator;
+    fInjector : TIocInjector;
+    function CreateInstance(aClass : TClass) : TValue;
+  public
+    constructor Create(aRegistrator : TIocRegistrator; aInjector : TIocInjector);
+    function Resolve<T>(const aName : string = ''): T; overload;
+    function Resolve(aServiceType: PTypeInfo; const aName : string = ''): TValue; overload;
+  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
+    class constructor Create;
+    class destructor Destroy;
+  public
+    constructor Create;
+    destructor Destroy; override;
+    function RegisterType<TInterface: IInterface; TImplementation: class>(const aName : string = '') : TIocRegistration<TImplementation>; overload;
+    function RegisterType(aInterface: PTypeInfo; aImplementation : TClass; const aName : string = '') : TIocRegistration; overload;
+    function RegisterInstance<T : class>(const aName: string = ''): TIocRegistration<T>; overload;
+    function RegisterInstance(aTypeInfo : PTypeInfo; const aName : string = '') : TIocRegistration; overload;
+    function RegisterOptions<T : TOptions>(aOptions : TOptions) : TIocRegistration<T>;
+    function Resolve<T>(const aName : string = ''): T; overload;
+    function Resolve(aServiceType: PTypeInfo; const aName : string = ''): TValue; overload;
+    function AbstractFactory<T : class, constructor>(aClass : TClass) : T;
+  end;
+
+  EIocRegisterError = class(Exception);
+  EIocResolverError = class(Exception);
+
+  //singleton global instance
+  function GlobalContainer: TIocContainer;
+
+implementation
+
+function GlobalContainer: TIocContainer;
+begin
+  Result := TIocContainer.GlobalInstance;
+end;
+
+{ TIocRegistration }
+
+constructor TIocRegistration.Create;
+begin
+  fRegisterMode := TRegisterMode.rmTransient;
+end;
+
+function TIocRegistration.AsTransient: TIocRegistration;
+begin
+  Result := Self;
+  fRegisterMode := TRegisterMode.rmTransient;
+end;
+
+function TIocRegistration.AsSingleton : TIocRegistration;
+begin
+  Result := Self;
+  fRegisterMode := TRegisterMode.rmSingleton;
+end;
+
+function TIocRegistration.AsScoped: TIocRegistration;
+begin
+  Result := Self;
+  fRegisterMode := TRegisterMode.rmScoped;
+end;
+
+function TIocRegistration.IsTransient: Boolean;
+begin
+  Result := fRegisterMode = TRegisterMode.rmTransient;
+end;
+
+function TIocRegistration.IsSingleton: Boolean;
+begin
+  Result := fRegisterMode = TRegisterMode.rmSingleton;
+end;
+
+function TIocRegistration.IsScoped: Boolean;
+begin
+  Result := fRegisterMode = TRegisterMode.rmScoped;
+end;
+
+{ TIocContainer }
+
+class constructor TIocContainer.Create;
+begin
+  GlobalInstance := TIocContainer.Create;
+end;
+
+class destructor TIocContainer.Destroy;
+begin
+  if GlobalInstance <> nil then GlobalInstance.Free;
+  inherited;
+end;
+
+function TIocContainer.AbstractFactory<T>(aClass: TClass): T;
+begin
+  Result := fResolver.CreateInstance(aClass).AsType<T>;
+end;
+
+constructor TIocContainer.Create;
+begin
+  fLogger := nil;
+  fRegistrator := TIocRegistrator.Create;
+  fInjector := TIocInjector.Create;
+  fResolver := TIocResolver.Create(fRegistrator,fInjector);
+end;
+
+destructor TIocContainer.Destroy;
+begin
+  fInjector.Free;
+  fResolver.Free;
+  fRegistrator.Free;
+  inherited;
+end;
+
+function TIocContainer.InterfaceTypeInfo(const AGUID : TGUID) : PTypeInfo;
+var
+  ctx : TRttiContext;
+  rtype : TRttiType;
+  rtypei : TRttiInterfaceType;
+begin
+  ctx := TRttiContext.Create;
+  try
+    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;
+  finally
+    ctx.Free;
+  end;
+  Result := nil;
+end;
+
+function TIocContainer.RegisterType<TInterface, TImplementation>(const aName: string): TIocRegistration<TImplementation>;
+begin
+  Result := fRegistrator.RegisterType<TInterface, TImplementation>(aName);
+end;
+
+function TIocContainer.RegisterType(aInterface: PTypeInfo; aImplementation: TClass; const aName: string): TIocRegistration;
+begin
+  Result := fRegistrator.RegisterType(aInterface,aImplementation,aName);
+end;
+
+function TIocContainer.RegisterInstance<T>(const aName: string): TIocRegistration<T>;
+begin
+  Result := fRegistrator.RegisterInstance<T>(aName);
+end;
+
+function TIocContainer.RegisterInstance(aTypeInfo : PTypeInfo; const aName : string = '') : TIocRegistration;
+begin
+  Result := fRegistrator.RegisterInstance(aTypeInfo,aName);
+end;
+
+function TIocContainer.RegisterOptions<T>(aOptions: TOptions): TIocRegistration<T>;
+begin
+  Result := fRegistrator.RegisterOptions<T>(aOptions).AsSingleton;
+end;
+
+function TIocContainer.Resolve(aServiceType: PTypeInfo; const aName: string): TValue;
+begin
+  Result := fResolver.Resolve(aServiceType,aName);
+end;
+
+function TIocContainer.Resolve<T>(const aName : string = ''): T;
+begin
+  Result := fResolver.Resolve<T>(aName);
+end;
+
+{ TIocRegistrator }
+
+constructor TIocRegistrator.Create;
+begin
+  fDependencies := TDictionary<string,TIocRegistration>.Create;
+end;
+
+destructor TIocRegistrator.Destroy;
+var
+  reg : TIocRegistration;
+begin
+  for reg in fDependencies.Values do
+  begin
+    if reg <> nil then
+    begin
+      //free singleton instances not interfaced
+      if (reg is TIocRegistrationInstance) and (TIocRegistrationInstance(reg).IsSingleton) then TIocRegistrationInstance(reg).Instance.Free;
+      reg.Free;
+    end;
+  end;
+  fDependencies.Free;
+  inherited;
+end;
+
+function TIocRegistrator.GetKey(aPInfo : PTypeInfo; const aName : string = ''): string;
+begin
+  {$IFDEF NEXTGEN}
+  Result := aPInfo.Name.ToString;
+  {$ELSE}
+  Result := string(aPInfo.Name);
+  {$ENDIF}
+  if not aName.IsEmpty then Result := Result + '.' + aName.ToLower;
+end;
+
+function TIocRegistrator.RegisterInstance<T>(const aName: string): TIocRegistration<T>;
+var
+  reg : TIocRegistration;
+begin
+  reg := RegisterInstance(TypeInfo(T),aName);
+  Result := TIocRegistration<T>.Create(reg);
+end;
+
+function TIocRegistrator.RegisterInstance(aTypeInfo : PTypeInfo; const aName : string = '') : TIocRegistration;
+var
+  key : string;
+begin
+  key := GetKey(aTypeInfo,aName);
+  if fDependencies.TryGetValue(key,Result) then
+  begin
+    if Result.&Implementation = aTypeInfo.TypeData.ClassType then raise EIocRegisterError.Create('Implementation is already registered!');
+  end
+  else
+  begin
+    Result := TIocRegistrationInstance.Create;
+    Result.IntfInfo := aTypeInfo;
+    Result.&Implementation := aTypeInfo.TypeData.ClassType;
+    //reg.Instance := T.Create;
+    fDependencies.Add(key,Result);
+  end;
+end;
+
+function TIocRegistrator.RegisterOptions<T>(aOptions: T): TIocRegistration<T>;
+var
+  pInfo : PTypeInfo;
+  key : string;
+  reg : TIocRegistration;
+begin
+  pInfo := TypeInfo(IOptions<T>);
+  key := GetKey(pInfo,'');
+  if fDependencies.TryGetValue(key,reg) then
+  begin
+    if reg.&Implementation = aOptions.ClassType then raise EIocRegisterError.Create('Implementation for this interface is already registered!');
+  end
+  else
+  begin
+    reg := TIocRegistrationInterface.Create;
+    reg.IntfInfo := pInfo;
+    reg.&Implementation := aOptions.ClassType;
+    TIocRegistrationInterface(reg).Instance := TOptionValue<T>.Create(aOptions);
+    fDependencies.Add(key,reg);
+  end;
+  Result := TIocRegistration<T>.Create(reg);
+end;
+
+function TIocRegistrator.RegisterType<TInterface, TImplementation>(const aName: string): TIocRegistration<TImplementation>;
+var
+  reg : TIocRegistration;
+begin
+  reg := RegisterType(TypeInfo(TInterface),TImplementation,aName);
+  Result := TIocRegistration<TImplementation>.Create(reg);
+end;
+
+function TIocRegistrator.RegisterType(aTypeInfo : PTypeInfo; aImplementation : TClass; const aName : string = '') : TIocRegistration;
+var
+  key : string;
+begin
+  key := GetKey(aTypeInfo,aName);
+  if fDependencies.TryGetValue(key,Result) then
+  begin
+    if Result.&Implementation = aImplementation then raise EIocRegisterError.Create('Implementation for this interface is already registered!');
+  end
+  else
+  begin
+    Result := TIocRegistrationInterface.Create;
+    Result.IntfInfo := aTypeInfo;
+    Result.&Implementation := aImplementation;
+    fDependencies.Add(key,Result);
+  end;
+end;
+
+{ TIocResolver }
+
+constructor TIocResolver.Create(aRegistrator : TIocRegistrator; aInjector : TIocInjector);
+begin
+  fRegistrator := aRegistrator;
+  fInjector := aInjector;
+end;
+
+function TIocResolver.CreateInstance(aClass: TClass): TValue;
+var
+  ctx : TRttiContext;
+  rtype : TRttiType;
+  rmethod : TRttiMethod;
+  rParam : TRttiParameter;
+  value : TValue;
+  values : TArray<TValue>;
+begin
+  Result := nil;
+  ctx := TRttiContext.Create;
+  try
+    rtype := ctx.GetType(aClass);
+    if rtype = nil then Exit;
+    for rmethod in TRttiInstanceType(rtype).GetMethods do
+    begin
+      if rmethod.IsConstructor then
+      begin
+        //if create don't have parameters
+        if Length(rmethod.GetParameters) = 0 then
+        begin
+          Result := rmethod.Invoke(TRttiInstanceType(rtype).MetaclassType,[]);
+          Break;
+        end
+        else
+        begin
+          for rParam in rmethod.GetParameters do
+          begin
+            value := Resolve(rParam.ParamType.Handle);
+            values := values + [value];
+          end;
+          Result := rmethod.Invoke(TRttiInstanceType(rtype).MetaclassType,values);
+          Break;
+        end;
+      end;
+    end;
+  finally
+    ctx.Free;
+  end;
+end;
+
+function TIocResolver.Resolve(aServiceType: PTypeInfo; const aName : string = ''): TValue;
+var
+  key : string;
+  reg : TIocRegistration;
+  intf : IInterface;
+begin
+  Result := nil;
+  reg := nil;
+  key := fRegistrator.GetKey(aServiceType,aName);
+  if not fRegistrator.Dependencies.TryGetValue(key,reg) then raise EIocResolverError.CreateFmt('Type "%s" not register for IOC!',[aServiceType.Name]);
+  //if is singleton return already instance if exists
+  if reg.IsSingleton then
+  begin
+    if reg is TIocRegistrationInterface then
+    begin
+      if TIocRegistrationInterface(reg).Instance <> nil then
+      begin
+        if TIocRegistrationInterface(reg).Instance.QueryInterface(GetTypeData(aServiceType).Guid,intf) <> 0 then raise EIocResolverError.CreateFmt('Implementation for "%s" not registered!',[aServiceType.Name]);
+        TValue.Make(@intf,aServiceType,Result);
+        Exit;
+      end;
+    end
+    else
+    begin
+      if TIocRegistrationInstance(reg).Instance <> nil then
+      begin
+        Result := TIocRegistrationInstance(reg).Instance;
+        Exit;
+      end;
+    end;
+  end;
+  //instance not created yet
+  if reg.&Implementation = nil then raise EIocResolverError.CreateFmt('Implemention for "%s" not defined!',[aServiceType.Name]);
+  //use activator if assigned
+  if reg is TIocRegistrationInterface then
+  begin
+    if Assigned(reg.ActivatorDelegate) then TIocRegistrationInterface(reg).Instance := reg.ActivatorDelegate().AsInterface
+      else TIocRegistrationInterface(reg).Instance := CreateInstance(reg.&Implementation).AsInterface;
+    if (TIocRegistrationInterface(reg).Instance = nil) or (TIocRegistrationInterface(reg).Instance.QueryInterface(GetTypeData(aServiceType).Guid,intf) <> 0) then raise EIocResolverError.CreateFmt('Implementation for "%s" not registered!',[aServiceType.Name]);
+    TValue.Make(@intf,aServiceType,Result);
+  end
+  else
+  begin
+    if Assigned(reg.ActivatorDelegate) then TIocRegistrationInstance(reg).Instance := reg.ActivatorDelegate().AsObject
+    else
+    begin
+      TIocRegistrationInstance(reg).Instance := CreateInstance(reg.&Implementation).AsObject;
+    end;
+    Result := TIocRegistrationInstance(reg).Instance;
+  end;
+end;
+
+function TIocResolver.Resolve<T>(const aName : string = ''): T;
+var
+  pInfo : PTypeInfo;
+begin
+  Result := Default(T);
+  pInfo := TypeInfo(T);
+
+  Result := Resolve(pInfo,aName).AsType<T>;
+end;
+
+{ TIocRegistration<T> }
+
+function TIocRegistration<T>.AsScoped: TIocRegistration<T>;
+begin
+  Result := Self;
+  fRegistration.AsScoped;
+end;
+
+function TIocRegistration<T>.AsSingleton: TIocRegistration<T>;
+begin
+  Result := Self;
+  fRegistration.AsSingleton;
+end;
+
+function TIocRegistration<T>.AsTransient: TIocRegistration<T>;
+begin
+  Result := Self;
+  fRegistration.AsTransient;
+end;
+
+constructor TIocRegistration<T>.Create(aRegistration: TIocRegistration);
+begin
+  fRegistration := aRegistration;
+end;
+
+function TIocRegistration<T>.DelegateTo(aDelegate: TActivatorDelegate<T>): TIocRegistration<T>;
+begin
+  Result := Self;
+  fRegistration.ActivatorDelegate := function: TValue
+                                     begin
+                                       Result := TValue.From<T>(aDelegate);
+                                     end;
+end;
+
+end.

+ 193 - 28
Quick.Json.Serializer.pas

@@ -5,9 +5,9 @@
   Unit        : Quick.JSON.Serializer
   Unit        : Quick.JSON.Serializer
   Description : Json Serializer
   Description : Json Serializer
   Author      : Kike Pérez
   Author      : Kike Pérez
-  Version     : 1.8
+  Version     : 1.10
   Created     : 21/05/2018
   Created     : 21/05/2018
-  Modified    : 12/04/2019
+  Modified    : 10/11/2019
 
 
   This file is part of QuickLib: https://github.com/exilon/QuickLib
   This file is part of QuickLib: https://github.com/exilon/QuickLib
 
 
@@ -53,6 +53,7 @@ uses
     {$IFDEF DELPHIRX103_UP}
     {$IFDEF DELPHIRX103_UP}
     System.Generics.Collections,
     System.Generics.Collections,
     {$ENDIF}
     {$ENDIF}
+    Variants,
   {$ENDIF}
   {$ENDIF}
   DateUtils,
   DateUtils,
   Quick.Commons,
   Quick.Commons,
@@ -88,6 +89,7 @@ type
     function JsonToObject(aType: TClass; const aJson: string): TObject; overload;
     function JsonToObject(aType: TClass; const aJson: string): TObject; overload;
     function JsonToObject(aObject: TObject; const aJson: string): TObject; overload;
     function JsonToObject(aObject: TObject; const aJson: string): TObject; overload;
     function ObjectToJson(aObject : TObject; aIndent : Boolean = False): string;
     function ObjectToJson(aObject : TObject; aIndent : Boolean = False): string;
+    function ValueToJson(aValue : TValue; aIndent : Boolean = False) : string;
   end;
   end;
 
 
   TSerializeLevel = (slPublicProperty, slPublishedProperty);
   TSerializeLevel = (slPublicProperty, slPublishedProperty);
@@ -143,6 +145,7 @@ type
     function Serialize(const aName : string; aValue : TValue) : TJSONPair;
     function Serialize(const aName : string; aValue : TValue) : TJSONPair;
     {$ENDIF}
     {$ENDIF}
     function Serialize(aObject : TObject) : TJSONObject; overload;
     function Serialize(aObject : TObject) : TJSONObject; overload;
+    function GetJsonPairValueByName(aJson : TJSONObject; const aName : string) : TJsonValue;
     function GetJsonPairByName(aJson : TJSONObject; const aName : string) : TJSONPair;
     function GetJsonPairByName(aJson : TJSONObject; const aName : string) : TJSONPair;
   end;
   end;
 
 
@@ -165,6 +168,13 @@ type
     function JsonToObject(aObject : TObject; const aJson: string) : TObject; overload;
     function JsonToObject(aObject : TObject; const aJson: string) : TObject; overload;
     function ObjectToJson(aObject : TObject; aIndent : Boolean = False): string;
     function ObjectToJson(aObject : TObject; aIndent : Boolean = False): string;
     function ObjectToJsonString(aObject : TObject; aIndent : Boolean = False): string;
     function ObjectToJsonString(aObject : TObject; aIndent : Boolean = False): string;
+    function ValueToJson(aValue : TValue; aIndent : Boolean = False) : string;
+    function ValueToJsonString(aValue : TValue; aIndent : Boolean = False) : string;
+    function ArrayToJson<T>(aArray : TArray<T>; aIndent : Boolean = False) : string;
+    function ArrayToJsonString<T>(aArray : TArray<T>; aIndent : Boolean = False) : string;
+    {$IFNDEF FPC}
+    function JsonToArray<T>(const aJson : string) : TArray<T>;
+    {$ENDIF}
   end;
   end;
 
 
   PPByte = ^PByte;
   PPByte = ^PByte;
@@ -315,7 +325,7 @@ var
   rRec : TRttiRecordType;
   rRec : TRttiRecordType;
   rField : TRttiField;
   rField : TRttiField;
   rValue : TValue;
   rValue : TValue;
-  member : TJSONPair;
+  member : TJsonValue;
   jArray : TJSONArray;
   jArray : TJSONArray;
   json : TJSONObject;
   json : TJSONObject;
   objClass : TClass;
   objClass : TClass;
@@ -327,7 +337,7 @@ begin
     begin
     begin
       rValue := nil;
       rValue := nil;
       //member := TJSONPair(aJson.GetValue(rField.Name));
       //member := TJSONPair(aJson.GetValue(rField.Name));
-      member := GetJsonPairByName(aJson,rField.Name);
+      member := GetJsonPairValueByName(aJson,rField.Name);
       if member <> nil then
       if member <> nil then
       case rField.FieldType.TypeKind of
       case rField.FieldType.TypeKind of
         tkDynArray :
         tkDynArray :
@@ -480,7 +490,7 @@ var
   ctx : TRttiContext;
   ctx : TRttiContext;
   rType : TRttiType;
   rType : TRttiType;
   jarray : TJSONArray;
   jarray : TJSONArray;
-  member : TJSONPair;
+  member : TJsonValue;
   rvalue : TValue;
   rvalue : TValue;
   i : Integer;
   i : Integer;
   rProp : TRttiProperty;
   rProp : TRttiProperty;
@@ -498,7 +508,7 @@ begin
     ctx.Free;
     ctx.Free;
   end;
   end;
 
 
-  member := GetJsonPairByName(aJson,aName);
+  member := GetJsonPairValueByName(aJson,aName);
   if member = nil then jArray := TJSONObject.ParseJSONValue(aJson.ToJSON) as TJSONArray
   if member = nil then jArray := TJSONObject.ParseJSONValue(aJson.ToJSON) as TJSONArray
     else jArray := TJSONObject.ParseJSONValue(member.ToJSON) as TJSONArray;
     else jArray := TJSONObject.ParseJSONValue(member.ToJSON) as TJSONArray;
   try
   try
@@ -546,7 +556,7 @@ var
   rRec : TRttiRecordType;
   rRec : TRttiRecordType;
   rfield : TRttiField;
   rfield : TRttiField;
   rValue : TValue;
   rValue : TValue;
-  member : TJSONPair;
+  member : TJsonValue;
   jArray : TJSONArray;
   jArray : TJSONArray;
 begin
 begin
   rRec := ctx.GetType(aRecord.TypeInfo).AsRecord;
   rRec := ctx.GetType(aRecord.TypeInfo).AsRecord;
@@ -556,7 +566,7 @@ begin
     begin
     begin
       rValue := nil;
       rValue := nil;
       //member := TJSONPair(aJson.GetValue(rField.Name));
       //member := TJSONPair(aJson.GetValue(rField.Name));
-      member := GetJsonPairByName(aJson,aPropertyName);
+      member := GetJsonPairValueByName(aJson,aPropertyName);
       if (member <> nil) and (rField.FieldType.TypeKind = tkDynArray) then
       if (member <> nil) and (rField.FieldType.TypeKind = tkDynArray) then
       begin
       begin
         jArray := TJSONObject.ParseJSONValue(member.ToJSON) as TJSONArray;
         jArray := TJSONObject.ParseJSONValue(member.ToJSON) as TJSONArray;
@@ -579,7 +589,7 @@ function TRTTIJson.DeserializeProperty(aObject : TObject; const aName : string;
 var
 var
   rValue : TValue;
   rValue : TValue;
   {$IFNDEF FPC}
   {$IFNDEF FPC}
-  member : TJSONPair;
+  member : TJsonValue;
   {$ELSE}
   {$ELSE}
   member : TJsonObject;
   member : TJsonObject;
   {$ENDIF}
   {$ENDIF}
@@ -591,7 +601,7 @@ begin
     rValue := nil;
     rValue := nil;
     {$IFNDEF FPC}
     {$IFNDEF FPC}
      //member := TJSONPair(aJson.GetValue(aName));
      //member := TJSONPair(aJson.GetValue(aName));
-     member := GetJsonPairByName(aJson,aName);
+     member := GetJsonPairValueByName(aJson,aName);
     {$ELSE}
     {$ELSE}
     member := TJsonObject(aJson.Find(aName));
     member := TJsonObject(aJson.Find(aName));
     {$ENDIF}
     {$ENDIF}
@@ -866,14 +876,14 @@ begin
   Result := aClassName.StartsWith('TXArray');
   Result := aClassName.StartsWith('TXArray');
 end;
 end;
 
 
-function TRTTIJson.GetJsonPairByName(aJson: TJSONObject; const aName: string): TJSONPair;
+function TRTTIJson.GetJsonPairValueByName(aJson: TJSONObject; const aName: string): TJsonValue;
 var
 var
   candidate : TJSONPair;
   candidate : TJSONPair;
   i : Integer;
   i : Integer;
 begin
 begin
   if fUseJsonCaseSense then
   if fUseJsonCaseSense then
   begin
   begin
-    Result := TJSONPair(aJson.GetValue(aName));
+    Result := aJson.GetValue(aName);
     Exit;
     Exit;
   end
   end
   else
   else
@@ -883,7 +893,28 @@ begin
       candidate := aJson.Pairs[I];
       candidate := aJson.Pairs[I];
       if candidate.JsonValue = nil then Exit(nil);
       if candidate.JsonValue = nil then Exit(nil);
       if CompareText(candidate.JsonString{$IFNDEF FPC}.Value{$ENDIF},aName) = 0 then
       if CompareText(candidate.JsonString{$IFNDEF FPC}.Value{$ENDIF},aName) = 0 then
-        Exit(TJsonPair(candidate.JsonValue));
+        Exit(candidate.JsonValue);
+    end;
+  end;
+  Result := nil;
+end;
+
+function TRTTIJson.GetJsonPairByName(aJson: TJSONObject; const aName: string): TJSONPair;
+var
+  i : Integer;
+begin
+  if fUseJsonCaseSense then
+  begin
+    Result := TJSONPair(aJson.GetValue(aName));
+    Exit;
+  end
+  else
+  begin
+    for i := 0 to aJson.Count - 1 do
+    begin
+      Result := aJson.Pairs[I];
+      if Result.JsonValue = nil then Exit(nil);
+      if CompareText(Result.JsonString{$IFNDEF FPC}.Value{$ENDIF},aName) = 0 then Exit;
     end;
     end;
   end;
   end;
   Result := nil;
   Result := nil;
@@ -1032,10 +1063,7 @@ var
   jpair : TJSONPair;
   jpair : TJSONPair;
   ExcludeSerialize : Boolean;
   ExcludeSerialize : Boolean;
   propertyname : string;
   propertyname : string;
-
-  //listtype : TRttiType;
-  //listprop : TRttiProperty;
-  //listvalue : TValue;
+  propvalue : TValue;
 begin
 begin
   if (aObject = nil) then
   if (aObject = nil) then
   begin
   begin
@@ -1071,20 +1099,21 @@ begin
             if comment <> '' then Result.AddPair(TJSONPair.Create('#Comment#->'+propertyname,Comment));
             if comment <> '' then Result.AddPair(TJSONPair.Create('#Comment#->'+propertyname,Comment));
             {$ENDIF}
             {$ENDIF}
             begin
             begin
-              if (rProp.GetValue(aObject).IsObject) and (IsGenericList(rProp.GetValue(aObject).AsObject)) then
+              propvalue := rProp.GetValue(aObject);
+              if (propvalue.IsObject) and (IsGenericList(propvalue.AsObject)) then
               begin
               begin
-                jpair := Serialize(propertyname,GetPropertyValueFromObject(rProp.GetValue(aObject).AsObject,'List'));
+                jpair := Serialize(propertyname,GetPropertyValueFromObject(propvalue.AsObject,'List'));
               end
               end
               {$IFNDEF FPC}
               {$IFNDEF FPC}
-              else if (not rProp.GetValue(aObject).IsObject) and (IsGenericXArray(rProp.GetValue(aObject){$IFNDEF NEXTGEN}.TypeInfo.Name{$ELSE}.TypeInfo.NameFld.ToString{$ENDIF})) then
+              else if (not propvalue.IsObject) and (IsGenericXArray(propvalue{$IFNDEF NEXTGEN}.TypeInfo.Name{$ELSE}.TypeInfo.NameFld.ToString{$ENDIF})) then
               begin
               begin
-                jpair := Serialize(propertyname,GetFieldValueFromRecord(rProp.GetValue(aObject),'fArray'));
+                jpair := Serialize(propertyname,GetFieldValueFromRecord(propvalue,'fArray'));
               end
               end
               {$ENDIF}
               {$ENDIF}
               else
               else
               begin
               begin
                 {$IFNDEF FPC}
                 {$IFNDEF FPC}
-                jpair := Serialize(propertyname,rProp.GetValue(aObject));
+                jpair := Serialize(propertyname,propvalue);
                 {$ELSE}
                 {$ELSE}
                 jpair := Serialize(aObject,rProp.PropertyType.TypeKind,propertyname);
                 jpair := Serialize(aObject,rProp.PropertyType.TypeKind,propertyname);
                 {$ENDIF}
                 {$ENDIF}
@@ -1245,6 +1274,14 @@ begin
             ctx.Free;
             ctx.Free;
           end;
           end;
         end;
         end;
+      tkVariant :
+        begin
+          case VarType(aValue.AsVariant) and VarTypeMask of
+            varInteger, varInt64 : Result.JsonValue := TJSONNumber.Create(aValue.AsInteger);
+            varString, varUString, varEmpty : Result.JsonValue := TJSONString.Create(aValue.AsString);
+            varDouble : Result.JsonValue := TJSONNumber.Create(aValue.AsExtended);
+          end;
+        end;
       tkMethod, tkPointer, tkClassRef ,tkInterface, tkProcedure :
       tkMethod, tkPointer, tkClassRef ,tkInterface, tkProcedure :
         begin
         begin
           //skip these properties
           //skip these properties
@@ -1516,6 +1553,12 @@ begin
   fRTTIJson.UseJsonCaseSense := fUseJsonCaseSense;
   fRTTIJson.UseJsonCaseSense := fUseJsonCaseSense;
 end;
 end;
 
 
+destructor TJsonSerializer.Destroy;
+begin
+  fRTTIJson.Free;
+  inherited;
+end;
+
 function TJsonSerializer.JsonToObject(aType: TClass; const aJson: string): TObject;
 function TJsonSerializer.JsonToObject(aType: TClass; const aJson: string): TObject;
 var
 var
   json: TJSONObject;
   json: TJSONObject;
@@ -1532,12 +1575,6 @@ begin
   end;
   end;
 end;
 end;
 
 
-destructor TJsonSerializer.Destroy;
-begin
-  fRTTIJson.Free;
-  inherited;
-end;
-
 function TJsonSerializer.JsonToObject(aObject: TObject; const aJson: string): TObject;
 function TJsonSerializer.JsonToObject(aObject: TObject; const aJson: string): TObject;
 var
 var
   json: TJSONObject;
   json: TJSONObject;
@@ -1580,6 +1617,134 @@ begin
   end;
   end;
 end;
 end;
 
 
+{$IFNDEF FPC}
+function TJsonSerializer.ValueToJson(aValue: TValue; aIndent: Boolean): string;
+var
+  json: TJSONObject;
+begin
+  json := TJSONObject.Create.AddPair(fRTTIJson.Serialize('value',aValue));
+  try
+    if aIndent then Result := TJsonUtils.JsonFormat(json.P['value'].ToJSON)
+      else Result := json.P['value'].ToJSON;
+  finally
+    json.Free;
+  end;
+end;
+
+function TJsonSerializer.ValueToJsonString(aValue: TValue; aIndent: Boolean): string;
+var
+  json: TJSONObject;
+begin
+  json := TJSONObject.Create.AddPair(fRTTIJson.Serialize('value',aValue));
+  try
+    if aIndent then Result := TJsonUtils.JsonFormat(json.P['value'].ToString)
+      else  Result := json.P['value'].ToString;
+  finally
+    json.Free;
+  end;
+end;
+
+function TJsonSerializer.ArrayToJson<T>(aArray: TArray<T>; aIndent: Boolean): string;
+var
+  json: TJSONObject;
+begin
+  json := TJSONObject.Create.AddPair(fRTTIJson.Serialize('array',TValue.From<TArray<T>>(aArray)));
+  try
+    if aIndent then Result := TJsonUtils.JsonFormat(json.P['array'].ToJSON)
+      else Result := json.P['array'].ToJSON;
+  finally
+    json.Free;
+  end;
+end;
+
+function TJsonSerializer.ArrayToJsonString<T>(aArray: TArray<T>; aIndent: Boolean): string;
+var
+  json: TJSONObject;
+begin
+  json := TJSONObject.Create.AddPair(fRTTIJson.Serialize('array',TValue.From<TArray<T>>(aArray)));
+  try
+    if aIndent then Result := TJsonUtils.JsonFormat(json.P['array'].ToString)
+      else Result := json.P['array'].ToString;
+  finally
+    json.Free;
+  end;
+end;
+
+function TJsonSerializer.JsonToArray<T>(const aJson: string): TArray<T>;
+var
+  jarray: TJSONArray;
+  value : TValue;
+begin;
+  {$If Defined(FPC) OR Defined(DELPHIRX10_UP)}
+  jarray := TJSONObject.ParseJSONValue(aJson,True) as TJSONArray;
+  {$ELSE}
+  jarray := TJsonObject.ParseJSONValue(TEncoding.UTF8.GetBytes(aJson),0,True) as TJSONArray;
+  {$ENDIF}
+  try
+    value := fRTTIJson.DeserializeDynArray(PTypeInfo(TypeInfo(TArray<T>)),nil,jarray);
+    Result := value.AsType<TArray<T>>;
+  finally
+    jarray.Free;
+  end;
+end;
+{$ELSE}
+function TJsonSerializer.ValueToJson(aValue: TValue; aIndent: Boolean): string;
+var
+  json: TJSONObject;
+begin
+  json := TJSONObject.Create;
+  json.AddPair(fRTTIJson.Serialize('value',aValue));
+  try
+    if aIndent then Result := TJsonUtils.JsonFormat(json.Get('value').ToJSON)
+      else Result := json.Get('value').ToJSON;
+  finally
+    json.Free;
+  end;
+end;
+
+function TJsonSerializer.ValueToJsonString(aValue: TValue; aIndent: Boolean): string;
+var
+  json: TJSONObject;
+begin
+  json := TJSONObject.Create;
+  json.AddPair(fRTTIJson.Serialize('value',aValue));
+  try
+    if aIndent then Result := TJsonUtils.JsonFormat(json.Get('value').ToString)
+      else  Result := json.Get('value').ToString;
+  finally
+    json.Free;
+  end;
+end;
+
+function TJsonSerializer.ArrayToJson<T>(aArray: TArray<T>; aIndent: Boolean): string;
+var
+  json: TJSONObject;
+begin
+  json := TJSONObject.Create;
+  json.AddPair(fRTTIJson.Serialize('array',TValue.From<TArray<T>>(aArray)));
+  try
+    if aIndent then Result := TJsonUtils.JsonFormat(json.Get('array').ToJSON)
+      else Result := json.Get('array').ToJSON;
+  finally
+    json.Free;
+  end;
+end;
+
+function TJsonSerializer.ArrayToJsonString<T>(aArray: TArray<T>; aIndent: Boolean): string;
+var
+  json: TJSONObject;
+begin
+  json := TJSONObject.Create;
+  json.AddPair(fRTTIJson.Serialize('array',TValue.From<TArray<T>>(aArray)));
+  try
+    if aIndent then Result := TJsonUtils.JsonFormat(json.Get('array').ToString)
+      else Result := json.Get('array').ToString;
+  finally
+    json.Free;
+  end;
+end;
+{$ENDIF}
+
 procedure TJsonSerializer.SetUseEnumNames(const Value: Boolean);
 procedure TJsonSerializer.SetUseEnumNames(const Value: Boolean);
 begin
 begin
   fUseEnumNames := Value;
   fUseEnumNames := Value;

+ 62 - 0
Quick.MemoryCache.Compressor.GZip.pas

@@ -0,0 +1,62 @@
+{ ***************************************************************************
+
+  Copyright (c) 2016-2019 Kike Pérez
+
+  Unit        : Quick.MemoryCache.Compressor.GZip
+  Description : Compress Cache data
+  Author      : Kike Pérez
+  Version     : 1.0
+  Created     : 14/07/2019
+  Modified    : 15/09/2019
+
+  This file is part of QuickLib: https://github.com/exilon/QuickLib
+
+ ***************************************************************************
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+ *************************************************************************** }
+
+unit Quick.MemoryCache.Compressor.GZip;
+
+{$i QuickLib.inc}
+
+interface
+
+uses
+  Quick.Compression,
+  Quick.MemoryCache.Types;
+
+type
+
+  TCacheCompressorGZip = class(TInterfacedObject,ICacheCompressor)
+  public
+    function Compress(const aValue : string) : string;
+    function Decompress(const aValue : string) : string;
+  end;
+
+implementation
+
+{ TCacheCompresorGZip }
+
+function TCacheCompressorGZip.Compress(const aValue: string): string;
+begin
+  Result := CompressGZipString(aValue,TCompressionLevel.zcFastest);
+end;
+
+function TCacheCompressorGZip.Decompress(const aValue: string): string;
+begin
+  Result := DeCompressGZipString(aValue);
+end;
+
+end.

+ 76 - 0
Quick.MemoryCache.Compressor.LZO.pas

@@ -0,0 +1,76 @@
+{ ***************************************************************************
+
+  Copyright (c) 2016-2019 Kike Pérez
+
+  Unit        : Quick.MemoryCache.Compressor.LZO
+  Description : Compress Cache data
+  Author      : Kike Pérez
+  Version     : 1.0
+  Created     : 15/07/2019
+  Modified    : 22/09/2019
+
+  This file is part of QuickLib: https://github.com/exilon/QuickLib
+
+ ***************************************************************************
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+ *************************************************************************** }
+
+unit Quick.MemoryCache.Compressor.LZO;
+
+{$i QuickLib.inc}
+
+interface
+
+uses
+  Quick.MemoryCache.Types,
+  Quick.Compression.LZO;
+
+type
+
+  TCacheCompressorLZO = class(TInterfacedObject,ICacheCompressor)
+  public
+    function Compress(const aValue : string) : string;
+    function Decompress(const aValue : string) : string;
+  end;
+
+implementation
+
+{ TCacheCompresorLZO }
+
+function TCacheCompressorLZO.Compress(const aValue: string): string;
+var
+  lzo : TLZOCompressor;
+begin
+  lzo := TLZOCompressor.Create;
+  try
+    Result := lzo.Compress(aValue);
+  finally
+    lzo.Free;
+  end;
+end;
+
+function TCacheCompressorLZO.Decompress(const aValue: string): string;
+var
+  lzo : TLZOCompressor;
+begin
+  lzo := TLZOCompressor.Create;
+  try
+    Result := lzo.Decompress(aValue);
+  finally
+    lzo.Free;
+  end;
+end;
+
+end.

+ 107 - 0
Quick.MemoryCache.Serializer.Json.pas

@@ -0,0 +1,107 @@
+{ ***************************************************************************
+
+  Copyright (c) 2016-2019 Kike Pérez
+
+  Unit        : Quick.MemoryCache.Serializer.Json
+  Description : Cache Json serializer
+  Author      : Kike Pérez
+  Version     : 1.0
+  Created     : 14/07/2019
+  Modified    : 02/11/2019
+
+  This file is part of QuickLib: https://github.com/exilon/QuickLib
+
+ ***************************************************************************
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+ *************************************************************************** }
+
+unit Quick.MemoryCache.Serializer.Json;
+
+{$i QuickLib.inc}
+
+interface
+
+uses
+  RTTI,
+  //System.JSON.Serializers,
+  Quick.Json.Serializer,
+  Quick.MemoryCache.Types;
+
+type
+
+  TCacheJsonSerializer = class(TInterfacedObject,ICacheSerializer)
+  private
+    fJsonSerializer : TJsonSerializer;
+  public
+    constructor Create;
+    destructor Destroy; override;
+    function Serialize(aObject : TObject) : string; overload;
+    function Serialize(aArray : TArray<string>) : string; overload;
+    function Serialize(aArray: TArray<TObject>): string; overload;
+    procedure Deserialize(const aValue : string; aObject : TObject); overload;
+    procedure Deserialize(const aValue : string; var aArray : TArray<string>); overload;
+    procedure Deserialize(const aValue : string; var aArray: TArray<TObject>); overload;
+  end;
+
+
+implementation
+
+{ TCacheJsonSerializer }
+
+constructor TCacheJsonSerializer.Create;
+begin
+  fJsonSerializer := TJsonSerializer.Create(TSerializeLevel.slPublicProperty,False);
+  //fJsonSerializer := TJsonSerializer.Create;
+end;
+
+destructor TCacheJsonSerializer.Destroy;
+begin
+  fJsonSerializer.Free;
+  inherited;
+end;
+
+function TCacheJsonSerializer.Serialize(aObject: TObject): string;
+begin
+  Result := fJsonSerializer.ObjectToJson(aObject,False);
+  //Result := fJsonSerializer.Serialize<TObject>(aObject);
+end;
+
+function TCacheJsonSerializer.Serialize(aArray: TArray<string>): string;
+begin
+  Result := fJsonSerializer.ArrayToJson<string>(aArray);
+end;
+
+function TCacheJsonSerializer.Serialize(aArray: TArray<TObject>): string;
+begin
+  Result := fJsonSerializer.ArrayToJson<TObject>(aArray);
+end;
+
+procedure TCacheJsonSerializer.Deserialize(const aValue: string; aObject: TObject);
+begin
+  fJsonSerializer.JsonToObject(aObject,aValue);
+  //aObject := fJsonSerializer.Deserialize<TObject>(aValue);
+end;
+
+procedure TCacheJsonSerializer.Deserialize(const aValue: string; var aArray: TArray<string>);
+begin
+  aArray := fJsonSerializer.JsonToArray<string>(aValue);
+end;
+
+procedure TCacheJsonSerializer.Deserialize(const aValue: string; var aArray: TArray<TObject>);
+begin
+  aArray := fJsonSerializer.JsonToArray<TObject>(aValue);
+end;
+
+end.

+ 77 - 0
Quick.MemoryCache.Types.pas

@@ -0,0 +1,77 @@
+{ ***************************************************************************
+
+  Copyright (c) 2016-2019 Kike Pérez
+
+  Unit        : Quick.MemoryCache.Types
+  Description : Memory Cache Types
+  Author      : Kike Pérez
+  Version     : 1.0
+  Created     : 14/07/2019
+  Modified    : 15/09/2019
+
+  This file is part of QuickLib: https://github.com/exilon/QuickLib
+
+ ***************************************************************************
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+ *************************************************************************** }
+
+unit Quick.MemoryCache.Types;
+
+{$i QuickLib.inc}
+
+interface
+
+uses
+  RTTI;
+
+type
+
+  ICacheEntry = interface
+  ['{3158454E-07D5-41A2-A0FA-D3917F6B58C1}']
+    function GetCreationDate: TDateTime;
+    function GetData: string;
+    function GetExpiration: Cardinal;
+    function GetExpirationDate: TDateTime;
+    procedure SetCreationDate(const Value: TDateTime);
+    procedure SetData(const Value: string);
+    procedure SetExpirationDate(const Value: TDateTime);
+    procedure SetExpiration(aMilliseconds : Cardinal);
+    property CreationDate : TDateTime read GetCreationDate write SetCreationDate;
+    property Expiration : Cardinal read GetExpiration write SetExpiration;
+    property ExpirationDate : TDateTime read GetExpirationDate write SetExpirationDate;
+    property Data : string read GetData write SetData;
+    function Size : Integer;
+    function IsExpired : Boolean;
+  end;
+
+  ICacheCompressor = interface
+  ['{DE4FB31F-0A0B-49AF-88A6-41689C316DFE}']
+    function Compress(const aValue : string) : string;
+    function Decompress(const aValue : string) : string;
+  end;
+
+  ICacheSerializer = interface
+  ['{F26B99AE-5080-4EDB-80CF-508E1A6F9EDE}']
+    function Serialize(aObject : TObject) : string; overload;
+    function Serialize(aArray : TArray<string>) : string; overload;
+    function Serialize(aArray: TArray<TObject>): string; overload;
+    procedure Deserialize(const aValue : string; aObject : TObject); overload;
+    procedure Deserialize(const aValue : string; var aArray : TArray<string>); overload;
+    procedure Deserialize(const aValue : string; var aArray: TArray<TObject>); overload;
+  end;
+
+implementation
+
+end.

+ 764 - 0
Quick.MemoryCache.pas

@@ -0,0 +1,764 @@
+{ ***************************************************************************
+
+  Copyright (c) 2016-2019 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
+
+  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.MemoryCache;
+
+{$i QuickLib.inc}
+
+interface
+
+uses
+  System.SysUtils,
+  System.Generics.Collections,
+  System.DateUtils,
+  System.TypInfo,
+  RTTI,
+  Quick.Commons,
+  Quick.Value,
+  Quick.Threads,
+  Quick.Cache.Intf,
+  Quick.MemoryCache.Types,
+  Quick.MemoryCache.Serializer.Json,
+  Quick.MemoryCache.Compressor.GZip;
+
+type
+
+  TCacheFlushedEvent = reference to procedure(aRemovedEntries : Integer);
+  TBeginPurgerJobEvent = reference to procedure;
+  TEndPurgerJobEvent = reference to procedure(aPurgedEntries : Integer);
+  TPurgerJobErrorEvent = reference to procedure(const aErrorMsg : string);
+
+  IMemoryCache<T> = interface
+  ['{57927AD7-C993-4C3C-B552-43A39F99E73A}']
+    function GetCompression: Boolean;
+    procedure SetCompression(const Value: Boolean);
+    function GetCachedObjects: Integer;
+    function GetCacheSize: Integer;
+    procedure SetOnBeginPurgerJob(const Value: TBeginPurgerJobEvent);
+    procedure SetOnCacheFlushed(const Value: TCacheFlushedEvent);
+    procedure SetOnEndPurgerJob(const Value: TEndPurgerJobEvent);
+    procedure SetOnPurgerJobError(const Value: TPurgerJobErrorEvent);
+    property Compression : Boolean read GetCompression write SetCompression;
+    property CachedObjects : Integer read GetCachedObjects;
+    property CacheSize : Integer read GetCacheSize;
+    property OnCacheFlushed : TCacheFlushedEvent write SetOnCacheFlushed;
+    property OnBeginPurgerJob : TBeginPurgerJobEvent write SetOnBeginPurgerJob;
+    property OnEndPurgerJob : TEndPurgerJobEvent write SetOnEndPurgerJob;
+    property OnPurgeJobError : TPurgerJobErrorEvent write SetOnPurgerJobError;
+    procedure SetValue(const aKey : string; aValue : T; aExpirationMillisecons : Integer = 0); overload;
+    procedure SetValue(const aKey : string; aValue : T; aExpirationDate : TDateTime); overload;
+    function GetValue(const aKey : string) : T;
+    function TryGetValue(const aKey : string; out aValue : T) : Boolean;
+    procedure RemoveValue(const aKey : string);
+    procedure Flush;
+  end;
+
+
+  IMemoryCache = interface(ICache)
+  ['{F109AE78-43D7-4983-B8ED-52A41533EEED}']
+    function GetCompression: Boolean;
+    procedure SetCompression(const Value: Boolean);
+    function GetCachedObjects: Integer;
+    function GetCacheSize: Integer;
+    procedure SetOnBeginPurgerJob(const Value: TBeginPurgerJobEvent);
+    procedure SetOnCacheFlushed(const Value: TCacheFlushedEvent);
+    procedure SetOnEndPurgerJob(const Value: TEndPurgerJobEvent);
+    procedure SetOnPurgerJobError(const Value: TPurgerJobErrorEvent);
+    property Compression : Boolean read GetCompression write SetCompression;
+    property CachedObjects : Integer read GetCachedObjects;
+    property CacheSize : Integer read GetCacheSize;
+    property OnCacheFlushed : TCacheFlushedEvent write SetOnCacheFlushed;
+    property OnBeginPurgerJob : TBeginPurgerJobEvent write SetOnBeginPurgerJob;
+    property OnEndPurgerJob : TEndPurgerJobEvent write SetOnEndPurgerJob;
+    property OnPurgeJobError : TPurgerJobErrorEvent write SetOnPurgerJobError;
+    procedure SetValue(const aKey : string; aValue : TObject; aExpirationMilliseconds : Integer = 0); overload;
+    procedure SetValue(const aKey : string; aValue : TObject; aExpirationDate : TDateTime); overload;
+    procedure SetValue(const aKey, aValue : string; aExpirationMilliseconds : Integer = 0); overload;
+    procedure SetValue(const aKey, aValue : string; aExpirationDate : TDateTime); overload;
+    procedure SetValue(const aKey : string; aValue : TArray<string>; aExpirationMilliseconds : Integer = 0); overload;
+    procedure SetValue(const aKey : string; aValue : TArray<string>; aExpirationDate : TDateTime); overload;
+    procedure SetValue(const aKey : string; aValue : TArray<TObject>; aExpirationMilliseconds : Integer = 0); overload;
+    procedure SetValue(const aKey : string; aValue : TArray<TObject>; aExpirationDate : TDateTime); overload;
+    function GetValue(const aKey : string) : string; overload;
+    function TryGetValue(const aKey : string; aValue : TObject) : Boolean; overload;
+    function TryGetValue(const aKey : string; out aValue : string) : Boolean; overload;
+    function TryGetValue(const aKey : string; out aValue : TArray<string>) : Boolean; overload;
+    function TryGetValue(const aKey : string; out aValue : TArray<TObject>) : Boolean; overload;
+    procedure RemoveValue(const aKey : string);
+    procedure Flush;
+  end;
+
+  TCacheEntry = class(TInterfacedObject,ICacheEntry)
+  private
+    fCreationDate : TDateTime;
+    fExpiration : Cardinal;
+    fExpirationDate : TDateTime;
+    fCompression : Boolean;
+    fCompressor : ICacheCompressor;
+    fData : string;
+    fIsCompressed : Boolean;
+    function GetCreationDate: TDateTime;
+    function GetData: string;
+    function GetExpiration: Cardinal;
+    procedure SetCreationDate(const Value: TDateTime);
+    procedure SetData(const Value: string);
+    procedure SetExpiration(aMilliseconds : Cardinal);
+    function GetExpirationDate: TDateTime;
+    procedure SetExpirationDate(const Value: TDateTime);
+  public
+    constructor Create(aCompression : Boolean; aCacheCompressor : ICacheCompressor);
+    property CreationDate : TDateTime read GetCreationDate write SetCreationDate;
+    property Expiration : Cardinal read GetExpiration write SetExpiration;
+    property ExpirationDate : TDateTime read GetExpirationDate write SetExpirationDate;
+    property Data : string read GetData write SetData;
+    function Size : Integer;
+    function IsExpired : Boolean;
+  end;
+
+  TMemoryCacheBase = class(TInterfacedObject)
+  private
+    fPurgerInterval : Integer;
+    fMaxSize : Integer;
+    fCachedObjects : Integer;
+    fCacheSize : Integer;
+    fCompression : Boolean;
+    fLock : TMultiReadExclusiveWriteSynchronizer;
+    fCacheJobs : TScheduledTasks;
+    fOnCacheFlushed : TCacheFlushedEvent;
+    fOnPurgerJobError : TPurgerJobErrorEvent;
+    fOnBeginPurgerJob : TBeginPurgerJobEvent;
+    fOnEndPurgerJob : TEndPurgerJobEvent;
+    procedure CreatePurgerJobs;
+    procedure RemoveExpiredCacheEntries; virtual;
+    procedure SetPurgerInterval(const Value: Integer);
+  protected
+    fItems : TDictionary<string,ICacheEntry>;
+    fSerializer : ICacheSerializer;
+    fCompressor : ICacheCompressor;
+    function GetCachedObjects: Integer;
+    function GetCacheSize: Integer;
+    procedure SetOnBeginPurgerJob(const Value: TBeginPurgerJobEvent);
+    procedure SetOnCacheFlushed(const Value: TCacheFlushedEvent);
+    procedure SetOnEndPurgerJob(const Value: TEndPurgerJobEvent);
+    procedure SetOnPurgerJobError(const Value: TPurgerJobErrorEvent);
+    function GetCompression: Boolean;
+    procedure SetCompression(const Value: Boolean);
+  public
+    constructor Create(aPurgerInterval : Integer = 20; aCacheSerializer : ICacheSerializer = nil; aCacheCompressor : ICacheCompressor = nil); virtual;
+    destructor Destroy; override;
+    property MaxSize : Integer read fMaxSize write fMaxSize;
+    property PurgerInterval : Integer read fPurgerInterval;
+    property Compression : Boolean read GetCompression write SetCompression;
+    property CachedObjects : Integer read GetCachedObjects;
+    property CacheSize : Integer read GetCacheSize;
+    property OnCacheFlushed : TCacheFlushedEvent read fOnCacheFlushed write SetOnCacheFlushed;
+    property OnBeginPurgerJob : TBeginPurgerJobEvent read fOnBeginPurgerJob write SetOnBeginPurgerJob;
+    property OnEndPurgerJob : TEndPurgerJobEvent read fOnEndPurgerJob write SetOnEndPurgerJob;
+    property OnPurgeJobError : TPurgerJobErrorEvent read fOnPurgerJobError write SetOnPurgerJobError;
+    procedure RemoveValue(const aKey : string); virtual;
+    procedure Flush; virtual;
+  end;
+
+  TMemoryCache<T> = class(TMemoryCacheBase,IMemoryCache<T>)
+  private
+    procedure SetValue(const aKey : string; aValue : T; aExpirationMilliseconds : Integer; aExpirationDate : TDateTime); overload;
+  public
+    constructor Create(aPurgerInterval : Integer = 20; aCacheSerializer : ICacheSerializer = nil; aCacheCompressor : ICacheCompressor = nil); override;
+    procedure SetValue(const aKey : string; aValue : T; aExpirationMillisecons : Integer = 0); overload;
+    procedure SetValue(const aKey : string; aValue : T; aExpirationDate : TDateTime); overload;
+    function GetValue(const aKey : string) : T;
+    function TryGetValue(const aKey : string; out oValue : T) : Boolean;
+    procedure RemoveValue(const aKey : string); override;
+  end;
+
+  TMemoryCache = class(TMemoryCacheBase,IMemoryCache)
+  private
+    procedure SetValue(const aKey: string; aValue: TObject; aExpirationMilliseconds : Integer; aExpirationDate : TDateTime); overload;
+    procedure SetValue(const aKey, aValue: string; aExpirationMilliseconds : Integer; aExpirationDate : TDateTime); overload;
+  public
+    procedure SetValue(const aKey, aValue : string; aExpirationMilliseconds : Integer = 0); overload;
+    procedure SetValue(const aKey, aValue : string; aExpirationDate : TDateTime); overload;
+    procedure SetValue(const aKey : string; aValue : TObject; aExpirationMilliseconds : Integer = 0); overload;
+    procedure SetValue(const aKey : string; aValue : TObject; aExpirationDate : TDateTime); overload;
+    procedure SetValue(const aKey : string; aValue : TArray<string>; aExpirationMilliseconds : Integer = 0); overload;
+    procedure SetValue(const aKey : string; aValue : TArray<string>; aExpirationDate : TDateTime); overload;
+    procedure SetValue(const aKey : string; aValue : TArray<TObject>; aExpirationMilliseconds : Integer = 0); overload;
+    procedure SetValue(const aKey : string; aValue : TArray<TObject>; aExpirationDate : TDateTime); overload;
+    function GetValue(const aKey : string) : string; overload;
+    function TryGetValue(const aKey : string; out aValue : string) : Boolean; overload;
+    function TryGetValue(const aKey : string; aValue : TObject) : Boolean; overload;
+    function TryGetValue<T>(const aKey : string; out oValue : T) : Boolean; overload;
+    function TryGetValue(const aKey : string; out aValue : TArray<string>) : Boolean; overload;
+    function TryGetValue(const aKey : string; out aValue : TArray<TObject>) : Boolean; overload;
+  end;
+
+  EMemoryCacheConfigError = class(Exception);
+  EMemoryCacheSetError = class(Exception);
+  EMemoryCacheGetError = class(Exception);
+  EMemoryCacheFlushError = class(Exception);
+
+
+implementation
+
+{ TMemoryCacheBase }
+
+constructor TMemoryCacheBase.Create(aPurgerInterval : Integer = 20; aCacheSerializer : ICacheSerializer = nil; aCacheCompressor : ICacheCompressor = nil);
+begin
+  fCompression := True;
+  SetPurgerInterval(aPurgerInterval);
+  fCachedObjects := 0;
+  fCacheSize := 0;
+  fLock := TMultiReadExclusiveWriteSynchronizer.Create;
+  if aCacheSerializer <> nil then fSerializer := aCacheSerializer
+    else fSerializer := TCacheJsonSerializer.Create;
+  if aCacheCompressor <> nil then fCompressor := aCacheCompressor
+    else fCompressor := TCacheCompressorGZip.Create;
+
+  fItems := TDictionary<string,ICacheEntry>.Create;
+  fCacheJobs := TScheduledTasks.Create;
+  CreatePurgerJobs;
+  fCacheJobs.Start;
+end;
+
+procedure TMemoryCacheBase.CreatePurgerJobs;
+begin
+  fCacheJobs.AddTask('RemoveExpired',procedure (task : ITask)
+                  begin
+                    RemoveExpiredCacheEntries;
+                  end
+                  ).OnException(procedure(task : ITask; aException : Exception)
+                  begin
+                    if Assigned(fOnPurgerJobError) then fOnPurgerJobError(aException.Message);
+                  end
+                  ).StartInSeconds(fPurgerInterval).RepeatEvery(fPurgerInterval,TTimeMeasure.tmSeconds);
+end;
+
+destructor TMemoryCacheBase.Destroy;
+begin
+  fItems.Free;
+  fLock.Free;
+  fCacheJobs.Stop;
+  fCacheJobs.Free;
+  inherited;
+end;
+
+procedure TMemoryCacheBase.Flush;
+begin
+  fLock.BeginWrite;
+  try
+    fItems.Clear;
+    if Assigned(fOnCacheFlushed) then fOnCacheFlushed(fCachedObjects);
+    fCachedObjects := 0;
+    fCacheSize := 0;
+  finally
+    fLock.EndWrite;
+  end;
+end;
+
+procedure TMemoryCacheBase.RemoveExpiredCacheEntries;
+var
+  pair : TPair<string,ICacheEntry>;
+  removedentries : Integer;
+begin
+  if Assigned(fOnBeginPurgerJob) then fOnBeginPurgerJob;
+  removedentries := 0;
+  fLock.BeginRead;
+  try
+    for pair in fItems do
+    begin
+      if pair.Value.IsExpired then
+      begin
+        fLock.BeginWrite;
+        try
+          //decrease cacheitem size to cachesize
+          AtomicDecrement(fCacheSize,pair.Value.Size);
+          //remove cacheitem from cache
+          fItems.Remove(pair.Key);
+          //decrease cachedobjects
+          AtomicDecrement(fCachedObjects,1);
+          Inc(removedentries);
+        finally
+          fLock.EndWrite;
+        end;
+      end;
+    end;
+  finally
+    fLock.EndRead;
+    if Assigned(fOnEndPurgerJob) then fOnEndPurgerJob(removedentries);
+  end;
+end;
+
+procedure TMemoryCacheBase.RemoveValue(const aKey: string);
+var
+  cacheitem : ICacheEntry;
+begin
+  if fItems.TryGetValue(aKey,cacheitem) then
+  begin
+    //decrease cacheitem size to cachesize
+    AtomicDecrement(fCacheSize,cacheitem.Size);
+    //remove cacheitem from cache
+    fItems.Remove(aKey);
+    //decrease cachedobjects
+    AtomicDecrement(fCachedObjects,1);
+  end;
+end;
+
+function TMemoryCacheBase.GetCachedObjects: Integer;
+begin
+  Result := fCachedObjects;
+end;
+
+function TMemoryCacheBase.GetCacheSize: Integer;
+begin
+  Result := fCacheSize;
+end;
+
+function TMemoryCacheBase.GetCompression: Boolean;
+begin
+  Result := fCompression;
+end;
+
+procedure TMemoryCacheBase.SetCompression(const Value: Boolean);
+begin
+  fCompression := Value;
+end;
+
+procedure TMemoryCacheBase.SetOnBeginPurgerJob(const Value: TBeginPurgerJobEvent);
+begin
+  fOnBeginPurgerJob := Value;
+end;
+
+procedure TMemoryCacheBase.SetOnCacheFlushed(const Value: TCacheFlushedEvent);
+begin
+  fOnCacheFlushed := Value;
+end;
+
+procedure TMemoryCacheBase.SetOnEndPurgerJob(const Value: TEndPurgerJobEvent);
+begin
+  fOnEndPurgerJob := Value;
+end;
+
+procedure TMemoryCacheBase.SetOnPurgerJobError(const Value: TPurgerJobErrorEvent);
+begin
+  fOnPurgerJobError := Value;
+end;
+
+procedure TMemoryCacheBase.SetPurgerInterval(const Value: Integer);
+begin
+  if Value > 5 then
+  begin
+    fPurgerInterval := Value;
+  end
+  else raise EMemoryCacheConfigError.Create('Purger Interval must be greater than 5 seconds');
+end;
+
+{ TCacheItem }
+
+constructor TCacheEntry.Create(aCompression : Boolean; aCacheCompressor : ICacheCompressor);
+begin
+  fIsCompressed := False;
+  fCompression := aCompression;
+  fCompressor := aCacheCompressor;
+end;
+
+function TCacheEntry.GetCreationDate: TDateTime;
+begin
+  Result := fCreationDate;
+end;
+
+function TCacheEntry.GetData: string;
+begin
+  if fIsCompressed then Result := fCompressor.Decompress(fData)
+    else Result := fData;
+end;
+
+function TCacheEntry.GetExpiration: Cardinal;
+begin
+  Result := fExpiration;
+end;
+
+function TCacheEntry.GetExpirationDate: TDateTime;
+begin
+  Result := fExpirationDate;
+end;
+
+procedure TCacheEntry.SetCreationDate(const Value: TDateTime);
+begin
+  fCreationDate := Value;
+end;
+
+procedure TCacheEntry.SetExpiration(aMilliseconds: Cardinal);
+begin
+  fExpiration := aMilliseconds;
+  fExpirationDate := IncMilliSecond(fCreationDate,fExpiration);
+end;
+
+procedure TCacheEntry.SetExpirationDate(const Value: TDateTime);
+begin
+  fExpiration := MilliSecondOf(Value);
+  fExpirationDate := Value;
+end;
+
+function TCacheEntry.IsExpired: Boolean;
+begin
+  if fExpiration = 0 then Result := False
+    else Result := Now() > fExpirationDate;
+end;
+
+procedure TCacheEntry.SetData(const Value: string);
+begin
+  fIsCompressed := False;
+  //var a := value;
+  //var b := value.Length;
+  if fCompression then
+  begin
+    if ((Value.Length + 1) * 2) > 1024 then
+    begin
+      fData := fCompressor.Compress(Value);
+      fIsCompressed := True;
+    end
+    else
+    begin
+      fData := Value;
+    end;
+  end
+  else fData := Value;
+end;
+
+function TCacheEntry.Size: Integer;
+begin
+  //Result := (fData.Length + 1) * SizeOf(Char);
+  Result := (fData.Length + 1) * StringElementSize(fData);
+end;
+
+{ TMemoryCache<T> }
+
+constructor TMemoryCache<T>.Create(aPurgerInterval: Integer; aCacheSerializer: ICacheSerializer; aCacheCompressor: ICacheCompressor);
+begin
+  inherited Create(aPurgerInterval,aCacheSerializer,aCacheCompressor);
+end;
+
+function TMemoryCache<T>.GetValue(const aKey: string): T;
+var
+  cacheitem : ICacheEntry;
+begin
+  fLock.BeginRead;
+  try
+    fItems.TryGetValue(aKey,cacheitem);
+  finally
+    fLock.EndRead;
+  end;
+end;
+
+procedure TMemoryCache<T>.RemoveValue(const aKey: string);
+begin
+  inherited RemoveValue(aKey);
+end;
+
+procedure TMemoryCache<T>.SetValue(const aKey: string; aValue: T; aExpirationDate: TDateTime);
+begin
+  SetValue(aKey,aValue,0,aExpirationDate);
+end;
+
+procedure TMemoryCache<T>.SetValue(const aKey: string; aValue: T; aExpirationMillisecons: Integer);
+begin
+  SetValue(aKey,aValue,aExpirationMillisecons,0.0);
+end;
+
+procedure TMemoryCache<T>.SetValue(const aKey: string; aValue: T; aExpirationMilliseconds : Integer; aExpirationDate : TDateTime);
+var
+  serialized : string;
+  cacheitem : TCacheEntry;
+begin
+  fLock.BeginWrite;
+  try
+    cacheitem := TCacheEntry.Create(fCompression,fCompressor);
+    cacheitem.CreationDate := Now();
+    cacheitem.Expiration := aExpirationMilliseconds;
+    if aExpirationDate > 0.0 then cacheitem.ExpirationDate := aExpirationDate;
+    //add object to cache
+    case PTypeInfo(TypeInfo(T))^.Kind of
+      tkClass, tkPointer :
+        begin
+          //object type need to be serialized
+          cacheitem.Data := fSerializer.Serialize(PObject(@aValue)^);
+        end;
+      tkString, tkWideString, tkUString, tkChar, tkWideChar : cacheitem.Data := string((@aValue)^);
+      {$IFNDEF NEXTGEN}
+      tkAnsiString : cacheitem.Data := string(AnsiString((@aValue)^));
+      {$ENDIF}
+    else
+      begin
+        raise EMemoryCacheSetError.Create('Type not supported as cache');
+      end;
+    end;
+    RemoveValue(aKey);
+    fItems.Add(aKey,cacheitem);
+    //add cacheitem size to cachesize
+    AtomicIncrement(fCacheSize,cacheitem.Size);
+    //increment cacheobjects
+    AtomicIncrement(fCachedObjects,1);
+  finally
+    fLock.EndWrite;
+  end;
+end;
+
+function TMemoryCache<T>.TryGetValue(const aKey: string; out oValue: T): Boolean;
+var
+  cacheitem : ICacheEntry;
+  flexvalue : TFlexValue;
+  obj : TObject;
+begin
+  fLock.BeginRead;
+  try
+    Result := fItems.TryGetValue(aKey,cacheitem);
+    //check if cacheitem already expired
+    if Result and cacheitem.IsExpired then Exit(False);
+  finally
+    fLock.EndRead;
+  end;
+
+  if Result then
+  begin
+    flexvalue.AsString := cacheitem.Data;
+    case PTypeInfo(TypeInfo(T))^.Kind of
+      tkInteger : oValue := TValue.From(flexvalue.AsInteger).AsType<T>;
+      tkInt64 : oValue := TValue.From(flexvalue.AsInt64).AsType<T>;
+      tkFloat :
+        begin
+          if TypeInfo(T) = TypeInfo(TDateTime) then oValue := TValue.From(flexvalue.AsDateTime).AsType<T>
+            else oValue := TValue.From(flexvalue.AsExtended).AsType<T>;
+        end;
+      tkString,
+      tkUString  : oValue := TValue.From(flexvalue.AsString).AsType<T>;
+      {$IFDEF MSWINDOWS}
+      tkAnsiString : oValue := TValue.From(flexvalue.AsAnsiString).AsType<T>;
+      tkWideString : oValue := TValue.From(flexvalue.AsWideString).AsType<T>;
+      {$ENDIF}
+      tkEnumeration :
+        begin
+          if TypeInfo(T) = TypeInfo(Boolean) then oValue := TValue.From(flexvalue.AsBoolean).AsType<T>
+            else oValue := TValue.From(flexvalue.AsInteger).AsType<T>;
+        end;
+      tkClass, tkPointer :
+        begin
+          obj := PTypeInfo(TypeInfo(T))^.TypeData.ClassType.Create;
+          fSerializer.Deserialize(cacheitem.Data,obj);
+          oValue := TValue.From(obj).AsType<T>;
+          //oValue := T((@obj)^);
+        end
+      else raise EMemoryCacheGetError.Create('Error casting value from cache');
+    end;
+  end;
+end;
+
+{ TMemoryCache }
+
+function TMemoryCache.GetValue(const aKey: string): string;
+var
+  cacheitem : ICacheEntry;
+begin
+  if fItems.TryGetValue(aKey,cacheitem) then Result := cacheitem.Data;
+end;
+
+procedure TMemoryCache.SetValue(const aKey, aValue: string; aExpirationMilliseconds: Integer);
+begin
+  SetValue(aKey,aValue,aExpirationMilliseconds,0.0);
+end;
+
+procedure TMemoryCache.SetValue(const aKey, aValue: string; aExpirationDate: TDateTime);
+begin
+  SetValue(aKey,aValue,0,aExpirationDate);
+end;
+
+procedure TMemoryCache.SetValue(const aKey: string; aValue: TObject; aExpirationMilliseconds: Integer);
+begin
+  SetValue(aKey,aValue,aExpirationMilliseconds,0.0);
+end;
+
+procedure TMemoryCache.SetValue(const aKey: string; aValue: TObject; aExpirationDate: TDateTime);
+begin
+  SetValue(aKey,aValue,0,aExpirationDate);
+end;
+
+procedure TMemoryCache.SetValue(const aKey: string; aValue: TObject; aExpirationMilliseconds : Integer; aExpirationDate : TDateTime);
+begin
+  SetValue(aKey,fSerializer.Serialize(aValue),aExpirationMilliseconds,aExpirationDate);
+end;
+
+procedure TMemoryCache.SetValue(const aKey, aValue: string; aExpirationMilliseconds : Integer; aExpirationDate : TDateTime);
+var
+  cacheitem : TCacheEntry;
+begin
+  fLock.BeginWrite;
+  try
+    cacheitem := TCacheEntry.Create(fCompression,fCompressor);
+    cacheitem.CreationDate := Now();
+    cacheitem.Expiration := aExpirationMilliseconds;
+    if aExpirationDate > 0.0 then cacheitem.ExpirationDate := aExpirationDate;
+    //add object to cache
+    cacheitem.Data := aValue;
+    RemoveValue(aKey);
+    fItems.Add(aKey,cacheitem);
+    //add cacheitem size to cachesize
+    AtomicIncrement(fCacheSize,cacheitem.Size);
+    //increment cacheobjects
+    AtomicIncrement(fCachedObjects,1);
+  finally
+    fLock.EndWrite;
+  end;
+end;
+
+procedure TMemoryCache.SetValue(const aKey: string; aValue: TArray<string>; aExpirationDate: TDateTime);
+begin
+  SetValue(aKey,fSerializer.Serialize(aValue),0,aExpirationDate);
+end;
+
+procedure TMemoryCache.SetValue(const aKey: string; aValue: TArray<string>; aExpirationMilliseconds: Integer);
+begin
+  SetValue(aKey,fSerializer.Serialize(aValue),aExpirationMilliseconds,0.0);
+end;
+
+procedure TMemoryCache.SetValue(const aKey: string; aValue: TArray<TObject>; aExpirationDate: TDateTime);
+begin
+  SetValue(aKey,fSerializer.Serialize(aValue),0,aExpirationDate);
+end;
+
+procedure TMemoryCache.SetValue(const aKey: string; aValue: TArray<TObject>; aExpirationMilliseconds: Integer);
+begin
+  SetValue(aKey,fSerializer.Serialize(aValue),aExpirationMilliseconds,0.0);
+end;
+
+function TMemoryCache.TryGetValue(const aKey: string; aValue : TObject): Boolean;
+var
+  cacheitem : ICacheEntry;
+begin
+  fLock.BeginRead;
+  try
+    if aValue = nil then raise EMemoryCacheGetError.Create('Cannot passed a nil object as param');
+
+    Result := fItems.TryGetValue(aKey,cacheitem);
+    //check if cacheitem already expired
+    if (not Result) or (cacheitem.IsExpired) then Exit(False);
+  finally
+    fLock.EndRead;
+  end;
+  fSerializer.Deserialize(cacheitem.Data,aValue);
+end;
+
+function TMemoryCache.TryGetValue(const aKey: string; out aValue: string): Boolean;
+begin
+  Result := TryGetValue<string>(aKey,aValue);
+end;
+
+function TMemoryCache.TryGetValue<T>(const aKey: string; out oValue: T): Boolean;
+var
+  cacheitem : ICacheEntry;
+  flexvalue : TFlexValue;
+  obj : TObject;
+begin
+  fLock.BeginRead;
+  try
+    Result := fItems.TryGetValue(aKey,cacheitem);
+    //check if cacheitem already expired
+    if Result and  cacheitem.IsExpired then Exit(False);
+  finally
+    fLock.EndRead;
+  end;
+
+  if Result then
+  begin
+    flexvalue.AsString := cacheitem.Data;
+    case PTypeInfo(TypeInfo(T))^.Kind of
+      tkInteger : oValue := TValue.From(flexvalue.AsInteger).AsType<T>;
+      tkInt64 : oValue := TValue.From(flexvalue.AsInt64).AsType<T>;
+      tkFloat :
+        begin
+          if TypeInfo(T) = TypeInfo(TDateTime) then oValue := TValue.From(flexvalue.AsDateTime).AsType<T>
+            else oValue := TValue.From(flexvalue.AsExtended).AsType<T>;
+        end;
+      tkString,
+      tkUString  : oValue := TValue.From(flexvalue.AsString).AsType<T>;
+      {$IFDEF MSWINDOWS}
+      tkAnsiString : oValue := TValue.From(flexvalue.AsAnsiString).AsType<T>;
+      tkWideString : oValue := TValue.From(flexvalue.AsWideString).AsType<T>;
+      {$ENDIF}
+      tkEnumeration :
+        begin
+          if TypeInfo(T) = TypeInfo(Boolean) then oValue := TValue.From(flexvalue.AsBoolean).AsType<T>
+            else oValue := TValue.From(flexvalue.AsInteger).AsType<T>;
+        end;
+      tkClass, tkPointer :
+        begin
+          obj := PTypeInfo(TypeInfo(T))^.TypeData.ClassType.Create;
+          fSerializer.Deserialize(flexvalue.AsString,obj);
+          oValue := TValue.From(obj).AsType<T>;
+        end;
+      else raise EMemoryCacheGetError.Create('Error casting value from cache');
+    end;
+  end;
+end;
+
+function TMemoryCache.TryGetValue(const aKey: string; out aValue: TArray<string>): Boolean;
+var
+  cacheitem : ICacheEntry;
+  flexvalue : TFlexValue;
+  obj : TObject;
+begin
+  fLock.BeginRead;
+  try
+    Result := fItems.TryGetValue(aKey,cacheitem);
+    //check if cacheitem already expired
+    if Result and  cacheitem.IsExpired then Exit(False);
+  finally
+    fLock.EndRead;
+  end;
+
+  if Result then fSerializer.Deserialize(cacheitem.Data,aValue);
+end;
+
+function TMemoryCache.TryGetValue(const aKey: string; out aValue: TArray<TObject>): Boolean;
+var
+  cacheitem : ICacheEntry;
+  flexvalue : TFlexValue;
+  obj : TObject;
+begin
+  fLock.BeginRead;
+  try
+    Result := fItems.TryGetValue(aKey,cacheitem);
+    //check if cacheitem already expired
+    if Result and  cacheitem.IsExpired then Exit(False);
+  finally
+    fLock.EndRead;
+  end;
+
+  if Result then fSerializer.Deserialize(cacheitem.Data,aValue);
+end;
+
+end.

+ 124 - 0
Quick.Options.Serializer.Json.pas

@@ -0,0 +1,124 @@
+{ ***************************************************************************
+
+  Copyright (c) 2015-2019 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    : 22/10/2019
+
+  This file is part of QuickLib: https://github.com/exilon/QuickLib
+
+ ***************************************************************************
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+ *************************************************************************** }
+
+unit Quick.Options.Serializer.Json;
+
+{$i QuickLib.inc}
+
+interface
+
+uses
+  System.SysUtils,
+  System.IOUtils,
+  System.Generics.Collections,
+  System.Json,
+  Quick.Commons,
+  Quick.JSON.Utils,
+  Quick.Json.Serializer,
+  Quick.Options;
+
+type
+
+  TJsonOptionsSerializer = class(TOptionsSerializer)
+  private
+    fSerializer : TRTTIJson;
+  public
+    constructor Create;
+    destructor Destroy; override;
+    procedure Load(const aFilename : string; aSections : TSectionList); override;
+    procedure Save(const aFilename : string; aSections : TSectionList); override;
+  end;
+
+implementation
+
+{ TJsonOptionsSerializer }
+
+constructor TJsonOptionsSerializer.Create;
+begin
+  fSerializer := TRTTIJson.Create(TSerializeLevel.slPublishedProperty,True);
+end;
+
+destructor TJsonOptionsSerializer.Destroy;
+begin
+  fSerializer.Free;
+  inherited;
+end;
+
+procedure TJsonOptionsSerializer.Load(const aFilename : string; aSections : TSectionList);
+var
+  option : TOptions;
+  fileoptions : string;
+  json : TJsonObject;
+  jpair : TJSONPair;
+begin
+  if FileExists(aFilename) then
+  begin
+    //read option file
+    fileoptions := TFile.ReadAllText(aFilename,TEncoding.UTF8);
+    json := TJSONObject.ParseJSONValue(fileoptions) as TJSONObject;
+    for option in aSections do
+    begin
+      jpair := fSerializer.GetJsonPairByName(json,option.Name);
+      if jpair = nil then raise Exception.CreateFmt('Config section "%s" not found',[option.Name]);
+      if jpair.JsonValue <> nil then
+      begin
+        //deserialize option
+        fSerializer.DeserializeObject(option,jpair.JsonValue as TJSONObject);
+        //validate loaded configuration
+        option.ValidateOptions;
+      end;
+    end;
+  end;
+end;
+
+procedure TJsonOptionsSerializer.Save(const aFilename : string; aSections : TSectionList);
+var
+  option : TOptions;
+  fileoptions : string;
+  json : TJSONObject;
+  jpair : TJSONPair;
+begin
+  json := TJSONObject.Create;
+  try
+    for option in aSections do
+    begin
+      //validate configuration before save
+      option.ValidateOptions;
+      //serialize option
+      jpair := fSerializer.Serialize(option.Name,option);
+      json.AddPair(jpair);
+    end;
+    fileoptions := TJsonUtils.JsonFormat(json.ToJSON);
+    TFile.WriteAllText(aFilename,fileoptions);
+  finally
+    json.Free;
+  end;
+end;
+
+end.

+ 123 - 0
Quick.Options.Serializer.Yaml.pas

@@ -0,0 +1,123 @@
+{ ***************************************************************************
+
+  Copyright (c) 2015-2019 Kike Pérez
+
+  Unit        : Quick.Options.Serializer.Yaml
+  Description : Configuration groups Yaml Serializer
+  Author      : Kike Pérez
+  Version     : 1.0
+  Created     : 18/10/2019
+  Modified    : 22/10/2019
+
+  This file is part of QuickLib: https://github.com/exilon/QuickLib
+
+ ***************************************************************************
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+ *************************************************************************** }
+
+unit Quick.Options.Serializer.Yaml;
+
+{$i QuickLib.inc}
+
+interface
+
+uses
+  System.SysUtils,
+  System.IOUtils,
+  System.Generics.Collections,
+  Quick.YAML,
+  Quick.Commons,
+  Quick.YAML.Serializer,
+  Quick.Options;
+
+type
+
+  TYamlOptionsSerializer = class(TOptionsSerializer)
+  private
+    fSerializer : TRTTIYaml;
+  public
+    constructor Create;
+    destructor Destroy; override;
+    procedure Load(const aFilename : string; aSections : TSectionList); override;
+    procedure Save(const aFilename : string; aSections : TSectionList); override;
+  end;
+
+implementation
+
+{ TYamlOptionsSerializer }
+
+constructor TYamlOptionsSerializer.Create;
+begin
+  fSerializer := TRTTIYaml.Create(TSerializeLevel.slPublishedProperty,True);
+end;
+
+destructor TYamlOptionsSerializer.Destroy;
+begin
+  fSerializer.Free;
+  inherited;
+end;
+
+procedure TYamlOptionsSerializer.Load(const aFilename : string; aSections : TSectionList);
+var
+  option : TOptions;
+  fileoptions : string;
+  json : TYamlObject;
+  jpair : TYamlPair;
+begin
+  if FileExists(aFilename) then
+  begin
+    //read option file
+    fileoptions := TFile.ReadAllText(aFilename,TEncoding.UTF8);
+    json := TYamlObject.ParseYAMLValue(fileoptions) as TYamlObject;
+    for option in aSections do
+    begin
+      jpair := fSerializer.GetYamlPairByName(json,option.Name);
+      if jpair.Value <> nil then
+      begin
+        //deserialize option
+        fSerializer.DeserializeObject(option,jpair.Value as TYamlObject);
+        //validate loaded configuration
+        option.ValidateOptions;
+      end;
+    end;
+  end;
+end;
+
+procedure TYamlOptionsSerializer.Save(const aFilename : string; aSections : TSectionList);
+var
+  option : TOptions;
+  fileoptions : string;
+  yaml : TYamlObject;
+  jpair : TYamlPair;
+begin
+  yaml := TYamlObject.Create;
+  try
+    for option in aSections do
+    begin
+      //validate configuration before save
+      option.ValidateOptions;
+      //serialize option
+      jpair := fSerializer.Serialize(option.Name,option);
+      yaml.AddPair(jpair);
+    end;
+    fileoptions := yaml.ToYaml;
+    TFile.WriteAllText(aFilename,fileoptions);
+  finally
+    yaml.Free;
+  end;
+end;
+
+end.
+

+ 552 - 0
Quick.Options.pas

@@ -0,0 +1,552 @@
+{ ***************************************************************************
+
+  Copyright (c) 2015-2019 Kike Pérez
+
+  Unit        : Quick.Options
+  Description : Configuration group settings
+  Author      : Kike Pérez
+  Version     : 1.0
+  Created     : 18/10/2019
+  Modified    : 29/10/2019
+
+  This file is part of QuickLib: https://github.com/exilon/QuickLib
+
+ ***************************************************************************
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+ *************************************************************************** }
+
+unit Quick.Options;
+
+{$i QuickLib.inc}
+
+interface
+
+uses
+  Classes,
+  RTTI,
+  Quick.RTTI.Utils,
+  System.TypInfo,
+  System.SysUtils,
+  System.Generics.Collections,
+  System.Json,
+  Quick.Commons,
+  Quick.FileMonitor;
+
+type
+  Required = class(TCustomAttribute);
+
+  TValidationCustomAttribute = class(TCustomAttribute)
+  protected
+    fErrorMsg : string;
+  public
+    property ErrorMsg : string read fErrorMsg write fErrorMsg;
+  end;
+
+  Range = class(TValidationCustomAttribute)
+  private
+    fRangeMin : Double;
+    fRangeMax : Double;
+  public
+    constructor Create(aMin, aMax : Integer; const aErrorMsg : string = ''); overload;
+    constructor Create(aMin, aMax : Double; const aErrorMsg : string = ''); overload;
+    property Min : Double read fRangeMin write fRangeMax;
+    property Max : Double read fRangeMax write fRangeMax;
+  end;
+
+  StringLength = class(TValidationCustomAttribute)
+  private
+    fMaxLength : Integer;
+  public
+    constructor Create(aMaxLength : Integer; const aErrorMsg : string = '');
+    property MaxLength : Integer read fMaxLength write fMaxLength;
+  end;
+
+  TOptions = class;
+
+  TConfigureOptionsProc<T : TOptions> = reference to procedure(aOptions : T);
+
+  IOptionsValidator = interface
+  ['{C6A09F78-8E34-4689-B943-83620437B9EF}']
+    procedure ValidateOptions;
+  end;
+
+  IOptionsConfigure<T> = interface
+  ['{49258BEB-A21D-4C64-BA71-767B8DBD4D92}']
+    //function ConfigureOptions(aOptionsFunc : TConfigureOptionsProc<T>) : IOptionsValidator;
+  end;
+
+  TOptions = class(TInterfacedObject,IOptionsValidator)
+  private
+    fName : string;
+    procedure ValidateRequired(aProperty : TRttiProperty);
+    procedure ValidateStringLength(aProperty: TRttiProperty; aValidation : StringLength);
+    procedure ValidateRange(aProperty : TRttiProperty; aValidation : Range);
+    procedure DoValidateOptions; virtual;
+  public
+    constructor Create;
+    property Name : string read fName write fName;
+    procedure DefaultValues; virtual; abstract;
+    function ConfigureOptions<T : TOptions>(aOptionsFunc : TConfigureOptionsProc<T>) : IOptionsValidator;
+    procedure ValidateOptions;
+  end;
+
+  TOptions<T : TOptions> = record
+  private
+    fOptions : T;
+  public
+    constructor Create(aOptions : T);
+    function ConfigureOptions(aOptionsFunc : TConfigureOptionsProc<T>) : IOptionsValidator;
+  end;
+
+  IOptions<T : TOptions> = interface
+  ['{2779F946-2692-4F74-88AD-F35F5137057A}']
+    function GetSectionValue : T;
+    property Value : T read GetSectionValue;
+  end;
+
+  TOptionsClass = class of TOptions;
+
+  IOptionsContainer = interface
+  ['{A593C8BB-53CF-4AA4-9641-BF974E45CBD1}']
+    function AddSection(aOption : TOptionsClass; const aOptionsName : string = '') : TOptions;
+    function GetOptions(aOptionClass : TOptionsClass): TOptions;
+    function GetSection(aOptionsSection : TOptionsClass; aOptions : TOptions) : Boolean; overload;
+  end;
+
+  TSectionList = TObjectList<TOptions>;
+
+  IOptionsSerializer = interface
+  ['{7DECE203-4AAE-4C9D-86C8-B3D583DF7C8B}']
+    procedure Load(const aFilename : string; aSections : TSectionList);
+    procedure Save(const aFilename : string; aSections : TSectionList);
+  end;
+
+  TOptionsSerializer = class(TInterfacedObject,IOptionsSerializer)
+  public
+    procedure Load(const aFilename : string; aSections : TSectionList); virtual; abstract;
+    procedure Save(const aFilename : string; aSections : TSectionList); virtual; abstract;
+  end;
+
+  TFileModifiedEvent = reference to procedure;
+  TLoadConfigEvent = reference to procedure;
+
+  TOptionValue<T : TOptions> = class(TInterfacedObject,IOptions<T>)
+  private
+    fValue : T;
+    function GetSectionValue : T;
+  public
+    constructor Create(aValue : T);
+    property Value : T read GetSectionValue;
+  end;
+
+  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; aOptions : TOptions) : Boolean; overload;
+  public
+    constructor Create(const aFilename : string; aOptionsSerializer : IOptionsSerializer; aReloadIfFileChanged : Boolean = False);
+    destructor Destroy; override;
+    property FileName : string read fFilename write fFilename;
+    property ReloadIfFileChanged : Boolean read fReloadIfFileChanged write SetReloadIfFileChanged;
+    property IsLoaded : Boolean read fLoaded;
+    property OnFileModified : TFileModifiedEvent read fOnFileModified write fOnFileModified;
+    property OnConfigLoaded : TLoadConfigEvent read fOnConfigLoaded write fOnConfigLoaded;
+    property OnConfigReloaded : TLoadConfigEvent read fOnConfigReloaded write fOnConfigReloaded;
+    property Items[aOptionClass : TOptionsClass] : TOptions read GetOptions; default;
+    property Items[aIndex : Integer] : TOptions read GetOptions; default;
+    function AddSection(aOption : TOptionsClass; const aSectionName : string = '') : TOptions; overload;
+    function AddSection<T : TOptions>(const aSectionName : string = '') : TOptions<T>; overload;
+    function GetSectionInterface<T : TOptions> : IOptions<T>;
+    function GetSection<T : TOptions>(const aSectionName : string = '') : T; overload;
+    function Count : Integer;
+    procedure Load;
+    procedure Save;
+  end;
+
+  IOptionsBuilder<T : TOptions> = interface
+  ['{1A1DC9A9-7F2D-4CC4-A772-6C7DBAB34424}']
+    function Options : T;
+  end;
+
+  TOptionsBuilder<T : TOptions> = class(TInterfacedObject,IOptionsBuilder<T>)
+  protected
+    fOptions : T;
+  public
+    constructor Create;
+    function Options : T;
+  end;
+
+  EOptionConfigureError = class(Exception);
+  EOptionLoadError = class(Exception);
+  EOptionSaveError = class(Exception);
+  EOptionValidationError = class(Exception);
+
+implementation
+
+{ TOptionsContainer }
+
+constructor TOptionsContainer.Create(const aFilename : string; aOptionsSerializer : IOptionsSerializer; aReloadIfFileChanged : Boolean = False);
+begin
+  fSerializer := aOptionsSerializer;
+  fSections := TSectionList.Create(True);
+  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;
+begin
+  if Assigned(fFileMonitor) then fFileMonitor.Free;
+  fSerializer := nil;
+  fSections.Free;
+  inherited;
+end;
+
+procedure TOptionsContainer.FileModifiedNotify(MonitorNotify: TMonitorNotify);
+begin
+  if MonitorNotify = TMonitorNotify.mnFileModified then
+  begin
+    if Assigned(fOnFileModified) then fOnFileModified;
+    if fReloadIfFileChanged then
+    begin
+      Load;
+    end;
+  end;
+end;
+
+function TOptionsContainer.AddSection(aOption : TOptionsClass; const aSectionName : string = '') : TOptions;
+var
+  option : TOptions;
+begin
+  option := aOption.Create;
+  if aSectionName.IsEmpty then option.Name := Copy(aOption.ClassName,2,aOption.ClassName.Length)
+    else option.Name := aSectionName;
+  fSections.Add(option);
+  Result := option;
+end;
+
+function TOptionsContainer.AddSection<T>(const aSectionName: string): TOptions<T>;
+var
+  option : TOptions;
+begin
+  option := TRTTI.CreateInstance<T>;
+  if aSectionName.IsEmpty then option.Name := Copy(T.ClassName,2,T.ClassName.Length)
+    else option.Name := aSectionName;
+  fSections.Add(option);
+  Result.Create(option);
+end;
+
+function TOptionsContainer.Count: Integer;
+begin
+  Result := fSections.Count;
+end;
+
+function TOptionsContainer.GetOptions(aIndex: Integer): TOptions;
+begin
+  Result := fSections[aIndex];
+end;
+
+function TOptionsContainer.GetSection(aOptionsSection: TOptionsClass; aOptions: TOptions): Boolean;
+var
+  option : TOptions;
+begin
+  Result := False;
+  for option in fSections do
+  begin
+    if option is TOptionsClass then
+    begin
+      aOptions := option as TOptionsClass;
+      Exit;
+    end;
+  end;
+end;
+
+function TOptionsContainer.GetOptions(aOptionClass : TOptionsClass) : TOptions;
+var
+  option : TOptions;
+begin
+  Result := nil;
+  for option in fSections do
+  begin
+    if option is TOptionsClass then Result := option as TOptionsClass;
+  end;
+end;
+
+function TOptionsContainer.GetSection<T>(const aSectionName : string = '') : T;
+var
+  option : TOptions;
+begin
+  for option in fSections do
+  begin
+    if option is T then
+    begin
+      if (aSectionName.IsEmpty) or (CompareText(option.Name,aSectionName) = 0) then
+      begin
+        Result := option as T;
+        Exit;
+      end;
+    end;
+  end;
+end;
+
+function TOptionsContainer.GetSectionInterface<T>: IOptions<T>;
+begin
+  Result := TOptionValue<T>.Create(Self.GetSection<T>);
+end;
+
+procedure TOptionsContainer.Load;
+var
+  option : TOptions;
+begin
+  if FileExists(fFilename) then
+  begin
+    fSerializer.Load(fFilename,fSections);
+    if not fLoaded then
+    begin
+      fLoaded := True;
+      if Assigned(fOnConfigLoaded) then fOnConfigLoaded;
+    end
+    else if Assigned(fOnConfigReloaded) then fOnConfigReloaded;
+  end
+  else
+  begin
+    //if not exists file get default values
+    for option in fSections do option.DefaultValues;
+    //creates default file
+    Save;
+  end;
+end;
+
+procedure TOptionsContainer.Save;
+var
+  laststate : Boolean;
+begin
+  //disable filemonitor to avoid detect manual save as a external file change
+  laststate := fFileMonitor.Enabled;
+  fFileMonitor.Enabled := False;
+  try
+    //save config file
+    fSerializer.Save(fFilename,fSections);
+  finally
+    //set last state
+    fFileMonitor.Enabled := laststate;
+  end;
+end;
+
+procedure TOptionsContainer.SetReloadIfFileChanged(const Value: Boolean);
+begin
+  if Value = fReloadIfFileChanged then Exit;
+  fReloadIfFileChanged := Value;
+  if Assigned(fFileMonitor) then fFileMonitor.Free;
+  if fReloadIfFileChanged then CreateFileMonitor;
+end;
+
+{ TOptions }
+
+function TOptions.ConfigureOptions<T>(aOptionsFunc: TConfigureOptionsProc<T>): IOptionsValidator;
+var
+  value : TValue;
+begin
+  Result := Self;
+  if Assigned(aOptionsFunc) then
+  begin
+    value := Self;
+    aOptionsFunc(value.AsType<T>);
+  end;
+end;
+
+constructor TOptions.Create;
+begin
+  fName := '';
+end;
+
+procedure TOptions.DoValidateOptions;
+var
+  ctx : TRttiContext;
+  rtype : TRttiType;
+  rprop : TRttiProperty;
+  attrib : TCustomAttribute;
+begin
+  ctx := TRttiContext.Create;
+  try
+    rtype := ctx.GetType(Self.ClassInfo);
+    for rprop in rtype.GetProperties do
+    begin
+      //check only published properties
+      if rprop.Visibility = TMemberVisibility.mvPublished then
+      begin
+        //check validation option attributes
+        for attrib in rprop.GetAttributes do
+        begin
+          if attrib is Required  then ValidateRequired(rprop)
+          else if attrib is StringLength then ValidateStringLength(rprop,StringLength(attrib))
+          else if attrib is Range then ValidateRange(rprop,Range(attrib));
+        end;
+      end;
+    end;
+  finally
+    ctx.Free;
+  end;
+end;
+
+procedure TOptions.ValidateOptions;
+begin
+  try
+    DoValidateOptions;
+  except
+    on E : Exception do
+    begin
+      raise EOptionConfigureError.CreateFmt('Validation Options Error : %s',[e.Message]);
+    end;
+  end;
+end;
+
+procedure TOptions.ValidateRange(aProperty: TRttiProperty; aValidation : Range);
+var
+  value : TValue;
+  msg : string;
+begin
+  value := aProperty.GetValue(Self);
+  if not value.IsEmpty then
+  begin
+    if value.Kind = tkFloat then
+    begin
+      if (value.AsExtended < aValidation.Min) or (value.AsExtended > aValidation.Max) then
+      begin
+        if aValidation.ErrorMsg.IsEmpty then msg := Format('Option "%s.%s" exceeds predefined range (%2f - %2f)',[Self.Name,aProperty.Name,aValidation.Min,aValidation.Max])
+          else msg := aValidation.ErrorMsg;
+        raise EOptionValidationError.Create(msg);
+      end;
+    end
+    else if value.Kind in [tkInteger,tkInt64] then
+    begin
+      if (value.AsInt64 < aValidation.Min) or (value.AsInt64 > aValidation.Max) then
+      begin
+        if aValidation.ErrorMsg.IsEmpty then msg := Format('Option "%s.%s" exceeds predefined range (%d - %d)',[Self.Name,aProperty.Name,Round(aValidation.Min),Round(aValidation.Max)])
+          else msg := aValidation.ErrorMsg;
+        raise EOptionValidationError.Create(msg);
+      end;
+    end;
+  end;
+end;
+
+procedure TOptions.ValidateRequired(aProperty: TRttiProperty);
+begin
+  if aProperty.GetValue(Self).IsEmpty then raise EOptionValidationError.CreateFmt('Option "%s.%s" is required',[Self.Name,aProperty.Name]);
+end;
+
+procedure TOptions.ValidateStringLength(aProperty: TRttiProperty; aValidation : StringLength);
+var
+  value : TValue;
+  msg : string;
+begin
+  value := aProperty.GetValue(Self);
+  if (not value.IsEmpty) and (value.AsString.Length > aValidation.MaxLength) then
+  begin
+    if aValidation.ErrorMsg.IsEmpty then msg := Format('Option "%s.%s" exceeds max length (%d)',[Self.Name,aProperty.Name,aValidation.MaxLength])
+      else msg := aValidation.ErrorMsg;
+
+    raise EOptionValidationError.Create(msg);
+  end;
+end;
+
+{ Range }
+
+constructor Range.Create(aMin, aMax: Integer; const aErrorMsg : string = '');
+begin
+  fRangeMin := aMin;
+  fRangeMax := aMax;
+  fErrorMsg := aErrorMsg;
+end;
+
+constructor Range.Create(aMin, aMax: Double; const aErrorMsg: string);
+begin
+  fRangeMin := aMin;
+  fRangeMax := aMax;
+  fErrorMsg := aErrorMsg;
+end;
+
+{ StringLength }
+
+constructor StringLength.Create(aMaxLength: Integer; const aErrorMsg : string = '');
+begin
+  fMaxLength := aMaxLength;
+  fErrorMsg := aErrorMsg;
+end;
+
+
+{ TOptionValue<T> }
+
+constructor TOptionValue<T>.Create(aValue: T);
+begin
+  fValue := aValue;
+end;
+
+function TOptionValue<T>.GetSectionValue: T;
+begin
+  Result := fValue;
+end;
+
+{ TOptions<T> }
+
+function TOptions<T>.ConfigureOptions(aOptionsFunc: TConfigureOptionsProc<T>): IOptionsValidator;
+begin
+  if Assigned(aOptionsFunc) then Result := fOptions.ConfigureOptions<T>(aOptionsFunc)
+    else Result := fOptions;
+  fOptions._AddRef;
+end;
+
+constructor TOptions<T>.Create(aOptions: T);
+begin
+  fOptions := aOptions;
+end;
+
+{ TOptionsBuilder<T> }
+
+constructor TOptionsBuilder<T>.Create;
+begin
+  fOptions := (PTypeInfo(TypeInfo(T)).TypeData.ClassType.Create) as T;
+end;
+
+function TOptionsBuilder<T>.Options: T;
+begin
+  Result := fOptions;
+end;
+
+end.

+ 35 - 2
Quick.RTTI.Utils.pas

@@ -7,7 +7,7 @@
   Author      : Kike Pérez
   Author      : Kike Pérez
   Version     : 1.4
   Version     : 1.4
   Created     : 09/03/2018
   Created     : 09/03/2018
-  Modified    : 27/05/2019
+  Modified    : 29/10/2019
 
 
   This file is part of QuickLib: https://github.com/exilon/QuickLib
   This file is part of QuickLib: https://github.com/exilon/QuickLib
 
 
@@ -47,14 +47,16 @@ type
   private class var
   private class var
     fCtx : TRttiContext;
     fCtx : TRttiContext;
   public
   public
-    class function GetType(aTypeInfo : Pointer) : TRttiType;
     {$IFNDEF FPC}
     {$IFNDEF FPC}
+    class constructor Create;
+    class destructor Destroy;
     class function GetField(aInstance : TObject; const aFieldName : string) : TRttiField; overload;
     class function GetField(aInstance : TObject; const aFieldName : string) : TRttiField; overload;
     class function GetField(aTypeInfo : Pointer; 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 FieldExists(aTypeInfo : Pointer; const aFieldName : string) : Boolean;
     class function GetFieldValue(aInstance : TObject; const aFieldName : string) : TValue; overload;
     class function GetFieldValue(aInstance : TObject; const aFieldName : string) : TValue; overload;
     class function GetFieldValue(aTypeInfo : Pointer; const aFieldName: string) : TValue; overload;
     class function GetFieldValue(aTypeInfo : Pointer; const aFieldName: string) : TValue; overload;
     {$ENDIF}
     {$ENDIF}
+    class function GetType(aTypeInfo : Pointer) : TRttiType;
     class function GetProperty(aInstance : TObject; const aPropertyName : string) : TRttiProperty; overload;
     class function GetProperty(aInstance : TObject; const aPropertyName : string) : TRttiProperty; overload;
     class function GetProperty(aTypeInfo : Pointer; const aPropertyName : string) : TRttiProperty; overload;
     class function GetProperty(aTypeInfo : Pointer; const aPropertyName : string) : TRttiProperty; overload;
     class function GetPropertyPath(aInstance : TObject; const aPropertyPath : string) : TRttiProperty;
     class function GetPropertyPath(aInstance : TObject; const aPropertyPath : string) : TRttiProperty;
@@ -67,6 +69,7 @@ type
     class function GetPropertyValue(aTypeInfo : Pointer; const aPropertyName : string) : TValue; overload;
     class function GetPropertyValue(aTypeInfo : Pointer; const aPropertyName : string) : TValue; overload;
     {$IFNDEF FPC}
     {$IFNDEF FPC}
     class function FindClass(const aClassName: string): TClass;
     class function FindClass(const aClassName: string): TClass;
+    class function CreateInstance<T>: T;
     {$ENDIF}
     {$ENDIF}
   end;
   end;
 
 
@@ -77,6 +80,36 @@ implementation
 { TRTTIUtils }
 { TRTTIUtils }
 
 
 {$IFNDEF FPC}
 {$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 destructor TRTTI.Destroy;
+begin
+  fCtx.Free;
+end;
+
 class function TRTTI.FieldExists(aTypeInfo: Pointer; const aFieldName: string): Boolean;
 class function TRTTI.FieldExists(aTypeInfo: Pointer; const aFieldName: string): Boolean;
 var
 var
   rtype : TRttiType;
   rtype : TRttiType;

+ 1 - 0
Quick.Value.RTTI.pas

@@ -62,6 +62,7 @@ begin
     case DataType of
     case DataType of
       dtNull : Result := TValueExtended;
       dtNull : Result := TValueExtended;
       dtBoolean : Result := AsBoolean;
       dtBoolean : Result := AsBoolean;
+      dtString : Result := AsString;
       {$IFDEF MSWINDOWS}
       {$IFDEF MSWINDOWS}
       dtAnsiString : Result := AsAnsiString;
       dtAnsiString : Result := AsAnsiString;
       dtWideString : Result := AsWideString;
       dtWideString : Result := AsWideString;

+ 16 - 0
Quick.Value.pas

@@ -267,6 +267,8 @@ type
     function  IsObject : Boolean; inline;
     function  IsObject : Boolean; inline;
     function  IsPointer : Boolean; inline;
     function  IsPointer : Boolean; inline;
     function  IsVariant : Boolean; inline;
     function  IsVariant : Boolean; inline;
+    function IsRealInteger : Boolean;
+    function IsRealExtended : Boolean;
     procedure Clear; inline;
     procedure Clear; inline;
     procedure _AddRef; inline;
     procedure _AddRef; inline;
     procedure _Release; inline;
     procedure _Release; inline;
@@ -910,6 +912,20 @@ begin
   Result := fDataType = dtPointer;
   Result := fDataType = dtPointer;
 end;
 end;
 
 
+function TFlexValue.IsRealExtended: Boolean;
+var
+  i : Extended;
+begin
+  Result := TryStrToFloat(AsString,i);
+end;
+
+function TFlexValue.IsRealInteger: Boolean;
+var
+  i : Int64;
+begin
+  Result := TryStrToInt64(AsString,i);
+end;
+
 function TFlexValue.IsString: Boolean;
 function TFlexValue.IsString: Boolean;
 begin
 begin
   Result := fDataType in [dtString,dtAnsiString,dtWideString];
   Result := fDataType in [dtString,dtAnsiString,dtWideString];

+ 308 - 41
README.md

@@ -9,7 +9,7 @@ Small delphi/Firemonkey(Windows, Linux, Android, OSX & IOS) and fpc(Windows & Li
 **Areas of functionality:**
 **Areas of functionality:**
   
   
 * **Mapping**: Map fields from a class to other class, copy objects, etc..
 * **Mapping**: Map fields from a class to other class, copy objects, etc..
-* **Config**: Thread your config as an object and load/save from/to file (Json/Yaml) or Windows Registry.
+* **Config**: Use your config as an object and load/save from/to file (Json/Yaml) or Windows Registry.
 * **Serialization**: Serialize objects to/from json/Yaml.
 * **Serialization**: Serialize objects to/from json/Yaml.
 * **Scheduling**: Schedule tasks launching as independent threads with retry policies.
 * **Scheduling**: Schedule tasks launching as independent threads with retry policies.
 * **Threading**: Simplify run and control of multithread background tasks, Thread-safe Lists, queues, etc
 * **Threading**: Simplify run and control of multithread background tasks, Thread-safe Lists, queues, etc
@@ -19,6 +19,7 @@ Small delphi/Firemonkey(Windows, Linux, Android, OSX & IOS) and fpc(Windows & Li
 * **Benchmark**: Time elapsed control and benchmark functions.
 * **Benchmark**: Time elapsed control and benchmark functions.
 * **Filesystem**: Process and Services control, file modify monitors and helpers, etc...
 * **Filesystem**: Process and Services control, file modify monitors and helpers, etc...
 * **FailControl**: Fail and Retry policies.
 * **FailControl**: Fail and Retry policies.
+* **Caching:**: Cache string or objects to retrieve fast later.
 
 
 **Main units description:**
 **Main units description:**
 
 
@@ -48,10 +49,13 @@ Small delphi/Firemonkey(Windows, Linux, Android, OSX & IOS) and fpc(Windows & Li
 * **Quick.YAML.Serializer:** Serialize/Deserialize object from/to Yaml.
 * **Quick.YAML.Serializer:** Serialize/Deserialize object from/to Yaml.
 * **Quick.Expression:** Evaluate object properties using expressions.
 * **Quick.Expression:** Evaluate object properties using expressions.
 * **Quick.Linq:** Makes Linq queries to any TObjectList<T>, TList<T>, TArray<T> and TXArray<T>, performing Select by complex Where like SQL syntax, update and order over your list.
 * **Quick.Linq:** Makes Linq queries to any TObjectList<T>, TList<T>, TArray<T> and TXArray<T>, performing Select by complex Where like SQL syntax, update and order over your list.
+* **Quick.MemoryCache:** Caches objects/info with an expiration time, to avoid generate this info everytime is needed (database queries, hard to calculate info, etc).
 
 
 
 
 **Updates:**
 **Updates:**
 
 
+* NEW: Options file settings with sections.
+* NEW: MemoryCache with expiration & object compression.
 * NEW: Now included on RAD Studio GetIt package manager.
 * NEW: Now included on RAD Studio GetIt package manager.
 * NEW: Background & Scheduled task with retry policies
 * NEW: Background & Scheduled task with retry policies
 * NEW: RunTask, FaultControl
 * NEW: RunTask, FaultControl
@@ -78,7 +82,9 @@ Small delphi/Firemonkey(Windows, Linux, Android, OSX & IOS) and fpc(Windows & Li
 
 
 **Documentation:**
 **Documentation:**
 ----------
 ----------
-**Quick.AppService:** Allow a console app to run as console mode or service mode with same code simplifying debug tasks.
+**Quick.AppService:**
+--
+Allow a console app to run as console mode or service mode with same code simplifying debug tasks.
 
 
 ```delphi
 ```delphi
 if not AppService.IsRunningAsService then
 if not AppService.IsRunningAsService then
@@ -100,7 +106,9 @@ begin
 end;
 end;
 ```
 ```
 
 
-**Quick.Azure/Amazon:** Simplifies blob iteraction with Azure and Amazon Cloud Storage.
+**Quick.Azure/Amazon:**
+--
+Simplifies blob iteraction with Azure and Amazon Cloud Storage.
 
 
 ```delphi
 ```delphi
 //connect to a Azure blobstorage
 //connect to a Azure blobstorage
@@ -120,7 +128,9 @@ end;
 ```
 ```
 
 
 
 
-**Quick.Network:** CIDR and IP Range functions.
+**Quick.Network:**
+--
+CIDR and IP Range functions.
 
 
 ```delphi
 ```delphi
 //convert ip string to integer
 //convert ip string to integer
@@ -130,7 +140,9 @@ IPv4ToInt('192.168.1.10');
 GetIpRange('192.168.100.0','255.255.255.0',LowIp,HighIP);
 GetIpRange('192.168.100.0','255.255.255.0',LowIp,HighIP);
 ```
 ```
 
 
-**Quick.Commons:** Functions frequently needed in the everyday of a developer.
+**Quick.Commons:**
+--
+Functions frequently needed in the everyday of a developer.
 
 
 ```delphi
 ```delphi
 //coverts UTC time TDateTime to Local date time
 //coverts UTC time TDateTime to Local date time
@@ -158,7 +170,9 @@ begin
 end;
 end;
 ```
 ```
 
 
-**Quick.Chrono:** Chronometer and Benchmark a piece of code is simple.
+**Quick.Chrono:**
+--
+Chronometer and Benchmark a piece of code is simple.
 
 
 ```delphi
 ```delphi
 //get elapsed time execution of a code part
 //get elapsed time execution of a code part
@@ -187,7 +201,9 @@ end;
 writeln(Chrono.ElapsedTime(False)); //shows total time elapsed in 00:00:00 format
 writeln(Chrono.ElapsedTime(False)); //shows total time elapsed in 00:00:00 format
 ```
 ```
 
 
-**Quick.Console:** Write log messages to console with colors and more...
+**Quick.Console:**
+--
+Write log messages to console with colors and more...
 
 
 ```delphi
 ```delphi
 //define which level of output needed
 //define which level of output needed
@@ -209,7 +225,9 @@ Console.Verbose := LOG_ONLYERRORS;
 Console.Log := MyQuickLog;
 Console.Log := MyQuickLog;
 ```
 ```
 
 
-**Quick.Log:** Log to disk or memory with verbose levels and daily or max space rotation.
+**Quick.Log:**
+--
+Log to disk or memory with verbose levels and daily or max space rotation.
 
 
 ```delphi
 ```delphi
 //write a header on start with info as running path, appname, debugmode, user, etc...
 //write a header on start with info as running path, appname, debugmode, user, etc...
@@ -225,7 +243,9 @@ Log.Add('Error x',etError);
 Log.Add('Error is %s',[ErrorStr],etError);
 Log.Add('Error is %s',[ErrorStr],etError);
 ```
 ```
 
 
-**Quick.Config:** Load/Save a config as Json or Yaml file or Windows Registry keys. Create a descend class from TAppConfigJson, TAppConfigYaml or TAppConfigRegistry and added published properties will be loaded/saved. Files configs can be reloaded on detect files changes.
+**Quick.Config:**
+--
+Load/Save a config as Json or Yaml file or Windows Registry keys. Create a descend class from TAppConfigJson, TAppConfigYaml or TAppConfigRegistry and added published properties will be loaded/saved. Files configs can be reloaded on detect files changes.
 
 
 ```delphi
 ```delphi
 //create a class heritage
 //create a class heritage
@@ -274,7 +294,9 @@ MyConfig := TMyConfig.Create(TAppConfigJsonProvider.Create('.\config.json');
 
 
 ```
 ```
 
 
-**Quick.FileMonitor:** Monitorizes a file for changes and throws events.
+**Quick.FileMonitor:**
+--
+Monitorizes a file for changes and throws events.
 
 
 ```delphi
 ```delphi
 FileMonitor.Filename := '.\myfile.txt';
 FileMonitor.Filename := '.\myfile.txt';
@@ -286,7 +308,9 @@ FileMonitor.OnFileChange := MyFileChangeFunction;
 FileMonitor.Enabled := True;
 FileMonitor.Enabled := True;
 ```
 ```
 	
 	
-**Quick.JsonUtils:** Utils for working with json objects.
+**Quick.JsonUtils:**
+--
+Utils for working with json objects.
 
 
 ```delphi
 ```delphi
 //When unit declared in uses, a TObject Helper allows all your objects to be loaded or saved to/from json string
 //When unit declared in uses, a TObject Helper allows all your objects to be loaded or saved to/from json string
@@ -297,7 +321,9 @@ MyString := MyObject.ToJson;
 MyObject1.Clone(MyObject2);
 MyObject1.Clone(MyObject2);
 ```
 ```
 
 
-**Quick.SMTP:** Send email with two code lines.
+**Quick.SMTP:**
+--
+Send email with two code lines.
 
 
 ```delphi
 ```delphi
 //Send email
 //Send email
@@ -316,11 +342,17 @@ SMTP.Attachments.Add('.\notes.txt');
 SMTP.SendMail;
 SMTP.SendMail;
 ```
 ```
 
 
-**Quick.Threads:** Thread safe classes.
-- **TThreadedQueueCS:** Version of TThreadedQueue with Critical Section.
-- **TThreadObjectList:** Thread safe Object List.
-- **TThreadedQueueList:** Thread safe Queue List. Autogrow and with Critical Section.
-- **TAnonymousThread:** Creates anonymous thread defining unchained Execute and OnTerminate methods. Use Execute_Sync and OnTerminate_Sync methods if code needs to update UI.
+**Quick.Threads:**
+--
+Thread safe classes.
+
+**TThreadedQueueCS:** Version of TThreadedQueue with Critical Section.
+
+**TThreadObjectList:** Thread safe Object List.
+
+**TThreadedQueueList:** Thread safe Queue List. Autogrow and with Critical Section.
+
+**TAnonymousThread:** Creates anonymous thread defining unchained Execute and OnTerminate methods. Use Execute_Sync and OnTerminate_Sync methods if code needs to update UI.
   - **Execute:** Specify code to execute on start.
   - **Execute:** Specify code to execute on start.
   - **Execute_Sync:** Like Execute but runs code with syncronized thread method (avoids problems if your code updates UI).
   - **Execute_Sync:** Like Execute but runs code with syncronized thread method (avoids problems if your code updates UI).
   - **OnTerminate:** Specify code to execute when task finishes.
   - **OnTerminate:** Specify code to execute when task finishes.
@@ -345,7 +377,7 @@ TAnonymousThread.Execute(
     .Start;
     .Start;
 ```
 ```
 
 
-- **TRunTask:** Launch an autofree single task thread with fault & retry control policies. Params can be passed and created into code.
+**TRunTask:** Launch an autofree single task thread with fault & retry control policies. Params can be passed and created into code.
 - *Define code to execute:*
 - *Define code to execute:*
   - **Execute:** Specify Task name, parameters to pass to anonymous method(If OwnedParams=true, task will free params on termination task) and method than will be executed. 
   - **Execute:** Specify Task name, parameters to pass to anonymous method(If OwnedParams=true, task will free params on termination task) and method than will be executed. 
   - **Execute_Sync:** Like Execute but runs code with synchronize thread method (avoids problems if your code updates UI).
   - **Execute_Sync:** Like Execute but runs code with synchronize thread method (avoids problems if your code updates UI).
@@ -400,7 +432,7 @@ TAnonymousThread.Execute(
     .Run;
     .Run;
 ```
 ```
 
 
-- **TBackgroundsTasks:** Launch tasks in background allowing number of concurrent workers with fault and retry control policies. Use AddTask_Sync and OnTerminate_Sync methods if code needs to update UI.
+**TBackgroundsTasks:** Launch tasks in background allowing number of concurrent workers with fault and retry control policies. Use AddTask_Sync and OnTerminate_Sync methods if code needs to update UI.
 - *Add a task to execute:*
 - *Add a task to execute:*
   - **AddTask:** Specify Task name, parameters to pass to anonymous method(If OwnedParams=true, task will free params on expiration task) and method than will be executed. 
   - **AddTask:** Specify Task name, parameters to pass to anonymous method(If OwnedParams=true, task will free params on expiration task) and method than will be executed. 
   - **AddTask_Sync:** Like AddTask but runs code with synchronize thread method (avoids problems if your code updates UI).
   - **AddTask_Sync:** Like AddTask but runs code with synchronize thread method (avoids problems if your code updates UI).
@@ -446,7 +478,7 @@ TAnonymousThread.Execute(
     end;
     end;
     backgroundtasks.Start;
     backgroundtasks.Start;
 ```
 ```
-- **TScheduledTasks:** Alternative to Timer. You can assign tasks with start time, repeat options and expiration date and fail and retry control policies. Use AddTask_Sync, OnTerminate_Sync and OnExpired_Sync if code needs to update UI.
+**TScheduledTasks:** Alternative to Timer. You can assign tasks with start time, repeat options and expiration date and fail and retry control policies. Use AddTask_Sync, OnTerminate_Sync and OnExpired_Sync if code needs to update UI.
 You can assign anonymous methods to execute, exception, terminate and expiration events.
 You can assign anonymous methods to execute, exception, terminate and expiration events.
 - *Add a task to execute:*
 - *Add a task to execute:*
   - **AddTask:** Specify Task name, parameters to pass to anonymous method(If OwnedParams=true, task will free params on expiration task) and method than will be executed. 
   - **AddTask:** Specify Task name, parameters to pass to anonymous method(If OwnedParams=true, task will free params on expiration task) and method than will be executed. 
@@ -523,9 +555,13 @@ scheduledtasks.Start;
   - **CircuitBreaked:** Return true if max retries has been reached or user cancelled into OnRetry event.
   - **CircuitBreaked:** Return true if max retries has been reached or user cancelled into OnRetry event.
   - **IsEnabled:** Return status of task.
   - **IsEnabled:** Return status of task.
 
 
-**Quick.FaultControl:** Manages fail and retry policies, defining max retries, wait time beetween retries and circuit break mecanism.
+**Quick.FaultControl:**
+--
+Manages fail and retry policies, defining max retries, wait time beetween retries and circuit break mecanism.
 
 
-**Quick.Process:** Manages windows processes.
+**Quick.Process:**
+--
+Manages windows processes.
 ```delphi
 ```delphi
 //kill explorer process
 //kill explorer process
 KillProcess('explorer.exe');
 KillProcess('explorer.exe');
@@ -537,7 +573,9 @@ writeln('Explorer.exe open by: ' + GetProcessUser('explorer.exe');
 if FindWindowTimeout('MainWindow',20) then writeln('Window detected');
 if FindWindowTimeout('MainWindow',20) then writeln('Window detected');
 ```
 ```
 
 
-**Quick.Services:** Manages windows services.
+**Quick.Services:**
+--
+Manages windows services.
 ```delphi
 ```delphi
 //detect if a service is installed
 //detect if a service is installed
 if not ServiceIsPresent('localhost','MySvc') then raise Exception.Create('Service not installed!');
 if not ServiceIsPresent('localhost','MySvc') then raise Exception.Create('Service not installed!');
@@ -547,7 +585,9 @@ ServiceStart('localhost','MySvc');
 ServiceUninstall('MySvc');
 ServiceUninstall('MySvc');
 ```
 ```
 
 
-**Quick.Format:** String format.
+**Quick.Format:**
+--
+String format.
 
 
 ```delphi
 ```delphi
 //Format bytes to MB, GB, TB...
 //Format bytes to MB, GB, TB...
@@ -555,7 +595,9 @@ FormatBytes(50000) //shows 50KB
 FormatBytes(90000000) //shows 90MB
 FormatBytes(90000000) //shows 90MB
 ```
 ```
 
 
-**Quick.JsonSerializer:** Serializes an object from/to json text. You can define if public or published will be processed (only Delphi, fpc rtti only supports published properties)	
+**Quick.JsonSerializer:**
+--
+Serializes an object from/to json text. You can define if public or published will be processed (only Delphi, fpc rtti only supports published properties)	
 
 
 ```delphi
 ```delphi
 json := '{"name":"Peter","age":30}';
 json := '{"name":"Peter","age":30}';
@@ -567,7 +609,9 @@ finally
 end;
 end;
 ```
 ```
 
 
-**Quick.AutoMapper:** Map fields from one class to another class. Allows custom mappings to match different fields and custom mapping procedure to cast/convert fields manually.	
+**Quick.AutoMapper:**
+--
+Map fields from one class to another class. Allows custom mappings to match different fields and custom mapping procedure to cast/convert fields manually.	
 
 
 ```delphi
 ```delphi
 //Map values from User1 to User2
 //Map values from User1 to User2
@@ -597,7 +641,9 @@ AutoMapper.OnAfterMapping := procedure(const aSrcObj : TUser; aTgtObj : TUser2)
 User2 := AutoMapper.Map(User);
 User2 := AutoMapper.Map(User);
 ```
 ```
 
 
-**Quick.JsonRecord:** Used as a DTO class, with json serialize and mapping functions included.	
+**Quick.JsonRecord:**
+--
+Used as a DTO class, with json serialize and mapping functions included.	
 
 
 ```delphi
 ```delphi
 type
 type
@@ -625,7 +671,9 @@ begin
 end;
 end;
 ```
 ```
 
 
-**Quick.Lists:** Improved lists with indexing or search features.
+**Quick.Lists:**
+--
+Improved lists with indexing or search features.
 - **TIndexedObjectList:** Allows fast hashed searches by object properties or fields.
 - **TIndexedObjectList:** Allows fast hashed searches by object properties or fields.
 - **TSearchObjectList:** Allows iteration search by object properties or fields.
 - **TSearchObjectList:** Allows iteration search by object properties or fields.
 ```delphi
 ```delphi
@@ -642,7 +690,9 @@ begin
 end;
 end;
 ```
 ```
 
 
-**Quick.Value** FlexValue stores any data type and allow pass to other class with integrated operators and autofrees.
+**Quick.Value**
+--
+FlexValue stores any data type and allow pass to other class with integrated operators and autofrees.
 ```delphi
 ```delphi
 var
 var
   value : TFlexValue;
   value : TFlexValue;
@@ -656,8 +706,11 @@ begin
 end;
 end;
 ```
 ```
 
 
-**Quick.Arrays:** Improved arrays.
-- **TXArray:** Array with methods like TList.
+**Quick.Arrays:**
+--
+Improved arrays.
+
+**TXArray:** Array with methods like TList.
 ```delphi
 ```delphi
 var
 var
    users : TXArray<TUser>;
    users : TXArray<TUser>;
@@ -673,7 +726,7 @@ begin
 end;
 end;
 ```
 ```
 
 
-- **TFlexArray:** Array with methods like TList than can storage different value types into same array.
+**TFlexArray:** Array with methods like TList than can storage different value types into same array.
 ```delphi
 ```delphi
 var
 var
   flexarray : TFlexArray;
   flexarray : TFlexArray;
@@ -693,7 +746,7 @@ begin
     end;
     end;
 end;
 end;
 ```
 ```
-- **TFlexPairArray:** Array with methods like TList than can store different value types into same array, and search by item name.
+**TFlexPairArray:** Array with methods like TList than can store different value types into same array, and search by item name.
 ```delphi
 ```delphi
 var
 var
   flexarray : TFlexPairArray;
   flexarray : TFlexPairArray;
@@ -714,8 +767,11 @@ begin
 end;
 end;
 ```
 ```
 
 
-**Quick.YAML:** Yaml object structure.
-- **TYamlObject:** A Yaml object is and array of YamlValue pairs.
+**Quick.YAML:**
+--
+Yaml object structure.
+
+**TYamlObject:** A Yaml object is and array of YamlValue pairs.
 ```delphi
 ```delphi
   //create Yaml object from yaml text
   //create Yaml object from yaml text
   yamlobj.ParseYamlValue(aYaml)
   yamlobj.ParseYamlValue(aYaml)
@@ -724,17 +780,19 @@ end;
   //display as yaml structure
   //display as yaml structure
   Writeln(yamlobj.ToYaml);
   Writeln(yamlobj.ToYaml);
 ```
 ```
-- **TYamlArray:** Array of objects or scalars.
+**TYamlArray:** Array of objects or scalars.
 ```delphi
 ```delphi
   yamlarray.AddElement(TYamlPair.Create('Age',30));
   yamlarray.AddElement(TYamlPair.Create('Age',30));
   yamlobj.AddPair('myarray',yamlarray);
   yamlobj.AddPair('myarray',yamlarray);
 ```
 ```
-- **TYamlPair:** Name-Value pair. Value can be object, array or scalar.
+**TYamlPair:** Name-Value pair. Value can be object, array or scalar.
 ```delphi
 ```delphi
   n := yamlobj.GetPair('Name').Value as TYamlInteger;
   n := yamlobj.GetPair('Name').Value as TYamlInteger;
 ```
 ```
 
 
-**Quick.YAML.Serializer:** Serialize/Deserialize object from/to Yaml.
+**Quick.YAML.Serializer:**
+--
+Serialize/Deserialize object from/to Yaml.
 ```delphi
 ```delphi
   //Serialize
   //Serialize
   text := YamlSerializer.ObjectToYaml(obj);
   text := YamlSerializer.ObjectToYaml(obj);
@@ -742,7 +800,9 @@ end;
   YamlSerializer.YamlToObject(obj,yamltext);
   YamlSerializer.YamlToObject(obj,yamltext);
 ```
 ```
 
 
-**Quick.Expression:** Evaluate object properties using expressions.
+**Quick.Expression:**
+--
+ Evaluate object properties using expressions.
 ```delphi
 ```delphi
   if TExpressionParser.Validate(user,('(Age > 30) AND (Dept.Name = "Financial")') then
   if TExpressionParser.Validate(user,('(Age > 30) AND (Dept.Name = "Financial")') then
   begin
   begin
@@ -750,7 +810,9 @@ end;
   end;
   end;
 ```
 ```
 
 
-**Quick.Linq:** Makes Linq queries to any TObjectList<T>, TList<T>, TArray<T> and TXArray<T>, performing Select by complex Where like SQL syntax, update and order over your list.
+**Quick.Linq:**
+--
+Makes Linq queries to any TObjectList<T>, TList<T>, TArray<T> and TXArray<T>, performing Select by complex Where like SQL syntax, update and order over your list.
 - **From:** Array, XArray or TObjectList to use.
 - **From:** Array, XArray or TObjectList to use.
 - **Where:** Expression to search. You can use a dots to define property path.
 - **Where:** Expression to search. You can use a dots to define property path.
 - **SelectAll:** Returns an array of objects matching where clause
 - **SelectAll:** Returns an array of objects matching where clause
@@ -782,4 +844,209 @@ end;
   
   
   //count results
   //count results
   numusers := TLinq<TUser>.From(userlist).Where('(Age > ?) AND (Age < ?)',[30,40]).Count;
   numusers := TLinq<TUser>.From(userlist).Where('(Age > ?) AND (Age < ?)',[30,40]).Count;
-```
+```
+
+**Quick.HTTPServer:**
+--
+TCustomHttpServer is a simple interfaced HttpServer with own HttpRequest and HttpResponse implementations to allow easy httpserver engine changes. 
+THttpServer is the IndyHttpServer implementation, but you can define your own.
+```delphi
+TMyHttpServer = class(THttpServer)
+  public
+    procedure ProcessRequest(aRequest: IHttpRequest; aResponse: IHttpResponse); override;
+  end;
+
+  procedure TMyHttpServer.ProcessRequest(aRequest: IHttpRequest; aResponse: IHttpResponse);
+  begin
+    aResponse.ContentText := 'Hello world!';
+  end;
+```
+
+**Quick.MemoryCache:**
+--
+Caches objects or strings with an expiration time, to avoid generate this info everytime is needed (database queries, hard to calculate info, etc). TMemoryCache allows to cache objects and strings. Generic version TMemoryCache<T> allows to cache a defined type only.
+- Create: Could be defined Purge interval and Serialization and Compression engines. By default serializes as Json and compress with gzip.
+```delphi
+ //create MemoryCache with 10 seconds purge interval
+ cache := TMemoryCache.Create(10);
+
+ //create MemoryCache for a type
+ cache := TMemoryCache<TMyObj>.Create;
+```
+- Compression: Enables/Disables cache data compression.
+- CachedObjects: Returns number of objects currently in cache.
+- CacheSize: Returns size in bytes of all objects currently in cache. Real memory used depends of memory managers or architecture. This value is the real size of data bytes.
+- PurgeInterval: Interval purge job tries to find expired objects to remove from cache (Default value 20 seconds).
+- OnCacheFlushed: When cache is flushed.
+- OnBeginPurgerJob: When PurgerJob starts.
+- OnEndPurgerJob: When PurgerJob ends.
+- Flush: Removes all cache objects.
+- SetValue: Adds an object to cache. You can indicate expiration date or number of milliseconds to expire. If not defined cache will be infinity. MemoryCache can store objects or strings.
+```delphi
+//set string to cache without expiration
+cache.SetValue('mystring','hello world');
+
+//set string to cache with expiration to 10 seconds
+cache.SetValue('mystring','this cache will expire in 10 seconds';
+
+//set object to cache
+cache.SetValue('Obj1',valueobj);
+```
+- TryGetValue: Tries to get and object from cache. Returns false if object doesn't exists or it's expired.
+```delphi
+//get string query result
+cache.GetValue('Query12');
+
+//get integer
+cache.TryGetValue<Integer>('number',valueint);
+
+//get object
+cache.TryGetValue('Obj1',valueobj);
+```
+
+- RemoveValue: Removes an object from cache.
+
+- **Cache Engine providers:**
+
+- TCacheSerializerJSON: Uses JSON to serialize cache data.  
+- TCacheCompressorGzip: Uses Gzip to compress cache data.
+- TCacheCompressorLZO: Uses LZO to compress cache data.
+   
+```delphi 
+ //create MemoryCache with 20 seconds purge interval and compression with LZO engine
+ cache := TMemoryCache.Create(10,nil,TCacheCompressorLZO.Create);
+ ```
+
+ **Quick.IOC:**
+ --
+  Inversion of Control manager allows autocreate interfaced o instanced object or autoinject them in constructor classes, to avoid dependency.
+
+ Create a container to manage dependency injection. 
+ ```delphi
+iocContainer := TIocContainer.Create;
+```
+**Register Types:**
+
+You need to register types before you can inject them. A Type can be registered as Singleton, Transient.
+**Singleton**: Life cycle will be one single instance for all injections, similar to a Global variable.
+**Transient**: Life cycle will be one instance per each injection.
+Register an interface type into container as transient:
+```delphi
+iocContainer.RegisterType<IMultService,TMultService>.AsTransient;
+```
+Register an interface type as singleton, delegating construction:
+```delphi
+iocContainer.RegisterType<ISumService,TSumService>.AsSingleTon.DelegateTo(
+  function : TSumService
+  begin
+    Result := TSumService.Create;
+  end
+);
+```
+**Register Instances:**
+
+Register a named instance object as transient, delegating construction:
+```delphi
+iocContainer.RegisterInstance<TDivideService>('one').AsTransient.DelegateTo(
+  function : TDivideService
+  begin
+    Result := TDivideService.Create(True);
+  end
+);
+```
+**Register Options:**
+
+Register IOptions (only singleton):
+```delphi
+ iocContainer.RegisterOptions<TMyOptions>(MyOptions);
+```
+**Resolve Types:**
+
+AbtractFactory:
+Creates a class trying to resolve all creation method parameter with dependency injection.
+```delphi
+MyClass := iocContainer.AbstractFactory<TMyBaseClass>(TMyClass);
+```
+Resolve an interface dependency:
+```delphi
+multservice := iocContainer.Resolve<IMultService>;
+result := multservice.Mult(2,4);
+```
+**Resolve Instances:**
+
+Resolve a named instance dependency:
+```delphi
+divideservice := iocContainer.Resolve<TDivideService>('other');
+result := divideservice.Divide(100,2);
+```
+Interface instances will be freed automatically, but instance dependencies only will be freed if defined as singleton, transient instances will be destroyed by code.
+
+**Quick.Options:**
+ --
+You define sections as classes and saves as single file settings. Works similar to dotnet Options. Options file can be in JSON or YAML format.
+
+Define your option class inherited from TOptions and all published properties will be load/save.
+Create options container, with JsonSerializer and reloading on change:
+```delphi
+Options := TOptionsContainer.Create('.\options.conf',TJsonOptionsSerializer.Create,True);
+```
+Add a section to your container options:
+```delphi
+Options.AddSection<TLoggingOptions>('Logging')
+```
+**Configure Options:**
+
+You can define section name to save into file and delegate configuration default settings and validating values:
+```delphi
+Options.AddSection<TLoggingOptions>('Logging').ConfigureOptions(
+  procedure(aOptions : TLoggingOptions)
+  begin
+    aOptions.Path := 'C:\';
+  end
+).ValidateOptions;
+```
+**Validate Options:**
+
+Validate options allows verify if option settings are setted between defined ranges. This validation needs previously assigned custom attributes to properties in your TOptions class.
+- **StringLength(max,messagestr):** Allows define max length in string properties, returning messagestr if length greater than max.
+- **Range(min,max,messagestr):** Allows define a range of min and max values permitted, returning messagestr if value length outbounds margins.
+```delphi
+TLoggingOptions = class(TOptions)
+  private
+    fPath : string;
+  published
+    [Required, StringLength(255,'Path too long')]
+    property Path : string read fPath write fPath;
+    [Range(0.0,5.2)]
+    property Level : Double read fLevel write fLevel;
+  end;
+```
+**Use Options:**
+To retrieve option section:
+```delphi
+LoggingOptions := Options.GetSection<TLoggingOptions>;
+LoggginOptions.Path := 'C:\Path';
+```
+**Use IOptions:**
+IOptions is a dependency injectable interface to TOptions. You can register with IocContainer.RegisterOptions<TOptions> to make injectable into constructor methods.
+```delphi
+UIOptions := Options.GetSectionInterface<TUIOptions>.Value;
+UIOptions.WindowColor := clBlue;
+```
+**Load/Save Options:**
+
+Load options from file settings:
+```delphi
+options.Load;
+```
+Save options to file settings:
+```delphi
+options.Save;
+```
+If you defined container creation with ReloadOnChanged parameter to true, every time file settings is changed, configuration will be reloaded. If you need to control when to reload, you can listen to the event:
+```
+Options.OnFileModified := procedure
+  begin
+    cout('Detected config file modification!',etWarning);
+  end;
+```

+ 39 - 0
samples/delphi/QuickCompression/CompressionTest.dpr

@@ -0,0 +1,39 @@
+program CompressionTest;
+
+{$APPTYPE CONSOLE}
+
+{$R *.res}
+
+uses
+  System.SysUtils,
+  Quick.Commons,
+  Quick.Console,
+  Quick.Compression.LZO;
+
+const
+  str = 'This is a test compression with LZO algorithm. Repeated words are compressed' +
+        'Test: Compression, Compression, Compression, Compression, Compression';
+var
+  lzo : TLZOCompressor;
+  compStr : string;
+  decompStr : string;
+
+begin
+  try
+    ReportMemoryLeaksOnShutdown := True;
+    lzo := TLZOCompressor.Create;
+    coutFmt('Original: %s',[str],etInfo);
+    coutFmt('Original size: %d',[str.Length],etInfo);
+    compStr := lzo.Compress(str);
+    coutFmt('Compressed: %s',[compStr],etInfo);
+    coutFmt('Compressed size: %d',[compStr.Length],etInfo);
+    decompStr := lzo.Decompress(compStr);
+    coutFmt('Decompressed: %s',[decompStr],etSuccess);
+    cout('Uncompressed size: %d',[decompStr.Length],etInfo);
+    ConsoleWaitForEnterKey;
+    lzo.Free;
+  except
+    on E: Exception do
+      Writeln(E.ClassName, ': ', E.Message);
+  end;
+end.

+ 906 - 0
samples/delphi/QuickCompression/CompressionTest.dproj

@@ -0,0 +1,906 @@
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+    <PropertyGroup>
+        <ProjectGuid>{9BB4DFEF-AC50-4DA0-A68E-098ACBA41764}</ProjectGuid>
+        <ProjectVersion>18.7</ProjectVersion>
+        <FrameworkType>None</FrameworkType>
+        <MainSource>CompressionTest.dpr</MainSource>
+        <Base>True</Base>
+        <Config Condition="'$(Config)'==''">Debug</Config>
+        <Platform Condition="'$(Platform)'==''">Win32</Platform>
+        <TargetedPlatforms>3</TargetedPlatforms>
+        <AppType>Console</AppType>
+    </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)'=='iOSDevice32' and '$(Base)'=='true') or '$(Base_iOSDevice32)'!=''">
+        <Base_iOSDevice32>true</Base_iOSDevice32>
+        <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)'=='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>
+        <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>CompressionTest</SanitizedProjectName>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Android)'!=''">
+        <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>
+        <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_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>
+    <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>
+    </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>
+        <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;DataSnapServerMidas;DBXDb2Driver;DBXInterBaseDriver;vclactnband;vclFireDAC;emsclientfiredac;DataSnapFireDAC;tethering;FireDACADSDriver;DBXMSSQLDriver;DatasnapConnectorsFreePascal;FireDACMSSQLDriver;vcltouch;vcldb;bindcompfmx;DBXOracleDriver;inetdb;FmxTeeUI;emsedge;FireDACIBDriver;fmx;fmxdae;RadiantShapesFmx;vclib;FlatButtonSet;FireDACDBXDriver;dbexpress;IndyCore;vclx;dsnap;DataSnapCommon;emsclient;FireDACCommon;RESTBackendComponents;DataSnapConnectors;VCLRESTComponents;soapserver;vclie;bindengine;DBXMySQLDriver;FireDACOracleDriver;CloudService;FireDACMySQLDriver;DBXFirebirdDriver;FireDACCommonODBC;FireDACCommonDriver;DataSnapClient;inet;bindcompdbx;IndyIPCommon;vcl;IndyIPServer;DBXSybaseASEDriver;PngComponents;IndySystem;FireDACDb2Driver;dsnapcon;tmsxlsdXE12;FireDACMSAccDriver;fmxFireDAC;FireDACInfxDriver;vclimg;TeeDB;FireDAC;emshosting;FireDACSqliteDriver;FireDACPgDriver;ibmonitor;FireDACASADriver;tmsdXE12;FireDACTDataDriver;DBXOdbcDriver;FMXTee;soaprtl;DbxCommonDriver;ibxpress;Tee;DataSnapServer;xmlrtl;soapmidas;DataSnapNativeClient;fmxobj;vclwinx;ibxbindings;rtl;emsserverresource;DbxClientDriver;FireDACDSDriver;DBXSybaseASADriver;GR32_R;CustomIPTransport;vcldsnap;tmsexdXE12;bindcomp;appanalytics;DBXInformixDriver;IndyIPClient;bindcompvcl;TeeUI;dbxcds;VclSmp;adortl;FireDACODBCDriver;DataSnapIndy10ServerTransport;RadiantShapesFmx_Design;dsnapxml;DataSnapProviderClient;dbrtl;inetdbxpress;FireDACMongoDBDriver;IndyProtocols;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">CompressionTest.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\CompressionTest.exe" Configuration="Debug" Class="ProjectOutput">
+                    <Platform Name="Win32">
+                        <RemoteName>CompressionTest.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>
+                </DeployClass>
+                <DeployClass Name="AndroidFileProvider">
+                    <Platform Name="Android">
+                        <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>
+                </DeployClass>
+                <DeployClass Name="AndroidLibnativeMipsFile">
+                    <Platform Name="Android">
+                        <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>
+                </DeployClass>
+                <DeployClass Name="AndroidSplashImageDef">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidSplashStyles">
+                    <Platform Name="Android">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidSplashStylesV21">
+                    <Platform Name="Android">
+                        <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>
+                </DeployClass>
+                <DeployClass Name="Android_DefaultAppIcon">
+                    <Platform Name="Android">
+                        <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>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon36">
+                    <Platform Name="Android">
+                        <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>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon72">
+                    <Platform Name="Android">
+                        <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>
+                </DeployClass>
+                <DeployClass Name="Android_NotificationIcon24">
+                    <Platform Name="Android">
+                        <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>
+                </DeployClass>
+                <DeployClass Name="Android_NotificationIcon48">
+                    <Platform Name="Android">
+                        <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>
+                </DeployClass>
+                <DeployClass Name="Android_NotificationIcon96">
+                    <Platform Name="Android">
+                        <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>
+                </DeployClass>
+                <DeployClass Name="Android_SplashImage470">
+                    <Platform Name="Android">
+                        <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>
+                </DeployClass>
+                <DeployClass Name="Android_SplashImage960">
+                    <Platform Name="Android">
+                        <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>
+                </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="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="iPad_Launch1024x768">
+                    <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_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">
+                    <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_Launch1668x2388">
+                    <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_Launch2048x1536">
+                    <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_Launch2048x2732">
+                    <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_Launch2224">
+                    <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_Launch2388x1668">
+                    <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_Launch2732x2048">
+                    <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_Launch768x1024">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch1125">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch1136x640">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch1242">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch1242x2688">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch1334">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch1792">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch2208">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch2436">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch2688x1242">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch320">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch640">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch640x1136">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch750">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch828">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectAndroidManifest">
+                    <Platform Name="Android">
+                        <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="ProjectiOSDeviceResourceRules">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <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="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="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="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"/>
+            </Deployment>
+            <Platforms>
+                <Platform value="Android">False</Platform>
+                <Platform value="iOSDevice32">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">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>

BIN
samples/delphi/QuickCompression/CompressionTest.res


+ 144 - 0
samples/delphi/QuickHttpServer/HttpServer/HttpServerService.Logger.pas

@@ -0,0 +1,144 @@
+unit HttpServerService.Logger;
+
+interface
+
+uses
+  System.SysUtils,
+  Quick.Logger.Intf,
+  Quick.Logger,
+  Quick.Logger.Provider.Console;
+
+type
+  TQuickLogger = class(TInterfacedObject,ILogger)
+  public
+    procedure Init;
+    procedure Info(const aMsg : string); overload;
+    procedure Info(const aMsg : string; aValues : array of const); overload;
+    procedure Succ(const aMsg : string); overload;
+    procedure Succ(const aMsg : string; aParams : array of const); overload;
+    procedure Done(const aMsg : string); overload;
+    procedure Done(const aMsg : string; aValues : array of const); overload;
+    procedure Warn(const aMsg : string); overload;
+    procedure Warn(const aMsg : string; aValues : array of const); overload;
+    procedure Error(const aMsg : string); overload;
+    procedure Error(const aMsg : string; aValues : array of const); overload;
+    procedure Critical(const aMsg : string); overload;
+    procedure Critical(const aMsg : string; aValues : array of const); overload;
+    procedure Trace(const aMsg : string); overload;
+    procedure Trace(const aMsg : string; aValues : array of const); overload;
+    procedure Debug(const aMsg : string); overload;
+    procedure Debug(const aMsg : string; aValues : array of const); overload;
+    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;
+  end;
+
+implementation
+
+{ TQuickLogger }
+
+
+procedure TQuickLogger.Init;
+begin
+  GlobalLogConsoleProvider.LogLevel := LOG_DEBUG;
+  Logger.Providers.Add(GlobalLogConsoleProvider);
+  GlobalLogConsoleProvider.Enabled := True;
+end;
+
+procedure TQuickLogger.Info(const aMsg: string);
+begin
+  Logger.Info(aMsg);
+end;
+
+procedure TQuickLogger.Info(const aMsg: string; aValues: array of const);
+begin
+  Logger.Info(aMsg,aValues);
+end;
+
+procedure TQuickLogger.Succ(const aMsg: string);
+begin
+  Logger.Succ(aMsg);
+end;
+
+procedure TQuickLogger.Succ(const aMsg: string; aParams: array of const);
+begin
+  Logger.Succ(aMsg,aParams);
+end;
+
+procedure TQuickLogger.Done(const aMsg: string);
+begin
+  Logger.Done(aMsg);
+end;
+
+procedure TQuickLogger.Done(const aMsg: string; aValues: array of const);
+begin
+  Logger.Done(aMsg,aValues);
+end;
+
+procedure TQuickLogger.Warn(const aMsg: string);
+begin
+  Logger.Warn(aMsg);
+end;
+
+procedure TQuickLogger.Warn(const aMsg: string; aValues: array of const);
+begin
+  Logger.Warn(aMsg,aValues);
+end;
+
+procedure TQuickLogger.Error(const aMsg: string);
+begin
+  Logger.Error(aMsg);
+end;
+
+procedure TQuickLogger.Error(const aMsg: string; aValues: array of const);
+begin
+  Logger.Error(aMsg,aValues);
+end;
+
+procedure TQuickLogger.Critical(const aMsg: string);
+begin
+  Logger.Critical(aMsg);
+end;
+
+procedure TQuickLogger.Critical(const aMsg: string; aValues: array of const);
+begin
+  Logger.Critical(aMsg,aValues);
+end;
+
+procedure TQuickLogger.Trace(const aMsg: string);
+begin
+  Logger.Trace(aMsg);
+end;
+
+procedure TQuickLogger.Trace(const aMsg: string; aValues: array of const);
+begin
+  Logger.Trace(aMsg,aValues);
+end;
+
+procedure TQuickLogger.Debug(const aMsg: string);
+begin
+  Logger.Debug(aMsg);
+end;
+
+procedure TQuickLogger.Debug(const aMsg: string; aValues: array of const);
+begin
+  Logger.Debug(aMsg,aValues);
+end;
+
+procedure TQuickLogger.&Except(const aMsg: string; aValues: array of const);
+begin
+  Logger.&Except(aMsg,aValues);
+end;
+
+procedure TQuickLogger.&Except(const aMsg: string; aValues: array of const; const aException, aStackTrace: string);
+begin
+  Logger.&Except(aMsg,aValues,aException,aStacktrace);
+end;
+
+procedure TQuickLogger.&Except(const aMsg, aException, aStackTrace: string);
+begin
+  Logger.&Except(aMsg,aException,aStackTrace);
+end;
+
+end.
+

+ 79 - 0
samples/delphi/QuickHttpServer/HttpServer/HttpServerService.dpr

@@ -0,0 +1,79 @@
+program HttpServerService;
+
+{$APPTYPE CONSOLE}
+
+{$R *.res}
+
+uses
+  System.SysUtils,
+  Quick.Commons,
+  Quick.Logger.Intf,
+  Quick.Console,
+  Quick.AppService,
+  Quick.HttpServer,
+  Quick.HttpServer.Request,
+  Quick.HttpServer.Response,
+  HttpServerService.Logger;
+
+type
+  TMyHttpServer = class(THttpServer)
+  public
+    procedure ProcessRequest(aRequest: IHttpRequest; aResponse: IHttpResponse); override;
+  end;
+
+  procedure TMyHttpServer.ProcessRequest(aRequest: IHttpRequest; aResponse: IHttpResponse);
+  begin
+    aResponse.ContentText := 'Hello world!';
+  end;
+
+var
+  HttpServer : TMyHttpServer;
+  Port : Integer;
+  Logger : TQuickLogger;
+
+begin
+  try
+    ReportMemoryLeaksOnShutdown := True;
+
+    //run as console
+    Logger := TQuickLogger.Create;
+    Logger.Init;
+    if not AppService.IsRunningAsService then
+    begin
+      //create server
+      cout('Init server...',etInfo);
+      if ParamCount > 0 then
+      begin
+        Integer.TryParse(ParamStr(1),Port)
+      end;
+      //start server
+      if Port = 0 then Port := 8080;
+      HttpServer := TMyHttpServer.Create('127.0.0.1',Port,False,Logger);
+      try
+        HttpServer.Start;
+        //Wait for Exit
+        cout(' ',ccWhite);
+        cout('Press [Enter] to quit',ccYellow);
+        ConsoleWaitForEnterKey;
+      finally
+        HttpServer.Free;
+      end;
+    end
+    else //run as a service
+    begin
+      AppService.DisplayName := 'Remote Server';
+      AppService.ServiceName := 'RemoteServerSvc';
+      AppService.CanInstallWithOtherName := True;
+      AppService.OnStart := procedure
+                               begin
+                                 HttpServer := TMyHttpServer.Create('127.0.0.1',Port,False,nil);
+                               end;
+      AppService.OnStop := HttpServer.Free;
+      AppService.OnExecute := HttpServer.Start;
+      AppService.CheckParams;
+    end;
+  except
+    on E: Exception do
+      Writeln(E.ClassName, ': ', E.Message);
+  end;
+end.

+ 902 - 0
samples/delphi/QuickHttpServer/HttpServer/HttpServerService.dproj

@@ -0,0 +1,902 @@
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+    <PropertyGroup>
+        <ProjectGuid>{9ADBF486-5A28-48FA-9B08-477C46CDE2F8}</ProjectGuid>
+        <ProjectVersion>18.7</ProjectVersion>
+        <FrameworkType>None</FrameworkType>
+        <MainSource>HttpServerService.dpr</MainSource>
+        <Base>True</Base>
+        <Config Condition="'$(Config)'==''">Debug</Config>
+        <Platform Condition="'$(Platform)'==''">Win32</Platform>
+        <TargetedPlatforms>1</TargetedPlatforms>
+        <AppType>Console</AppType>
+    </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)'=='iOSDevice32' and '$(Base)'=='true') or '$(Base_iOSDevice32)'!=''">
+        <Base_iOSDevice32>true</Base_iOSDevice32>
+        <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)'=='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>
+        <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>HttpServerService</SanitizedProjectName>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Android)'!=''">
+        <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>
+        <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_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>
+    <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>
+    </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>
+        <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;DataSnapServerMidas;DBXDb2Driver;DBXInterBaseDriver;vclactnband;vclFireDAC;emsclientfiredac;DataSnapFireDAC;tethering;FireDACADSDriver;DBXMSSQLDriver;DatasnapConnectorsFreePascal;FireDACMSSQLDriver;vcltouch;vcldb;bindcompfmx;DBXOracleDriver;inetdb;FmxTeeUI;emsedge;FireDACIBDriver;fmx;fmxdae;RadiantShapesFmx;vclib;FlatButtonSet;FireDACDBXDriver;dbexpress;IndyCore;vclx;dsnap;DataSnapCommon;emsclient;FireDACCommon;RESTBackendComponents;DataSnapConnectors;VCLRESTComponents;soapserver;vclie;bindengine;DBXMySQLDriver;FireDACOracleDriver;CloudService;FireDACMySQLDriver;DBXFirebirdDriver;FireDACCommonODBC;FireDACCommonDriver;DataSnapClient;inet;bindcompdbx;IndyIPCommon;vcl;IndyIPServer;DBXSybaseASEDriver;PngComponents;IndySystem;FireDACDb2Driver;dsnapcon;tmsxlsdXE12;FireDACMSAccDriver;fmxFireDAC;FireDACInfxDriver;vclimg;TeeDB;FireDAC;emshosting;FireDACSqliteDriver;FireDACPgDriver;ibmonitor;FireDACASADriver;tmsdXE12;FireDACTDataDriver;DBXOdbcDriver;FMXTee;soaprtl;DbxCommonDriver;ibxpress;Tee;DataSnapServer;xmlrtl;soapmidas;DataSnapNativeClient;fmxobj;vclwinx;ibxbindings;rtl;emsserverresource;DbxClientDriver;FireDACDSDriver;DBXSybaseASADriver;GR32_R;CustomIPTransport;vcldsnap;tmsexdXE12;bindcomp;appanalytics;DBXInformixDriver;IndyIPClient;bindcompvcl;TeeUI;dbxcds;VclSmp;adortl;FireDACODBCDriver;DataSnapIndy10ServerTransport;RadiantShapesFmx_Design;dsnapxml;DataSnapProviderClient;dbrtl;inetdbxpress;FireDACMongoDBDriver;IndyProtocols;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">HttpServerService.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\HttpServerService.exe" Configuration="Debug" Class="ProjectOutput">
+                    <Platform Name="Win32">
+                        <RemoteName>HttpServerService.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>
+                </DeployClass>
+                <DeployClass Name="AndroidFileProvider">
+                    <Platform Name="Android">
+                        <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>
+                </DeployClass>
+                <DeployClass Name="AndroidLibnativeMipsFile">
+                    <Platform Name="Android">
+                        <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>
+                </DeployClass>
+                <DeployClass Name="AndroidSplashImageDef">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidSplashStyles">
+                    <Platform Name="Android">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidSplashStylesV21">
+                    <Platform Name="Android">
+                        <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>
+                </DeployClass>
+                <DeployClass Name="Android_DefaultAppIcon">
+                    <Platform Name="Android">
+                        <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>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon36">
+                    <Platform Name="Android">
+                        <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>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon72">
+                    <Platform Name="Android">
+                        <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>
+                </DeployClass>
+                <DeployClass Name="Android_NotificationIcon24">
+                    <Platform Name="Android">
+                        <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>
+                </DeployClass>
+                <DeployClass Name="Android_NotificationIcon48">
+                    <Platform Name="Android">
+                        <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>
+                </DeployClass>
+                <DeployClass Name="Android_NotificationIcon96">
+                    <Platform Name="Android">
+                        <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>
+                </DeployClass>
+                <DeployClass Name="Android_SplashImage470">
+                    <Platform Name="Android">
+                        <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>
+                </DeployClass>
+                <DeployClass Name="Android_SplashImage960">
+                    <Platform Name="Android">
+                        <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>
+                </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="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="iPad_Launch1024x768">
+                    <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_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">
+                    <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_Launch1668x2388">
+                    <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_Launch2048x1536">
+                    <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_Launch2048x2732">
+                    <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_Launch2224">
+                    <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_Launch2388x1668">
+                    <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_Launch2732x2048">
+                    <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_Launch768x1024">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch1125">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch1136x640">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch1242">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch1242x2688">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch1334">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch1792">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch2208">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch2436">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch2688x1242">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch320">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch640">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch640x1136">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch750">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch828">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectAndroidManifest">
+                    <Platform Name="Android">
+                        <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="ProjectiOSDeviceResourceRules">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <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="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="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="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"/>
+            </Deployment>
+            <Platforms>
+                <Platform value="Android">False</Platform>
+                <Platform value="iOSDevice32">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>
+        </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>

BIN
samples/delphi/QuickHttpServer/HttpServer/HttpServerService.res


+ 43 - 0
samples/delphi/QuickIOC/AndroidManifest.template.xml

@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- BEGIN_INCLUDE(manifest) -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="%package%"
+        android:versionCode="%versionCode%"
+        android:versionName="%versionName%"
+        android:installLocation="%installLocation%">
+
+    <uses-sdk android:minSdkVersion="%minSdkVersion%" android:targetSdkVersion="%targetSdkVersion%" />
+    <%uses-permission%>
+    <uses-feature android:glEsVersion="0x00020000" android:required="True"/>
+    <application android:persistent="%persistent%" 
+        android:restoreAnyVersion="%restoreAnyVersion%" 
+        android:label="%label%" 
+        android:debuggable="%debuggable%" 
+        android:largeHeap="%largeHeap%"
+        android:icon="%icon%"
+        android:theme="%theme%"
+        android:hardwareAccelerated="%hardwareAccelerated%"
+        android:resizeableActivity="false">
+
+        <%provider%>
+        <%application-meta-data%>
+        <%services%>
+        <!-- Our activity is a subclass of the built-in NativeActivity framework class.
+             This will take care of integrating with our NDK code. -->
+        <activity android:name="com.embarcadero.firemonkey.FMXNativeActivity"
+                android:label="%activityLabel%"
+                android:configChanges="orientation|keyboard|keyboardHidden|screenSize"
+                android:launchMode="singleTask">
+            <!-- Tell NativeActivity the name of our .so -->
+            <meta-data android:name="android.app.lib_name"
+                android:value="%libNameValue%" />
+            <intent-filter>  
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter> 
+        </activity>
+        <%activity%>
+        <%receivers%>
+    </application>
+</manifest>
+<!-- END_INCLUDE(manifest) -->

+ 279 - 0
samples/delphi/QuickIOC/IOCdemo.dpr

@@ -0,0 +1,279 @@
+program IOCdemo;
+
+{$APPTYPE CONSOLE}
+
+{$R *.res}
+
+uses
+  System.SysUtils,
+  Quick.Commons,
+  Quick.Console,
+  Quick.IOC;
+
+type
+  IMathService = interface
+  ['{E8BEE282-3828-4F27-869D-C808296F8CA2}']
+    procedure IncNumsOperations;
+    function NumOperations : Integer;
+  end;
+
+  ISumService = interface(IMathService)
+  ['{7580F5F6-0132-49F3-A22A-A2E93E53E8A7}']
+    function Sum(a, b : Integer) : Integer;
+  end;
+
+  IMultService = interface(IMathService)
+  ['{56772C4B-70AF-4BB7-9DFE-E2D67912DDC1}']
+    function Mult(a, b : Integer) : Integer;
+  end;
+
+  TMathService = class(TInterfacedObject,IMathService)
+  private
+    fNumOperations : Integer;
+  public
+    constructor Create;
+    procedure IncNumsOperations;
+    function NumOperations : Integer;
+  end;
+
+  TSumService = class(TMathService,ISumService)
+  public
+    function Sum(a, b : Integer) : Integer;
+  end;
+
+  TMultService = class(TMathService,IMultService)
+  public
+    function Mult(a, b : Integer) : Integer;
+  end;
+
+  IBigService = interface
+  ['{AE7E7617-02BD-48C9-A370-49566A563C38}']
+    function GetNumOperations : Integer;
+    function Sum(a, b : Integer) : Integer;
+    function Mult(a, b : Integer) : Integer;
+    function SumService : ISumService;
+    function MultService : IMultService;
+    property NumOperations : Integer read GetNumOperations;
+  end;
+  TBigService = class(TInterfacedObject,IBigService)
+  private
+    fSumService : ISumService;
+    fMultService : IMultService;
+    fNumOperations : Integer;
+    function GetNumOperations : Integer;
+    procedure IncNumOperations;
+  public
+    constructor Create(aSumService : ISumService; aMultService : IMultService);
+    function Sum(a, b : Integer) : Integer;
+    function Mult(a, b : Integer) : Integer;
+    function SumService : ISumService;
+    function MultService : IMultService;
+    property NumOperations : Integer read GetNumOperations;
+  end;
+
+  TDivideService = class
+  private
+    fNumOperations : Integer;
+    fRound : Boolean;
+  public
+    constructor Create(aRound : Boolean);
+    property NumOperations : Integer read fNumOperations;
+    function Divide(a,b : Integer) : Integer;
+  end;
+
+{ TSumService }
+
+function TSumService.Sum(a, b: Integer): Integer;
+begin
+  Result := a + b;
+  IncNumsOperations;
+end;
+
+{ TMultService }
+
+function TMultService.Mult(a, b: Integer): Integer;
+begin
+  Result := a * b;
+  IncNumsOperations;
+end;
+
+{ TBigService }
+
+constructor TBigService.Create(aSumService: ISumService; aMultService: IMultService);
+begin
+  fSumService := aSumService;
+  fMultService := aMultService;
+end;
+
+function TBigService.Sum(a, b: Integer): Integer;
+begin
+  Result := fSumService.Sum(a,b);
+  IncNumOperations;
+end;
+
+function TBigService.SumService: ISumService;
+begin
+  Result := fSumService;
+end;
+
+function TBigService.GetNumOperations: Integer;
+begin
+  Result := fNumOperations;
+end;
+
+procedure TBigService.IncNumOperations;
+begin
+  Inc(fNumOperations);
+end;
+
+function TBigService.Mult(a, b: Integer): Integer;
+begin
+  Result := fMultService.Mult(a,b);
+  IncNumOperations;
+end;
+
+function TBigService.MultService: IMultService;
+begin
+  Result := fMultService;
+end;
+
+var
+  iocContainer : TIocContainer;
+  sumservice : ISumService;
+  multservice : IMultService;
+  bigservice : IBigService;
+  divideservice : TDivideService;
+  res : Integer;
+  i : Integer;
+  times : Integer;
+  numoperations : Integer;
+
+{ TMathService }
+
+constructor TMathService.Create;
+begin
+  fNumOperations := 0;
+end;
+
+procedure TMathService.IncNumsOperations;
+begin
+  Inc(fNumOperations);
+end;
+
+function TMathService.NumOperations: Integer;
+begin
+  Result := fNumOperations;
+end;
+
+{ TDivideService }
+
+constructor TDivideService.Create(aRound : Boolean);
+begin
+  fNumOperations := 0;
+  fRound := aRound;
+end;
+
+function TDivideService.Divide(a, b: Integer): Integer;
+begin
+  if fRound then Result := Round(a / b)
+    else Result := Trunc(a / b);
+  Inc(fNumOperations);
+end;
+
+begin
+  try
+    ReportMemoryLeaksOnShutdown := True;
+
+    iocContainer := TIocContainer.Create;
+    iocContainer.RegisterType<ISumService,TSumService>.AsSingleTon.DelegateTo(function : TSumService
+                                                                              begin
+                                                                                Result := TSumService.Create;
+                                                                              end);
+    iocContainer.RegisterType<IMultService,TMultService>.AsTransient;
+    iocContainer.RegisterType<IBigService,TBigService>('one').AsSingleTon;
+    iocContainer.RegisterType<IBigService,TBigService>('other').AsTransient;
+
+    iocContainer.RegisterInstance<TDivideService>('one').AsSingleton.DelegateTo(function : TDivideService
+                                                                                begin
+                                                                                  Result := TDivideService.Create(True);
+                                                                                end);
+    iocContainer.RegisterInstance<TDivideService>('other').AsTransient.DelegateTo(function : TDivideService
+                                                                                begin
+                                                                                  Result := TDivideService.Create(True);
+                                                                                end);
+
+    times := 100;
+    res := 0;
+
+    //test1: class injection as singleton
+    for i := 1 to times do
+    begin
+      sumservice := iocContainer.Resolve<ISumService>;
+      res := sumservice.Sum(2,2);
+    end;
+    if sumservice.NumOperations = times then cout('Test1: Class injection as Singleton test ok',etSuccess)
+      else cout('Test1: Class injection as Singleton test error',etError);
+    cout('SumService.Sum = %d (calls: %d)',[res,sumservice.NumOperations],etInfo);
+
+    //test2: class injection as transient
+    for i := 1 to times do
+    begin
+      multservice := iocContainer.Resolve<IMultService>;
+      res := multservice.Mult(2,4);
+    end;
+    if multservice.NumOperations = 1 then cout('Test2: Class injection as Transient test ok',etSuccess)
+      else cout('Test2: Class injection as Transient test error',etError);
+    cout('MultService.Mult = %d (calls: %d)',[res,multservice.NumOperations],etInfo);
+
+    //test3: constructor injection as singleton
+    for i := 1 to times do
+    begin
+      bigservice := iocContainer.Resolve<IBigService>('one');
+      res := bigservice.Sum(2,2);
+    end;
+    if bigservice.NumOperations = times then cout('Test3: Constructor injection as Singleton test ok',etSuccess)
+      else cout('Test3: Constructor injection as Singleton test error',etError);
+    cout('BigService.Sum = %d (calls: %d to BigService / calls: %d to SumService (as singleton))',[res,bigservice.NumOperations,bigservice.sumservice.NumOperations],etInfo);
+
+    //test4: constructor injection as transient
+    for i := 1 to times do
+    begin
+      bigservice := iocContainer.Resolve<IBigService>('other');
+      res := bigservice.Mult(2,4);
+    end;
+    if bigservice.NumOperations = 1 then cout('Test4: Constructor injection as Transient test ok',etSuccess)
+      else cout('Test4: Constructor injection as Transient test error',etError);
+    cout('BigService.Mult = %d (calls: %d to BigService / calls: %d to MultService (as transient))',[res,bigservice.NumOperations,bigservice.multservice.NumOperations],etInfo);
+
+    //test5: class instance injection as singleton
+    for i := 1 to times do
+    begin
+      divideservice := iocContainer.Resolve<TDivideService>('one');
+      res := divideservice.Divide(100,2);
+    end;
+    if divideservice.NumOperations = times then cout('Test5: Class instance injection as Singleton test ok',etSuccess)
+      else cout('Test5: Class instance injection as Singleton test error',etError);
+    cout('DivideService.Divide = %d (calls: %d)',[res,divideservice.NumOperations],etInfo);
+
+    //test6: class instance injection as transient
+    for i := 1 to times do
+    begin
+      divideservice := iocContainer.Resolve<TDivideService>('other');
+      res := divideservice.Divide(100,2);
+      numoperations := divideservice.NumOperations;
+      //transient instances must be manual free
+      divideservice.Free;
+    end;
+    if numoperations = 1 then cout('Test6: Class instance injection as Transient test ok',etSuccess)
+      else cout('Test6: Class instance injection as Transient test error',etError);
+    cout('DivideService.Divide = %d (calls: %d)',[res,numoperations],etInfo);
+
+    cout('Press <ENTER> to Exit',ccYellow);
+    ConsoleWaitForEnterKey;
+
+    iocContainer.Free;
+  except
+    on E: Exception do
+      Writeln(E.ClassName, ': ', E.Message);
+  end;
+end.

File diff suppressed because it is too large
+ 109 - 0
samples/delphi/QuickIOC/IOCdemo.dproj


BIN
samples/delphi/QuickIOC/IOCdemo.res


+ 153 - 0
samples/delphi/QuickMemoryCache/MemoryCache/MemCacheTest.dpr

@@ -0,0 +1,153 @@
+program MemCacheTest;
+
+{$APPTYPE CONSOLE}
+
+{$R *.res}
+
+uses
+  System.SysUtils,
+  Quick.Commons,
+  Quick.Console,
+  Quick.Threads,
+  Quick.Chrono,
+  Quick.Format,
+  Quick.MemoryCache;
+
+type
+  TMyObject = class
+  private
+    fTestStr : string;
+    fTestInt : Integer;
+  public
+    property TestStr : string read fTestStr write fTestStr;
+    property TestInt : Integer read fTestInt write fTestInt;
+  end;
+
+var
+  cache : TMemoryCache<TMyObject>;
+  valueobj : TMyObject;
+  backgroundtasks : TBackgroundTasks;
+  i : Integer;
+  n : Integer;
+  chrono : TChronometer;
+  dummystr : string;
+
+begin
+
+  ReportMemoryLeaksOnShutdown := True;
+
+  backgroundtasks := TBackgroundTasks.Create(20,100);
+
+  cache := TMemoryCache<TMyObject>.Create(10);
+  //cache := TMemoryCache.Create(10,nil,TCacheCompressorLZO.Create);
+  cache.Compression := True;
+  cache.OnEndPurgerJob := procedure(aRemovedEntries : Integer)
+                          begin
+                            cout(Format('Purger job finished (Removed: %s /CachedObjects: %s / CacheSize: %s)',[NumberToStr(aRemovedEntries),NumberToStr(cache.CachedObjects),FormatBytes(cache.CacheSize)]),ccMagenta);
+                          end;
+
+  cache.OnPurgeJobError := procedure(const aErrorMsg : string)
+                           begin
+                             coutFmt('Error flushing cache expireds (%s)',[aErrorMsg],etError);
+                           end;
+
+  //set object to cache
+  valueobj := TMyObject.Create;
+  try
+    valueobj.TestStr := 'TestOk';
+    valueobj.TestInt := 7;
+    cache.SetValue('obj1',valueobj);
+  finally
+    valueobj.Free;
+  end;
+
+  //get object from cache
+  //valueobj := TMyObject.Create;
+  try
+    //cache.TryGetValue('Obj1',valueobj,TMyObject);
+    cache.TryGetValue('obj1',valueobj);
+    coutFmt('Got Id(obj1) from cache: (TestStr = %s / TestIn = %d)',[valueobj.TestStr,valueobj.TestInt],etSuccess);
+  finally
+    valueobj.Free;
+  end;
+
+  chrono := TChronometer.Create(False);
+  //concurrent read/writes
+  dummystr := '';
+
+  cout('Preparing data..',ccWhite);
+
+  //for i := 0 to 1024 do dummystr := dummystr + Chr(Random(255));
+  dummystr := RandomString(1024);
+  n := 0;
+  for i := 1 to 100000 do
+  begin
+    Inc(n);
+    if n < 9 then
+    begin
+      backgroundtasks.AddTask(procedure(task : ITask)
+                           var obj : TMyObject;
+                          begin
+                            if not cache.TryGetValue('obj1',obj) then
+                            begin
+                              coutFmt('Value %d not in cache or expired',[1],etWarning);
+                              obj := TMyObject.Create;
+                              try
+                                obj.TestStr := 'TestOk';
+                                obj.TestInt := 7;
+                                cache.SetValue('obj1',obj,1000);
+                              finally
+                                obj.Free;
+                              end;
+                            end;
+                            //coutFmt('Get Id(1) from cache = %s',[obj.TestStr],etSuccess);
+                          end
+                  ).OnException(procedure(task : ITask; aException : Exception)
+                          begin
+                            cout(aException.Message,etError);
+                          end
+                  ).Run;
+    end
+    else
+    begin
+      n := 0;
+      backgroundtasks.AddTask(procedure(task : ITask)
+                           var
+                            obj : TMyObject;
+                          begin
+                            obj := TMyObject.Create;
+                            try
+                              obj.TestStr := 'TestOk';
+                              obj.TestInt := 7;
+                              cache.SetValue(Random(1000000).ToString,obj,Random(5000));
+                            finally
+                              obj.Free;
+                            end;
+                            //coutFmt('Set Id(1) to cache = %s',[obj.TestStr],etSuccess);
+                          end
+                  ).OnException(procedure(task : ITask; aException : Exception)
+                          begin
+                            cout(aException.Message,etError);
+                          end
+                  ).Run;
+    end;
+  end;
+  backgroundtasks.AddTask(procedure(task : ITask)
+                          begin
+                            chrono.Stop;
+                            coutFmt('Performance: %s Combined cache IO Read/Writes in %s',[NumberToStr(i),chrono.ElapsedTime],etWarning);
+                            coutFmt('Cached Objects: %s / Cache Size: %s',[NumberToStr(cache.CachedObjects),FormatBytes(cache.CacheSize)],etInfo);
+                            cout('Wait to see how cache is expiring every 10 seconds or press <ENTER> to Exit',ccYellow);
+                            //cache.Flush;
+                          end
+                  ).Run;
+  cout('Stress caching test launched...',ccWhite);
+  backgroundtasks.Start;
+  chrono.Start;
+
+  ConsoleWaitForEnterKey;
+  coutFmt('Cached Objects: %s / Cache Size: %s',[NumberToStr(cache.CachedObjects),FormatBytes(cache.CacheSize)],etInfo);
+  cache.Free;
+  chrono.Free;
+  backgroundtasks.Free;
+end.

+ 916 - 0
samples/delphi/QuickMemoryCache/MemoryCache/MemCacheTest.dproj

@@ -0,0 +1,916 @@
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+    <PropertyGroup>
+        <ProjectGuid>{764CAF4F-133A-42F7-AE8D-93D32C5D60D9}</ProjectGuid>
+        <ProjectVersion>18.7</ProjectVersion>
+        <FrameworkType>None</FrameworkType>
+        <MainSource>MemCacheTest.dpr</MainSource>
+        <Base>True</Base>
+        <Config Condition="'$(Config)'==''">Debug</Config>
+        <Platform Condition="'$(Platform)'==''">Win64</Platform>
+        <TargetedPlatforms>7</TargetedPlatforms>
+        <AppType>Console</AppType>
+    </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)'=='iOSDevice32' and '$(Base)'=='true') or '$(Base_iOSDevice32)'!=''">
+        <Base_iOSDevice32>true</Base_iOSDevice32>
+        <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)'=='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>
+        <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>MemCacheTest</SanitizedProjectName>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Android)'!=''">
+        <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>
+        <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>
+        <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_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>
+    <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>
+    </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>
+        <VerInfo_Keys>CFBundleName=$(MSBuildProjectName);CFBundleDisplayName=$(MSBuildProjectName);CFBundleIdentifier=$(MSBuildProjectName);CFBundleVersion=1.0.0;CFBundleShortVersionString=1.0.0;CFBundlePackageType=APPL;CFBundleSignature=????;CFBundleAllowMixedLocalizations=YES;CFBundleExecutable=$(MSBuildProjectName);NSHighResolutionCapable=true;LSApplicationCategoryType=public.app-category.utilities;NSLocationUsageDescription=The reason for accessing the location information of the user;NSContactsUsageDescription=The reason for accessing the contacts</VerInfo_Keys>
+        <BT_BuildType>Debug</BT_BuildType>
+    </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>
+        <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;DataSnapServerMidas;DBXDb2Driver;DBXInterBaseDriver;vclactnband;vclFireDAC;emsclientfiredac;DataSnapFireDAC;tethering;FireDACADSDriver;DBXMSSQLDriver;DatasnapConnectorsFreePascal;FireDACMSSQLDriver;vcltouch;vcldb;bindcompfmx;DBXOracleDriver;inetdb;FmxTeeUI;emsedge;FireDACIBDriver;fmx;fmxdae;RadiantShapesFmx;vclib;FlatButtonSet;FireDACDBXDriver;dbexpress;IndyCore;vclx;dsnap;DataSnapCommon;emsclient;FireDACCommon;RESTBackendComponents;DataSnapConnectors;VCLRESTComponents;soapserver;vclie;bindengine;DBXMySQLDriver;FireDACOracleDriver;CloudService;FireDACMySQLDriver;DBXFirebirdDriver;FireDACCommonODBC;FireDACCommonDriver;DataSnapClient;inet;bindcompdbx;IndyIPCommon;vcl;IndyIPServer;DBXSybaseASEDriver;PngComponents;IndySystem;FireDACDb2Driver;dsnapcon;tmsxlsdXE12;FireDACMSAccDriver;fmxFireDAC;FireDACInfxDriver;vclimg;TeeDB;FireDAC;emshosting;FireDACSqliteDriver;FireDACPgDriver;ibmonitor;FireDACASADriver;tmsdXE12;FireDACTDataDriver;DBXOdbcDriver;FMXTee;soaprtl;DbxCommonDriver;ibxpress;Tee;DataSnapServer;xmlrtl;soapmidas;DataSnapNativeClient;fmxobj;vclwinx;ibxbindings;rtl;emsserverresource;DbxClientDriver;FireDACDSDriver;DBXSybaseASADriver;GR32_R;CustomIPTransport;vcldsnap;tmsexdXE12;bindcomp;appanalytics;DBXInformixDriver;IndyIPClient;bindcompvcl;TeeUI;dbxcds;VclSmp;adortl;FireDACODBCDriver;DataSnapIndy10ServerTransport;RadiantShapesFmx_Design;dsnapxml;DataSnapProviderClient;dbrtl;inetdbxpress;FireDACMongoDBDriver;IndyProtocols;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">MemCacheTest.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="Win64\Debug\MemCacheTest.exe" Configuration="Debug" Class="ProjectOutput">
+                    <Platform Name="Win64">
+                        <RemoteName>MemCacheTest.exe</RemoteName>
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile LocalName="Win32\Debug\MemCacheTest.exe" Configuration="Debug" Class="ProjectOutput">
+                    <Platform Name="Win32">
+                        <RemoteName>MemCacheTest.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>
+                </DeployClass>
+                <DeployClass Name="AndroidFileProvider">
+                    <Platform Name="Android">
+                        <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>
+                </DeployClass>
+                <DeployClass Name="AndroidLibnativeMipsFile">
+                    <Platform Name="Android">
+                        <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>
+                </DeployClass>
+                <DeployClass Name="AndroidSplashImageDef">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidSplashStyles">
+                    <Platform Name="Android">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidSplashStylesV21">
+                    <Platform Name="Android">
+                        <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>
+                </DeployClass>
+                <DeployClass Name="Android_DefaultAppIcon">
+                    <Platform Name="Android">
+                        <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>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon36">
+                    <Platform Name="Android">
+                        <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>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon72">
+                    <Platform Name="Android">
+                        <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>
+                </DeployClass>
+                <DeployClass Name="Android_NotificationIcon24">
+                    <Platform Name="Android">
+                        <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>
+                </DeployClass>
+                <DeployClass Name="Android_NotificationIcon48">
+                    <Platform Name="Android">
+                        <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>
+                </DeployClass>
+                <DeployClass Name="Android_NotificationIcon96">
+                    <Platform Name="Android">
+                        <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>
+                </DeployClass>
+                <DeployClass Name="Android_SplashImage470">
+                    <Platform Name="Android">
+                        <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>
+                </DeployClass>
+                <DeployClass Name="Android_SplashImage960">
+                    <Platform Name="Android">
+                        <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>
+                </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="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="iPad_Launch1024x768">
+                    <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_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">
+                    <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_Launch1668x2388">
+                    <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_Launch2048x1536">
+                    <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_Launch2048x2732">
+                    <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_Launch2224">
+                    <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_Launch2388x1668">
+                    <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_Launch2732x2048">
+                    <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_Launch768x1024">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch1125">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch1136x640">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch1242">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch1242x2688">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch1334">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch1792">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch2208">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch2436">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch2688x1242">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch320">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch640">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch640x1136">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch750">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch828">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectAndroidManifest">
+                    <Platform Name="Android">
+                        <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="ProjectiOSDeviceResourceRules">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <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="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="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="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"/>
+            </Deployment>
+            <Platforms>
+                <Platform value="Android">False</Platform>
+                <Platform value="iOSDevice32">False</Platform>
+                <Platform value="iOSDevice64">False</Platform>
+                <Platform value="iOSSimulator">False</Platform>
+                <Platform value="OSX32">True</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>

BIN
samples/delphi/QuickMemoryCache/MemoryCache/MemCacheTest.res


+ 119 - 0
samples/delphi/QuickMemoryCache/MemoryCache/MemCacheTest2.dpr

@@ -0,0 +1,119 @@
+program MemCacheTest2;
+
+{$APPTYPE CONSOLE}
+
+{$R *.res}
+
+uses
+  System.SysUtils,
+  Quick.Commons,
+  Quick.Console,
+  Quick.Threads,
+  Quick.Chrono,
+  Quick.Format,
+  Quick.MemoryCache;
+
+type
+  TMyObject = class
+  private
+    fTestStr : string;
+    fTestInt : Integer;
+  public
+    property TestStr : string read fTestStr write fTestStr;
+    property TestInt : Integer read fTestInt write fTestInt;
+  end;
+
+var
+  cache : TMemoryCache<string>;
+  valuestr : string;
+  valueint : Integer;
+  valuefloat : Extended;
+  valuebool : Boolean;
+  valueobj : TMyObject;
+  backgroundtasks : TBackgroundTasks;
+  i : Integer;
+  n : Integer;
+  chrono : TChronometer;
+  dummystr : string;
+  arr : TArray<string>;
+
+begin
+
+  ReportMemoryLeaksOnShutdown := True;
+
+  backgroundtasks := TBackgroundTasks.Create(20,100);
+
+  cache := TMemoryCache<string>.Create(10);
+  //cache := TMemoryCache.Create(10,nil,TCacheCompressorLZO.Create);
+  cache.Compression := True;
+  cache.OnEndPurgerJob := procedure(aRemovedEntries : Integer)
+                          begin
+                            cout(Format('Purger job finished (Removed: %s /CachedObjects: %s / CacheSize: %s)',[NumberToStr(aRemovedEntries),NumberToStr(cache.CachedObjects),FormatBytes(cache.CacheSize)]),ccMagenta);
+                          end;
+
+  cache.OnPurgeJobError := procedure(const aErrorMsg : string)
+                           begin
+                             coutFmt('Error flushing cache expireds (%s)',[aErrorMsg],etError);
+                           end;
+
+  chrono := TChronometer.Create(False);
+  //concurrent read/writes
+  dummystr := '';
+
+  cout('Preparing data..',ccWhite);
+
+  //for i := 0 to 1024 do dummystr := dummystr + Chr(Random(255));
+  cache.SetValue('obj1',dummystr,30000);
+  dummystr := RandomString(1024);
+  n := 0;
+  for i := 1 to 100000 do
+  begin
+    Inc(n);
+    if n < 9 then
+    begin
+      backgroundtasks.AddTask(procedure(task : ITask)
+                          var
+                            a : string;
+                          begin
+                            if not cache.TryGetValue('obj1',a) then
+                            begin
+                              coutFmt('Value %d not in cache or expired',[1],etWarning);
+                              cache.SetValue('obj1',dummystr,1000);
+                            end;
+                            //coutFmt('Get Id(1) from cache = %s',[a],etSuccess);
+                          end
+                  ).Run;
+    end
+    else
+    begin
+      n := 0;
+      backgroundtasks.AddTask(procedure(task : ITask)
+                           var
+                            a : string;
+                          begin
+                            a := Random(1000000).ToString;
+                            cache.SetValue(a,dummystr,Random(5000));
+                            //coutFmt('Set Id(1) to cache = %s',[a],etSuccess);
+                          end
+                  ).Run;
+    end;
+  end;
+  backgroundtasks.AddTask(procedure(task : ITask)
+                          begin
+                            chrono.Stop;
+                            coutFmt('Performance: %s Combined cache IO Read/Writes in %s',[NumberToStr(i),chrono.ElapsedTime],etWarning);
+                            coutFmt('Cached Objects: %s / Cache Size: %s',[NumberToStr(cache.CachedObjects),FormatBytes(cache.CacheSize)],etInfo);
+                            cout('Wait to see how cache is expiring every 10 seconds or press <ENTER> to Exit',ccYellow);
+                            //cache.Flush;
+                          end
+                  ).Run;
+  cout('Stress caching test launched...',ccWhite);
+  backgroundtasks.Start;
+  chrono.Start;
+
+  ConsoleWaitForEnterKey;
+  coutFmt('Cached Objects: %s / Cache Size: %s',[NumberToStr(cache.CachedObjects),FormatBytes(cache.CacheSize)],etInfo);
+  cache.Free;
+  chrono.Free;
+  backgroundtasks.Free;
+end.

+ 922 - 0
samples/delphi/QuickMemoryCache/MemoryCache/MemCacheTest2.dproj

@@ -0,0 +1,922 @@
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+    <PropertyGroup>
+        <ProjectGuid>{764CAF4F-133A-42F7-AE8D-93D32C5D60D9}</ProjectGuid>
+        <ProjectVersion>18.7</ProjectVersion>
+        <FrameworkType>None</FrameworkType>
+        <MainSource>MemCacheTest2.dpr</MainSource>
+        <Base>True</Base>
+        <Config Condition="'$(Config)'==''">Debug</Config>
+        <Platform Condition="'$(Platform)'==''">Win64</Platform>
+        <TargetedPlatforms>7</TargetedPlatforms>
+        <AppType>Console</AppType>
+    </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)'=='iOSDevice32' and '$(Base)'=='true') or '$(Base_iOSDevice32)'!=''">
+        <Base_iOSDevice32>true</Base_iOSDevice32>
+        <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)'=='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>
+        <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>MemCacheTest2</SanitizedProjectName>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Android)'!=''">
+        <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>
+        <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>
+        <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_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>
+    <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>
+    </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>
+        <VerInfo_Keys>CFBundleName=$(MSBuildProjectName);CFBundleDisplayName=$(MSBuildProjectName);CFBundleIdentifier=$(MSBuildProjectName);CFBundleVersion=1.0.0;CFBundleShortVersionString=1.0.0;CFBundlePackageType=APPL;CFBundleSignature=????;CFBundleAllowMixedLocalizations=YES;CFBundleExecutable=$(MSBuildProjectName);NSHighResolutionCapable=true;LSApplicationCategoryType=public.app-category.utilities;NSLocationUsageDescription=The reason for accessing the location information of the user;NSContactsUsageDescription=The reason for accessing the contacts</VerInfo_Keys>
+        <BT_BuildType>Debug</BT_BuildType>
+    </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>
+        <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;DataSnapServerMidas;DBXDb2Driver;DBXInterBaseDriver;vclactnband;vclFireDAC;emsclientfiredac;DataSnapFireDAC;tethering;FireDACADSDriver;DBXMSSQLDriver;DatasnapConnectorsFreePascal;FireDACMSSQLDriver;vcltouch;vcldb;bindcompfmx;DBXOracleDriver;inetdb;FmxTeeUI;emsedge;FireDACIBDriver;fmx;fmxdae;RadiantShapesFmx;vclib;FlatButtonSet;FireDACDBXDriver;dbexpress;IndyCore;vclx;dsnap;DataSnapCommon;emsclient;FireDACCommon;RESTBackendComponents;DataSnapConnectors;VCLRESTComponents;soapserver;vclie;bindengine;DBXMySQLDriver;FireDACOracleDriver;CloudService;FireDACMySQLDriver;DBXFirebirdDriver;FireDACCommonODBC;FireDACCommonDriver;DataSnapClient;inet;bindcompdbx;IndyIPCommon;vcl;IndyIPServer;DBXSybaseASEDriver;PngComponents;IndySystem;FireDACDb2Driver;dsnapcon;tmsxlsdXE12;FireDACMSAccDriver;fmxFireDAC;FireDACInfxDriver;vclimg;TeeDB;FireDAC;emshosting;FireDACSqliteDriver;FireDACPgDriver;ibmonitor;FireDACASADriver;tmsdXE12;FireDACTDataDriver;DBXOdbcDriver;FMXTee;soaprtl;DbxCommonDriver;ibxpress;Tee;DataSnapServer;xmlrtl;soapmidas;DataSnapNativeClient;fmxobj;vclwinx;ibxbindings;rtl;emsserverresource;DbxClientDriver;FireDACDSDriver;DBXSybaseASADriver;GR32_R;CustomIPTransport;vcldsnap;tmsexdXE12;bindcomp;appanalytics;DBXInformixDriver;IndyIPClient;bindcompvcl;TeeUI;dbxcds;VclSmp;adortl;FireDACODBCDriver;DataSnapIndy10ServerTransport;RadiantShapesFmx_Design;dsnapxml;DataSnapProviderClient;dbrtl;inetdbxpress;FireDACMongoDBDriver;IndyProtocols;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">MemCacheTest2.dpr</Source>
+                </Source>
+            </Delphi.Personality>
+            <Deployment Version="3">
+                <DeployFile LocalName="Win64\Debug\MemCacheTest2.rsm" Configuration="Debug" Class="DebugSymbols">
+                    <Platform Name="Win64">
+                        <RemoteName>MemCacheTest2.rsm</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>
+                <DeployFile LocalName="Win64\Debug\MemCacheTest2.exe" Configuration="Debug" Class="ProjectOutput">
+                    <Platform Name="Win64">
+                        <RemoteName>MemCacheTest2.exe</RemoteName>
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile LocalName="Win32\Debug\MemCacheTest2.exe" Configuration="Debug" Class="ProjectOutput">
+                    <Platform Name="Win32">
+                        <RemoteName>MemCacheTest2.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>
+                </DeployClass>
+                <DeployClass Name="AndroidFileProvider">
+                    <Platform Name="Android">
+                        <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>
+                </DeployClass>
+                <DeployClass Name="AndroidLibnativeMipsFile">
+                    <Platform Name="Android">
+                        <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>
+                </DeployClass>
+                <DeployClass Name="AndroidSplashImageDef">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidSplashStyles">
+                    <Platform Name="Android">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidSplashStylesV21">
+                    <Platform Name="Android">
+                        <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>
+                </DeployClass>
+                <DeployClass Name="Android_DefaultAppIcon">
+                    <Platform Name="Android">
+                        <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>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon36">
+                    <Platform Name="Android">
+                        <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>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon72">
+                    <Platform Name="Android">
+                        <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>
+                </DeployClass>
+                <DeployClass Name="Android_NotificationIcon24">
+                    <Platform Name="Android">
+                        <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>
+                </DeployClass>
+                <DeployClass Name="Android_NotificationIcon48">
+                    <Platform Name="Android">
+                        <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>
+                </DeployClass>
+                <DeployClass Name="Android_NotificationIcon96">
+                    <Platform Name="Android">
+                        <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>
+                </DeployClass>
+                <DeployClass Name="Android_SplashImage470">
+                    <Platform Name="Android">
+                        <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>
+                </DeployClass>
+                <DeployClass Name="Android_SplashImage960">
+                    <Platform Name="Android">
+                        <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>
+                </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="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="iPad_Launch1024x768">
+                    <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_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">
+                    <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_Launch1668x2388">
+                    <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_Launch2048x1536">
+                    <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_Launch2048x2732">
+                    <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_Launch2224">
+                    <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_Launch2388x1668">
+                    <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_Launch2732x2048">
+                    <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_Launch768x1024">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch1125">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch1136x640">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch1242">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch1242x2688">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch1334">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch1792">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch2208">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch2436">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch2688x1242">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch320">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch640">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch640x1136">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch750">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch828">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectAndroidManifest">
+                    <Platform Name="Android">
+                        <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="ProjectiOSDeviceResourceRules">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <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="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="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="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"/>
+            </Deployment>
+            <Platforms>
+                <Platform value="Android">False</Platform>
+                <Platform value="iOSDevice32">False</Platform>
+                <Platform value="iOSDevice64">False</Platform>
+                <Platform value="iOSSimulator">False</Platform>
+                <Platform value="OSX32">True</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>

BIN
samples/delphi/QuickMemoryCache/MemoryCache/MemCacheTest2.res


+ 172 - 0
samples/delphi/QuickMemoryCache/MemoryCacheVariant/MemCacheVariantTest.dpr

@@ -0,0 +1,172 @@
+program MemCacheVariantTest;
+
+{$APPTYPE CONSOLE}
+
+{$R *.res}
+
+uses
+  System.SysUtils,
+  Quick.Commons,
+  Quick.Console,
+  Quick.Threads,
+  Quick.Chrono,
+  Quick.Format,
+  Quick.MemoryCache;
+
+type
+  TMyObject = class
+  private
+    fTestStr : string;
+    fTestInt : Integer;
+  public
+    property TestStr : string read fTestStr write fTestStr;
+    property TestInt : Integer read fTestInt write fTestInt;
+  end;
+
+var
+  cache : IMemoryCache;
+  valuestr : string;
+  valueobj : TMyObject;
+  valueobj2 : TMyObject;
+  backgroundtasks : TBackgroundTasks;
+  i : Integer;
+  n : Integer;
+  chrono : TChronometer;
+  dummystr : string;
+  arr : TArray<string>;
+  arrobj : TArray<TMyObject>;
+
+begin
+
+  ReportMemoryLeaksOnShutdown := True;
+
+  backgroundtasks := TBackgroundTasks.Create(20,100);
+
+  cache := TMemoryCache.Create(10);
+  //cache := TMemoryCache.Create(10,nil,TCacheCompressorLZO.Create);
+  cache.Compression := True;
+  cache.OnEndPurgerJob := procedure(aRemovedEntries : Integer)
+                          begin
+                            cout(Format('Purger job finished (Removed: %s /CachedObjects: %s / CacheSize: %s)',[NumberToStr(aRemovedEntries),NumberToStr(cache.CachedObjects),FormatBytes(cache.CacheSize)]),ccMagenta);
+                          end;
+
+  cache.OnPurgeJobError := procedure(const aErrorMsg : string)
+                           begin
+                             coutFmt('Error flushing cache expireds (%s)',[aErrorMsg],etError);
+                           end;
+  //set string to cache
+  cache.SetValue('one','one string');
+
+  //set string to cache with expiration to 10 seconds
+  cache.SetValue('other','another string',10);
+
+  //set array of string
+  cache.SetValue('myarray',['one','two','three','four']);
+
+  //set object to cache
+  valueobj := TMyObject.Create;
+  try
+    valueobj.TestStr := 'TestOk';
+    valueobj.TestInt := 7;
+    cache.SetValue('Obj1',valueobj);
+  finally
+    valueobj.Free;
+  end;
+
+  //set array of myobject
+  valueobj := TMyObject.Create;
+  try
+    valueobj.TestStr := 'TestOk One';
+    valueobj.TestInt := 7;
+    arrobj := arrobj + [valueobj];
+    cache.SetValue('arrayobj',TArray<TObject>(arrobj));
+  finally
+    valueobj.Free;
+  end;
+  arrobj := nil;
+
+  //get string from cache
+  //cache.TryGetValue<string>('one',valuestr);
+  valuestr := cache.GetValue('one');
+  coutFmt('Got Id(one) from cache: %s',[valuestr],etSuccess);
+
+  //get other string from cache
+  //cache.TryGetValue<string>('other',valueint);
+  cache.TryGetValue('other',valuestr);
+  coutFmt('Got Id(other) from cache: %s',[valuestr],etSuccess);
+
+  //get object from cache
+  valueobj2 := TMyObject.Create;
+  try
+    cache.TryGetValue('Obj1',valueobj2);
+    coutFmt('Got Id(Obj1) from cache: (TestStr = %s / TestIn = %d)',[valueobj2.TestStr,valueobj2.TestInt],etSuccess);
+  finally
+    valueobj2.Free;
+  end;
+
+  //get array of string from cache
+  cache.TryGetValue('myarray',arr);
+  coutFmt('array of string[0] = %s',[arr[0]],etSuccess);
+
+  //get array of myobject from cache
+  cache.TryGetValue('arrayobj',TArray<TObject>(arrobj));
+  coutFmt('array of MyObject[0].TestStr = %s',[arrobj[0].TestStr],etSuccess);
+
+  chrono := TChronometer.Create(False);
+  //concurrent read/writes
+  dummystr := '';
+
+  cout('Preparing data..',ccWhite);
+
+  dummystr := RandomString(1024);
+  n := 0;
+  for i := 1 to 100000 do
+  begin
+    Inc(n);
+    if n < 9 then
+    begin
+      backgroundtasks.AddTask(procedure(task : ITask)
+                           var a : string;
+                          begin
+                            if not cache.TryGetValue('1',a) then
+                            begin
+                              coutFmt('Value %d not in cache or expired',[1],etWarning);
+                              cache.SetValue('1',a,1000);
+                            end;
+                            //coutFmt('Get Id(1) from cache = %s',[a],etSuccess);
+                          end
+                  ).Run;
+    end
+    else
+    begin
+      n := 0;
+      backgroundtasks.AddTask(procedure(task : ITask)
+                           var a : string;
+                          begin
+                            a := Random(1000000).ToString;
+                            cache.SetValue(a,dummystr + a,Random(5000));
+                            //coutFmt('Set Id(1) to cache = %s',[a],etSuccess);
+                          end
+                  ).Run;
+    end;
+  end;
+  backgroundtasks.AddTask(procedure(task : ITask)
+                           var a : string;
+                          begin
+                            chrono.Stop;
+                            coutFmt('Performance: %s Combined cache IO Read/Writes in %s',[NumberToStr(i),chrono.ElapsedTime],etWarning);
+                            coutFmt('Cached Objects: %s / Cache Size: %s',[NumberToStr(cache.CachedObjects),FormatBytes(cache.CacheSize)],etInfo);
+                            //cache.Flush;
+                          end
+                  ).Run;
+  cout('Stress caching test launched',ccWhite);
+  backgroundtasks.Start;
+  chrono.Start;
+
+  cout('Wait to see how cache is expiring every 10 seconds or press <ENTER> to Exit',ccYellow);
+  ConsoleWaitForEnterKey;
+  coutFmt('Cached Objects: %s / Cache Size: %s',[NumberToStr(cache.CachedObjects),FormatBytes(cache.CacheSize)],etInfo);
+  //cache.Free;
+  chrono.Free;
+  backgroundtasks.Free;
+end.

+ 916 - 0
samples/delphi/QuickMemoryCache/MemoryCacheVariant/MemCacheVariantTest.dproj

@@ -0,0 +1,916 @@
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+    <PropertyGroup>
+        <ProjectGuid>{764CAF4F-133A-42F7-AE8D-93D32C5D60D9}</ProjectGuid>
+        <ProjectVersion>18.7</ProjectVersion>
+        <FrameworkType>None</FrameworkType>
+        <MainSource>MemCacheVariantTest.dpr</MainSource>
+        <Base>True</Base>
+        <Config Condition="'$(Config)'==''">Debug</Config>
+        <Platform Condition="'$(Platform)'==''">Win64</Platform>
+        <TargetedPlatforms>7</TargetedPlatforms>
+        <AppType>Console</AppType>
+    </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)'=='iOSDevice32' and '$(Base)'=='true') or '$(Base_iOSDevice32)'!=''">
+        <Base_iOSDevice32>true</Base_iOSDevice32>
+        <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)'=='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>
+        <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>MemCacheVariantTest</SanitizedProjectName>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Android)'!=''">
+        <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>
+        <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>
+        <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_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>
+    <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>
+    </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>
+        <VerInfo_Keys>CFBundleName=$(MSBuildProjectName);CFBundleDisplayName=$(MSBuildProjectName);CFBundleIdentifier=$(MSBuildProjectName);CFBundleVersion=1.0.0;CFBundleShortVersionString=1.0.0;CFBundlePackageType=APPL;CFBundleSignature=????;CFBundleAllowMixedLocalizations=YES;CFBundleExecutable=$(MSBuildProjectName);NSHighResolutionCapable=true;LSApplicationCategoryType=public.app-category.utilities;NSLocationUsageDescription=The reason for accessing the location information of the user;NSContactsUsageDescription=The reason for accessing the contacts</VerInfo_Keys>
+        <BT_BuildType>Debug</BT_BuildType>
+    </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>
+        <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;DataSnapServerMidas;DBXDb2Driver;DBXInterBaseDriver;vclactnband;vclFireDAC;emsclientfiredac;DataSnapFireDAC;tethering;FireDACADSDriver;DBXMSSQLDriver;DatasnapConnectorsFreePascal;FireDACMSSQLDriver;vcltouch;vcldb;bindcompfmx;DBXOracleDriver;inetdb;FmxTeeUI;emsedge;FireDACIBDriver;fmx;fmxdae;RadiantShapesFmx;vclib;FlatButtonSet;FireDACDBXDriver;dbexpress;IndyCore;vclx;dsnap;DataSnapCommon;emsclient;FireDACCommon;RESTBackendComponents;DataSnapConnectors;VCLRESTComponents;soapserver;vclie;bindengine;DBXMySQLDriver;FireDACOracleDriver;CloudService;FireDACMySQLDriver;DBXFirebirdDriver;FireDACCommonODBC;FireDACCommonDriver;DataSnapClient;inet;bindcompdbx;IndyIPCommon;vcl;IndyIPServer;DBXSybaseASEDriver;PngComponents;IndySystem;FireDACDb2Driver;dsnapcon;tmsxlsdXE12;FireDACMSAccDriver;fmxFireDAC;FireDACInfxDriver;vclimg;TeeDB;FireDAC;emshosting;FireDACSqliteDriver;FireDACPgDriver;ibmonitor;FireDACASADriver;tmsdXE12;FireDACTDataDriver;DBXOdbcDriver;FMXTee;soaprtl;DbxCommonDriver;ibxpress;Tee;DataSnapServer;xmlrtl;soapmidas;DataSnapNativeClient;fmxobj;vclwinx;ibxbindings;rtl;emsserverresource;DbxClientDriver;FireDACDSDriver;DBXSybaseASADriver;GR32_R;CustomIPTransport;vcldsnap;tmsexdXE12;bindcomp;appanalytics;DBXInformixDriver;IndyIPClient;bindcompvcl;TeeUI;dbxcds;VclSmp;adortl;FireDACODBCDriver;DataSnapIndy10ServerTransport;RadiantShapesFmx_Design;dsnapxml;DataSnapProviderClient;dbrtl;inetdbxpress;FireDACMongoDBDriver;IndyProtocols;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">MemCacheVariantTest.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\MemCacheVariantTest.exe" Configuration="Debug" Class="ProjectOutput">
+                    <Platform Name="Win32">
+                        <RemoteName>MemCacheVariantTest.exe</RemoteName>
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile LocalName="Win64\Debug\MemCacheVariantTest.exe" Configuration="Debug" Class="ProjectOutput">
+                    <Platform Name="Win64">
+                        <RemoteName>MemCacheVariantTest.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>
+                </DeployClass>
+                <DeployClass Name="AndroidFileProvider">
+                    <Platform Name="Android">
+                        <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>
+                </DeployClass>
+                <DeployClass Name="AndroidLibnativeMipsFile">
+                    <Platform Name="Android">
+                        <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>
+                </DeployClass>
+                <DeployClass Name="AndroidSplashImageDef">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidSplashStyles">
+                    <Platform Name="Android">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidSplashStylesV21">
+                    <Platform Name="Android">
+                        <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>
+                </DeployClass>
+                <DeployClass Name="Android_DefaultAppIcon">
+                    <Platform Name="Android">
+                        <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>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon36">
+                    <Platform Name="Android">
+                        <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>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon72">
+                    <Platform Name="Android">
+                        <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>
+                </DeployClass>
+                <DeployClass Name="Android_NotificationIcon24">
+                    <Platform Name="Android">
+                        <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>
+                </DeployClass>
+                <DeployClass Name="Android_NotificationIcon48">
+                    <Platform Name="Android">
+                        <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>
+                </DeployClass>
+                <DeployClass Name="Android_NotificationIcon96">
+                    <Platform Name="Android">
+                        <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>
+                </DeployClass>
+                <DeployClass Name="Android_SplashImage470">
+                    <Platform Name="Android">
+                        <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>
+                </DeployClass>
+                <DeployClass Name="Android_SplashImage960">
+                    <Platform Name="Android">
+                        <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>
+                </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="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="iPad_Launch1024x768">
+                    <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_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">
+                    <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_Launch1668x2388">
+                    <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_Launch2048x1536">
+                    <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_Launch2048x2732">
+                    <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_Launch2224">
+                    <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_Launch2388x1668">
+                    <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_Launch2732x2048">
+                    <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_Launch768x1024">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch1125">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch1136x640">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch1242">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch1242x2688">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch1334">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch1792">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch2208">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch2436">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch2688x1242">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch320">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch640">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch640x1136">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch750">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch828">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectAndroidManifest">
+                    <Platform Name="Android">
+                        <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="ProjectiOSDeviceResourceRules">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <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="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="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="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"/>
+            </Deployment>
+            <Platforms>
+                <Platform value="Android">False</Platform>
+                <Platform value="iOSDevice32">False</Platform>
+                <Platform value="iOSDevice64">False</Platform>
+                <Platform value="iOSSimulator">False</Platform>
+                <Platform value="OSX32">True</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>

BIN
samples/delphi/QuickMemoryCache/MemoryCacheVariant/MemCacheVariantTest.res


+ 109 - 0
samples/delphi/QuickOptions/Optionsdemo.dpr

@@ -0,0 +1,109 @@
+program Optionsdemo;
+
+{$APPTYPE CONSOLE}
+
+{$R *.res}
+
+uses
+  System.SysUtils,
+  Quick.Commons,
+  Quick.Console,
+  Quick.Options,
+  Quick.Options.Serializer.Json,
+  Quick.Options.Serializer.Yaml;
+
+type
+  TLoggingOptions = class(TOptions)
+  private
+    fPath : string;
+  published
+    [Required, StringLength(255,'Path too long')]
+    property Path : string read fPath write fPath;
+  end;
+
+  TGlobalOptions = class(TOptions)
+  private
+    fStartMinimized : Boolean;
+    fServers : TArray<string>;
+    fLevel : Double;
+  published
+    property StartMinimized : Boolean read fStartMinimized write fStartMinimized;
+    property Servers : TArray<string> read fServers write fServers;
+    [Range(0.0,5.2)]
+    property Level : Double read fLevel write fLevel;
+  end;
+
+  TUIOptions = class(TOptions)
+  private
+    fForeColor : Integer;
+    fBackColor : Integer;
+  published
+    [Range(0, 255)]
+    property ForeColor : Integer read fForeColor write fForeColor;
+    [Range(0, 255,'Out of range')]
+    property BackgroundColor : Integer read fBackColor write fBackColor;
+  end;
+
+var
+  Options : TOptionsContainer;
+  LoggingOptions : TLoggingOptions;
+  GlobalOptions : TGlobalOptions;
+  UIOptions : TUIOptions;
+
+begin
+  try
+    Options := TOptionsContainer.Create('.\options.conf',TJsonOptionsSerializer.Create,True);
+    Options.OnFileModified := procedure
+                              begin
+                                cout('Detected config file modification!',etWarning);
+                              end;
+
+    Options.AddSection<TLoggingOptions>('Logging').ConfigureOptions(procedure(aOptions : TLoggingOptions)
+                                                            begin
+                                                              aOptions.Path := 'C:\';
+                                                            end
+                                                            ).ValidateOptions;
+    Options.AddSection<TGlobalOptions>('GlobalOptions').ConfigureOptions(procedure(aOptions : TGlobalOptions)
+                                                begin
+                                                  aOptions.StartMinimized := True;
+                                                  aOptions.Servers := ['ServerOne','ServerTwo','ServerThree','ServerFour'];
+                                                end
+                                                ).ValidateOptions;
+
+    Options.AddSection(TUIOptions).ConfigureOptions<TUIOptions>(procedure(aOptions : TUIOptions)
+                                                begin
+                                                  aOptions.ForeColor := 77;
+                                                  aOptions.BackgroundColor := 100;
+                                                end
+                                                ).ValidateOptions;
+
+    Options.Load;
+    LoggingOptions := Options.GetSection<TLoggingOptions>;
+    UIOptions := Options.GetSectionInterface<TUIOptions>.Value;
+    GlobalOptions := Options.GetSectionInterface<TGlobalOptions>.Value;
+
+    coutFmt('Logging.Path = %s',[LoggingOptions.Path],etInfo);
+    coutFmt('UIOptions.BackgroundColor = %d',[UIOptions.BackgroundColor],etInfo);
+    coutFmt('GlobalOptions.StarMinimized = %s',[BoolToStr(GlobalOptions.StartMinimized,True)],etInfo);
+
+    LoggingOptions.Path := 'D:\OtherTest';
+    UIOptions.BackgroundColor := 120;
+
+    Options.Save;
+
+    //get instance of options section
+    LoggingOptions := Options.GetSection<TLoggingOptions>;
+    //LoggingOptions := Options.GetSection<TLoggingOptions>.Value;
+
+    //gets value from IOptions<TUIOptions> interface (depency injection)
+    UIOptions := Options.GetSectionInterface<TUIOptions>.Value;
+
+    coutFmt('Logging.Path = %s',[LoggingOptions.Path],etInfo);
+    coutFmt('UIOptions.BackgroundColor = %d',[UIOptions.BackgroundColor],etInfo);
+
+    Readln;
+  except
+    on E: Exception do
+      coutFmt('%s:%s',[E.ClassName,E.Message],etError);
+  end;
+end.

File diff suppressed because it is too large
+ 109 - 0
samples/delphi/QuickOptions/Optionsdemo.dproj


BIN
samples/delphi/QuickOptions/Optionsdemo.res


+ 105 - 0
samples/delphi/QuickValue/QuickValue.dpr

@@ -0,0 +1,105 @@
+program QuickValue;
+
+{$APPTYPE CONSOLE}
+
+{$R *.res}
+
+uses
+  System.SysUtils,
+  RTTI,
+  Variants,
+  System.TypInfo,
+  Quick.Json.Serializer,
+  Quick.Commons,
+  Quick.Console,
+  Quick.Value,
+  Quick.Value.RTTI;
+
+type
+  TDynArrayOfVariant = array of TVarRecord;
+
+  TMyArray = TArray<TObject>;
+
+  PMyArray = ^TMyArray;
+
+  TMyObject = class
+  private
+    fName : string;
+    fAge : Integer;
+  public
+    property Name : string read fName write fName;
+    property Age : Integer read fAge write fAge;
+  end;
+
+var
+  flexvalue : TFlexValue;
+  arr : TArray<string>;
+  value : TValue;
+
+function Test(aValue : variant) : string;
+var
+  i : Integer;
+  serializer : TJsonSerializer;
+  arr : array of variant;
+  parr : Pointer;
+begin
+
+  serializer := TJsonSerializer.Create(TSerializeLevel.slPublicProperty);
+  if VarIsArray(aValue) then
+  begin
+    parr := VarArrayLock(aValue);
+    var a := VarArrayGet(aValue,[1]);
+    var b := VarTypeAsText(VarType(a) and VarTypeMask);
+    SetLength(arr,VarArrayHighBound(aValue,1) + 1);
+    arr := [aValue];
+    Result := serializer.ArrayToJson(TValue.FromVariant(aValue));
+  end;
+end;
+
+function Test2(aValue : Pointer) : string;
+var
+  arr : TMyArray;
+  parr : Pointer;
+begin
+  //if VarIsArray(aValue) then
+  begin
+    //parr := VarArrayLock(aValue);
+    //SetLength(arr,VarArrayHighBound(aValue,1) + 1);
+    parr := aValue;
+    SetLength(arr,2);
+    arr := PMyArray(@parr)^;
+    var a := arr[0];
+    var b := TMyObject(a).Name;
+  end;
+end;
+
+var
+  obj : TMyObject;
+  arr2 : TArray<TMyObject>;
+  vari : Variant;
+
+begin
+  try
+
+
+    obj := TMyObject.Create;
+    obj.Name := 'Joe';
+    obj.Age := 30;
+
+    arr2 := [obj];
+    //vari := arr2;
+
+    test2(arr2);
+
+    arr := ['item1','item2','item3','item4'];
+    flexvalue := arr;
+    var a := Test(arr);
+    SetLength(arr,0);
+    arr := TArray<string>(flexvalue.AsPointer);
+    coutFmt('arr[1]=%s',[arr[1]],etInfo);
+    ConsoleWaitForEnterKey;
+  except
+    on E: Exception do
+      Writeln(E.ClassName, ': ', E.Message);
+  end;
+end.

File diff suppressed because it is too large
+ 109 - 0
samples/delphi/QuickValue/QuickValue.dproj


BIN
samples/delphi/QuickValue/QuickValue.res


+ 43 - 0
samples/firemonkey/QuickIOC/IOCDemo/AndroidManifest.template.xml

@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- BEGIN_INCLUDE(manifest) -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="%package%"
+        android:versionCode="%versionCode%"
+        android:versionName="%versionName%"
+        android:installLocation="%installLocation%">
+
+    <uses-sdk android:minSdkVersion="%minSdkVersion%" android:targetSdkVersion="%targetSdkVersion%" />
+    <%uses-permission%>
+    <uses-feature android:glEsVersion="0x00020000" android:required="True"/>
+    <application android:persistent="%persistent%" 
+        android:restoreAnyVersion="%restoreAnyVersion%" 
+        android:label="%label%" 
+        android:debuggable="%debuggable%" 
+        android:largeHeap="%largeHeap%"
+        android:icon="%icon%"
+        android:theme="%theme%"
+        android:hardwareAccelerated="%hardwareAccelerated%"
+        android:resizeableActivity="false">
+
+        <%provider%>
+        <%application-meta-data%>
+        <%services%>
+        <!-- Our activity is a subclass of the built-in NativeActivity framework class.
+             This will take care of integrating with our NDK code. -->
+        <activity android:name="com.embarcadero.firemonkey.FMXNativeActivity"
+                android:label="%activityLabel%"
+                android:configChanges="orientation|keyboard|keyboardHidden|screenSize"
+                android:launchMode="singleTask">
+            <!-- Tell NativeActivity the name of our .so -->
+            <meta-data android:name="android.app.lib_name"
+                android:value="%libNameValue%" />
+            <intent-filter>  
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter> 
+        </activity>
+        <%activity%>
+        <%receivers%>
+    </application>
+</manifest>
+<!-- END_INCLUDE(manifest) -->

+ 171 - 0
samples/firemonkey/QuickIOC/IOCDemo/Dependencies.pas

@@ -0,0 +1,171 @@
+unit Dependencies;
+
+interface
+
+uses
+  System.SysUtils,
+  Quick.Commons,
+  Quick.IOC;
+
+type
+  IMathService = interface
+  ['{E8BEE282-3828-4F27-869D-C808296F8CA2}']
+    procedure IncNumsOperations;
+    function NumOperations : Integer;
+  end;
+
+  ISumService = interface(IMathService)
+  ['{7580F5F6-0132-49F3-A22A-A2E93E53E8A7}']
+    function Sum(a, b : Integer) : Integer;
+  end;
+
+  IMultService = interface(IMathService)
+  ['{56772C4B-70AF-4BB7-9DFE-E2D67912DDC1}']
+    function Mult(a, b : Integer) : Integer;
+  end;
+
+  TMathService = class(TInterfacedObject,IMathService)
+  private
+    fNumOperations : Integer;
+  public
+    constructor Create;
+    procedure IncNumsOperations;
+    function NumOperations : Integer;
+  end;
+
+  TSumService = class(TMathService,ISumService)
+  public
+    function Sum(a, b : Integer) : Integer;
+  end;
+
+  TMultService = class(TMathService,IMultService)
+  public
+    function Mult(a, b : Integer) : Integer;
+  end;
+
+  IBigService = interface
+  ['{AE7E7617-02BD-48C9-A370-49566A563C38}']
+    function GetNumOperations : Integer;
+    function Sum(a, b : Integer) : Integer;
+    function Mult(a, b : Integer) : Integer;
+    function SumService : ISumService;
+    function MultService : IMultService;
+    property NumOperations : Integer read GetNumOperations;
+  end;
+  TBigService = class(TInterfacedObject,IBigService)
+  private
+    fSumService : ISumService;
+    fMultService : IMultService;
+    fNumOperations : Integer;
+    function GetNumOperations : Integer;
+    procedure IncNumOperations;
+  public
+    constructor Create(aSumService : ISumService; aMultService : IMultService);
+    function Sum(a, b : Integer) : Integer;
+    function Mult(a, b : Integer) : Integer;
+    function SumService : ISumService;
+    function MultService : IMultService;
+    property NumOperations : Integer read GetNumOperations;
+  end;
+
+  TDivideService = class
+  private
+    fNumOperations : Integer;
+    fRound : Boolean;
+  public
+    constructor Create(aRound : Boolean);
+    property NumOperations : Integer read fNumOperations;
+    function Divide(a,b : Integer) : Integer;
+  end;
+
+implementation
+
+{ TSumService }
+
+function TSumService.Sum(a, b: Integer): Integer;
+begin
+  Result := a + b;
+  IncNumsOperations;
+end;
+
+{ TMultService }
+
+function TMultService.Mult(a, b: Integer): Integer;
+begin
+  Result := a * b;
+  IncNumsOperations;
+end;
+
+{ TBigService }
+
+constructor TBigService.Create(aSumService: ISumService; aMultService: IMultService);
+begin
+  fSumService := aSumService;
+  fMultService := aMultService;
+end;
+
+function TBigService.Sum(a, b: Integer): Integer;
+begin
+  Result := fSumService.Sum(a,b);
+  IncNumOperations;
+end;
+
+function TBigService.SumService: ISumService;
+begin
+  Result := fSumService;
+end;
+
+function TBigService.GetNumOperations: Integer;
+begin
+  Result := fNumOperations;
+end;
+
+procedure TBigService.IncNumOperations;
+begin
+  Inc(fNumOperations);
+end;
+
+function TBigService.Mult(a, b: Integer): Integer;
+begin
+  Result := fMultService.Mult(a,b);
+  IncNumOperations;
+end;
+
+function TBigService.MultService: IMultService;
+begin
+  Result := fMultService;
+end;
+
+{ TMathService }
+
+constructor TMathService.Create;
+begin
+  fNumOperations := 0;
+end;
+
+procedure TMathService.IncNumsOperations;
+begin
+  Inc(fNumOperations);
+end;
+
+function TMathService.NumOperations: Integer;
+begin
+  Result := fNumOperations;
+end;
+
+{ TDivideService }
+
+constructor TDivideService.Create(aRound : Boolean);
+begin
+  fNumOperations := 0;
+  fRound := aRound;
+end;
+
+function TDivideService.Divide(a, b: Integer): Integer;
+begin
+  if fRound then Result := Round(a / b)
+    else Result := Trunc(a / b);
+  Inc(fNumOperations);
+end;
+
+end.

+ 286 - 0
samples/firemonkey/QuickIOC/IOCDemo/IOCDemo.deployproj

@@ -0,0 +1,286 @@
+<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'">emulator-5554</DeviceId>
+        <DeviceId Condition="'$(Platform)'=='iOSDevice32'"/>
+        <DeviceId Condition="'$(Platform)'=='iOSDevice64'"/>
+        <DeviceId Condition="'$(Platform)'=='iOSSimulator'">iPhone5</DeviceId>
+    </PropertyGroup>
+    <ItemGroup Condition="'$(Platform)'=='iOSDevice64'"/>
+    <ItemGroup Condition="'$(Platform)'=='Win64'"/>
+    <ItemGroup Condition="'$(Platform)'=='iOSDevice32'"/>
+    <ItemGroup Condition="'$(Platform)'=='Win32'">
+        <DeployFile Include="Win32\Debug\IOCDemo.exe" Condition="'$(Config)'=='Debug'">
+            <RemoteDir>IOCDemo\</RemoteDir>
+            <RemoteName>IOCDemo.exe</RemoteName>
+            <DeployClass>ProjectOutput</DeployClass>
+            <Operation>0</Operation>
+            <LocalCommand/>
+            <RemoteCommand/>
+            <Overwrite>True</Overwrite>
+            <Required>True</Required>
+        </DeployFile>
+    </ItemGroup>
+    <ItemGroup Condition="'$(Platform)'=='OSX32'">
+        <DeployFile Include="$(BDS)\Redist\osx32\libcgunwind.1.0.dylib">
+            <RemoteDir>IOCDemo.app\Contents\MacOS\</RemoteDir>
+            <RemoteName>libcgunwind.1.0.dylib</RemoteName>
+            <DeployClass>DependencyModule</DeployClass>
+            <Operation>1</Operation>
+            <LocalCommand/>
+            <RemoteCommand/>
+            <Overwrite>True</Overwrite>
+        </DeployFile>
+    </ItemGroup>
+    <ItemGroup Condition="'$(Platform)'=='Android'">
+        <DeployFile Include="$(BDS)\bin\Artwork\Android\FM_NotificationIcon_72x72.png" Condition="'$(Config)'=='Debug'">
+            <RemoteDir>IOCDemo\res\drawable-xxhdpi\</RemoteDir>
+            <RemoteName>ic_notification.png</RemoteName>
+            <DeployClass>Android_NotificationIcon72</DeployClass>
+            <Operation>1</Operation>
+            <LocalCommand/>
+            <RemoteCommand/>
+            <Overwrite>True</Overwrite>
+        </DeployFile>
+        <DeployFile Include="$(BDS)\bin\Artwork\Android\FM_LauncherIcon_36x36.png" Condition="'$(Config)'=='Debug'">
+            <RemoteDir>IOCDemo\res\drawable-ldpi\</RemoteDir>
+            <RemoteName>ic_launcher.png</RemoteName>
+            <DeployClass>Android_LauncherIcon36</DeployClass>
+            <Operation>1</Operation>
+            <LocalCommand/>
+            <RemoteCommand/>
+            <Overwrite>True</Overwrite>
+        </DeployFile>
+        <DeployFile Include="$(BDS)\bin\Artwork\Android\FM_LauncherIcon_72x72.png" Condition="'$(Config)'=='Debug'">
+            <RemoteDir>IOCDemo\res\drawable-hdpi\</RemoteDir>
+            <RemoteName>ic_launcher.png</RemoteName>
+            <DeployClass>Android_LauncherIcon72</DeployClass>
+            <Operation>1</Operation>
+            <LocalCommand/>
+            <RemoteCommand/>
+            <Overwrite>True</Overwrite>
+        </DeployFile>
+        <DeployFile Include="$(BDS)\bin\Artwork\Android\FM_SplashImage_640x480.png" Condition="'$(Config)'=='Debug'">
+            <RemoteDir>IOCDemo\res\drawable-large\</RemoteDir>
+            <RemoteName>splash_image.png</RemoteName>
+            <DeployClass>Android_SplashImage640</DeployClass>
+            <Operation>1</Operation>
+            <LocalCommand/>
+            <RemoteCommand/>
+            <Overwrite>True</Overwrite>
+        </DeployFile>
+        <DeployFile Include="$(BDS)\bin\Artwork\Android\FM_SplashImage_960x720.png" Condition="'$(Config)'=='Debug'">
+            <RemoteDir>IOCDemo\res\drawable-xlarge\</RemoteDir>
+            <RemoteName>splash_image.png</RemoteName>
+            <DeployClass>Android_SplashImage960</DeployClass>
+            <Operation>1</Operation>
+            <LocalCommand/>
+            <RemoteCommand/>
+            <Overwrite>True</Overwrite>
+        </DeployFile>
+        <DeployFile Include="$(BDS)\bin\Artwork\Android\FM_SplashImage_426x320.png" Condition="'$(Config)'=='Debug'">
+            <RemoteDir>IOCDemo\res\drawable-small\</RemoteDir>
+            <RemoteName>splash_image.png</RemoteName>
+            <DeployClass>Android_SplashImage426</DeployClass>
+            <Operation>1</Operation>
+            <LocalCommand/>
+            <RemoteCommand/>
+            <Overwrite>True</Overwrite>
+        </DeployFile>
+        <DeployFile Include="$(BDS)\bin\Artwork\Android\FM_NotificationIcon_36x36.png" Condition="'$(Config)'=='Debug'">
+            <RemoteDir>IOCDemo\res\drawable-hdpi\</RemoteDir>
+            <RemoteName>ic_notification.png</RemoteName>
+            <DeployClass>Android_NotificationIcon36</DeployClass>
+            <Operation>1</Operation>
+            <LocalCommand/>
+            <RemoteCommand/>
+            <Overwrite>True</Overwrite>
+        </DeployFile>
+        <DeployFile Include="$(BDS)\bin\Artwork\Android\FM_LauncherIcon_48x48.png" Condition="'$(Config)'=='Debug'">
+            <RemoteDir>IOCDemo\res\drawable-mdpi\</RemoteDir>
+            <RemoteName>ic_launcher.png</RemoteName>
+            <DeployClass>Android_LauncherIcon48</DeployClass>
+            <Operation>1</Operation>
+            <LocalCommand/>
+            <RemoteCommand/>
+            <Overwrite>True</Overwrite>
+        </DeployFile>
+        <DeployFile Include="$(BDS)\lib\android\debug\mips\libnative-activity.so" Condition="'$(Config)'=='Debug'">
+            <RemoteDir>IOCDemo\library\lib\mips\</RemoteDir>
+            <RemoteName>libIOCDemo.so</RemoteName>
+            <DeployClass>AndroidLibnativeMipsFile</DeployClass>
+            <Operation>1</Operation>
+            <LocalCommand/>
+            <RemoteCommand/>
+            <Overwrite>True</Overwrite>
+        </DeployFile>
+        <DeployFile Include="Android\Debug\classes.dex" Condition="'$(Config)'=='Debug'">
+            <RemoteDir>IOCDemo\classes\</RemoteDir>
+            <RemoteName>classes.dex</RemoteName>
+            <DeployClass>AndroidClassesDexFile</DeployClass>
+            <Operation>1</Operation>
+            <LocalCommand/>
+            <RemoteCommand/>
+            <Overwrite>True</Overwrite>
+        </DeployFile>
+        <DeployFile Include="$(NDKBasePath)\prebuilt\android-arm\gdbserver\gdbserver" Condition="'$(Config)'=='Debug'">
+            <RemoteDir>IOCDemo\library\lib\armeabi-v7a\</RemoteDir>
+            <RemoteName>gdbserver</RemoteName>
+            <DeployClass>AndroidGDBServer</DeployClass>
+            <Operation>1</Operation>
+            <LocalCommand/>
+            <RemoteCommand/>
+            <Overwrite>True</Overwrite>
+        </DeployFile>
+        <DeployFile Include="Android\Debug\splash_image_def.xml" Condition="'$(Config)'=='Debug'">
+            <RemoteDir>IOCDemo\res\drawable\</RemoteDir>
+            <RemoteName>splash_image_def.xml</RemoteName>
+            <DeployClass>AndroidSplashImageDef</DeployClass>
+            <Operation>1</Operation>
+            <LocalCommand/>
+            <RemoteCommand/>
+            <Overwrite>True</Overwrite>
+        </DeployFile>
+        <DeployFile Include="Android\Debug\styles.xml" Condition="'$(Config)'=='Debug'">
+            <RemoteDir>IOCDemo\res\values\</RemoteDir>
+            <RemoteName>styles.xml</RemoteName>
+            <DeployClass>AndroidSplashStyles</DeployClass>
+            <Operation>1</Operation>
+            <LocalCommand/>
+            <RemoteCommand/>
+            <Overwrite>True</Overwrite>
+        </DeployFile>
+        <DeployFile Include="$(BDS)\bin\Artwork\Android\FM_NotificationIcon_96x96.png" Condition="'$(Config)'=='Debug'">
+            <RemoteDir>IOCDemo\res\drawable-xxxhdpi\</RemoteDir>
+            <RemoteName>ic_notification.png</RemoteName>
+            <DeployClass>Android_NotificationIcon96</DeployClass>
+            <Operation>1</Operation>
+            <LocalCommand/>
+            <RemoteCommand/>
+            <Overwrite>True</Overwrite>
+        </DeployFile>
+        <DeployFile Include="Android\Debug\AndroidManifest.xml" Condition="'$(Config)'=='Debug'">
+            <RemoteDir>IOCDemo\</RemoteDir>
+            <RemoteName>AndroidManifest.xml</RemoteName>
+            <DeployClass>ProjectAndroidManifest</DeployClass>
+            <Operation>1</Operation>
+            <LocalCommand/>
+            <RemoteCommand/>
+            <Overwrite>True</Overwrite>
+        </DeployFile>
+        <DeployFile Include="$(BDS)\lib\android\debug\armeabi\libnative-activity.so" Condition="'$(Config)'=='Debug'">
+            <RemoteDir>IOCDemo\library\lib\armeabi\</RemoteDir>
+            <RemoteName>libIOCDemo.so</RemoteName>
+            <DeployClass>AndroidLibnativeArmeabiFile</DeployClass>
+            <Operation>1</Operation>
+            <LocalCommand/>
+            <RemoteCommand/>
+            <Overwrite>True</Overwrite>
+        </DeployFile>
+        <DeployFile Include="$(BDS)\bin\Artwork\Android\FM_LauncherIcon_144x144.png" Condition="'$(Config)'=='Debug'">
+            <RemoteDir>IOCDemo\res\drawable-xxhdpi\</RemoteDir>
+            <RemoteName>ic_launcher.png</RemoteName>
+            <DeployClass>Android_LauncherIcon144</DeployClass>
+            <Operation>1</Operation>
+            <LocalCommand/>
+            <RemoteCommand/>
+            <Overwrite>True</Overwrite>
+        </DeployFile>
+        <DeployFile Include="$(BDS)\bin\Artwork\Android\FM_SplashImage_470x320.png" Condition="'$(Config)'=='Debug'">
+            <RemoteDir>IOCDemo\res\drawable-normal\</RemoteDir>
+            <RemoteName>splash_image.png</RemoteName>
+            <DeployClass>Android_SplashImage470</DeployClass>
+            <Operation>1</Operation>
+            <LocalCommand/>
+            <RemoteCommand/>
+            <Overwrite>True</Overwrite>
+        </DeployFile>
+        <DeployFile Include="$(BDS)\bin\Artwork\Android\FM_NotificationIcon_24x24.png" Condition="'$(Config)'=='Debug'">
+            <RemoteDir>IOCDemo\res\drawable-mdpi\</RemoteDir>
+            <RemoteName>ic_notification.png</RemoteName>
+            <DeployClass>Android_NotificationIcon24</DeployClass>
+            <Operation>1</Operation>
+            <LocalCommand/>
+            <RemoteCommand/>
+            <Overwrite>True</Overwrite>
+        </DeployFile>
+        <DeployFile Include="Android\Debug\libIOCDemo.so" Condition="'$(Config)'=='Debug'">
+            <RemoteDir>IOCDemo\library\lib\armeabi-v7a\</RemoteDir>
+            <RemoteName>libIOCDemo.so</RemoteName>
+            <DeployClass>ProjectOutput</DeployClass>
+            <Operation>1</Operation>
+            <LocalCommand/>
+            <RemoteCommand/>
+            <Overwrite>True</Overwrite>
+            <Required>True</Required>
+        </DeployFile>
+        <DeployFile Include="Android\Debug\colors.xml" Condition="'$(Config)'=='Debug'">
+            <RemoteDir>IOCDemo\res\values\</RemoteDir>
+            <RemoteName>colors.xml</RemoteName>
+            <DeployClass>Android_Colors</DeployClass>
+            <Operation>1</Operation>
+            <LocalCommand/>
+            <RemoteCommand/>
+            <Overwrite>True</Overwrite>
+        </DeployFile>
+        <DeployFile Include="$(BDS)\bin\Artwork\Android\FM_LauncherIcon_96x96.png" Condition="'$(Config)'=='Debug'">
+            <RemoteDir>IOCDemo\res\drawable-xhdpi\</RemoteDir>
+            <RemoteName>ic_launcher.png</RemoteName>
+            <DeployClass>Android_LauncherIcon96</DeployClass>
+            <Operation>1</Operation>
+            <LocalCommand/>
+            <RemoteCommand/>
+            <Overwrite>True</Overwrite>
+        </DeployFile>
+        <DeployFile Include="$(BDS)\bin\Artwork\Android\FM_NotificationIcon_48x48.png" Condition="'$(Config)'=='Debug'">
+            <RemoteDir>IOCDemo\res\drawable-xhdpi\</RemoteDir>
+            <RemoteName>ic_notification.png</RemoteName>
+            <DeployClass>Android_NotificationIcon48</DeployClass>
+            <Operation>1</Operation>
+            <LocalCommand/>
+            <RemoteCommand/>
+            <Overwrite>True</Overwrite>
+        </DeployFile>
+        <DeployFile Include="Android\Debug\styles-v21.xml" Condition="'$(Config)'=='Debug'">
+            <RemoteDir>IOCDemo\res\values-v21\</RemoteDir>
+            <RemoteName>styles.xml</RemoteName>
+            <DeployClass>AndroidSplashStylesV21</DeployClass>
+            <Operation>1</Operation>
+            <LocalCommand/>
+            <RemoteCommand/>
+            <Overwrite>True</Overwrite>
+        </DeployFile>
+        <DeployFile Include="Android\Debug\strings.xml" Condition="'$(Config)'=='Debug'">
+            <RemoteDir>IOCDemo\res\values\</RemoteDir>
+            <RemoteName>strings.xml</RemoteName>
+            <DeployClass>Android_Strings</DeployClass>
+            <Operation>1</Operation>
+            <LocalCommand/>
+            <RemoteCommand/>
+            <Overwrite>True</Overwrite>
+        </DeployFile>
+    </ItemGroup>
+    <ItemGroup Condition="'$(Platform)'=='iOSSimulator'">
+        <DeployFile Include="$(BDS)\Redist\iossimulator\libcgunwind.1.0.dylib">
+            <RemoteDir>IOCDemo.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>IOCDemo.app\</RemoteDir>
+            <RemoteName>libpcre.dylib</RemoteName>
+            <DeployClass>DependencyModule</DeployClass>
+            <Operation>1</Operation>
+            <LocalCommand/>
+            <RemoteCommand/>
+            <Overwrite>True</Overwrite>
+        </DeployFile>
+    </ItemGroup>
+</Project>

+ 14 - 0
samples/firemonkey/QuickIOC/IOCDemo/IOCDemo.dpr

@@ -0,0 +1,14 @@
+program IOCDemo;
+
+uses
+  System.StartUpCopy,
+  FMX.Forms,
+  Main in 'Main.pas' {Form1};
+
+{$R *.res}
+
+begin
+  Application.Initialize;
+  Application.CreateForm(TForm1, Form1);
+  Application.Run;
+end.

File diff suppressed because it is too large
+ 305 - 0
samples/firemonkey/QuickIOC/IOCDemo/IOCDemo.dproj


BIN
samples/firemonkey/QuickIOC/IOCDemo/IOCDemo.res


+ 42 - 0
samples/firemonkey/QuickIOC/IOCDemo/Main.fmx

@@ -0,0 +1,42 @@
+object Form1: TForm1
+  Left = 0
+  Top = 0
+  Caption = 'Form1'
+  ClientHeight = 480
+  ClientWidth = 640
+  FormFactor.Width = 320
+  FormFactor.Height = 480
+  FormFactor.Devices = [Desktop]
+  OnCreate = FormCreate
+  OnClose = FormClose
+  DesignerMasterStyle = 0
+  object meInfo: TMemo
+    Touch.InteractiveGestures = [Pan, LongTap, DoubleTap]
+    DataDetectorTypes = []
+    ReadOnly = True
+    Align = Client
+    Size.Width = 640.000000000000000000
+    Size.Height = 432.000000000000000000
+    Size.PlatformDefault = False
+    TabOrder = 1
+    Viewport.Width = 636.000000000000000000
+    Viewport.Height = 428.000000000000000000
+  end
+  object Panel1: TPanel
+    Align = MostBottom
+    Position.Y = 432.000000000000000000
+    Size.Width = 640.000000000000000000
+    Size.Height = 48.000000000000000000
+    Size.PlatformDefault = False
+    TabOrder = 2
+    object btnCheckIOC: TButton
+      Align = Center
+      Size.Width = 129.000000000000000000
+      Size.Height = 39.000000000000000000
+      Size.PlatformDefault = False
+      TabOrder = 1
+      Text = 'Check IOC'
+      OnClick = btnCheckIOCClick
+    end
+  end
+end

+ 142 - 0
samples/firemonkey/QuickIOC/IOCDemo/Main.pas

@@ -0,0 +1,142 @@
+unit Main;
+
+interface
+
+uses
+  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
+  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.StdCtrls, FMX.Controls.Presentation, FMX.ScrollBox,
+  FMX.Memo,
+  Quick.IOC,
+  Dependencies;
+
+type
+  TForm1 = class(TForm)
+    meInfo: TMemo;
+    Panel1: TPanel;
+    btnCheckIOC: TButton;
+    procedure FormCreate(Sender: TObject);
+    procedure FormClose(Sender: TObject; var Action: TCloseAction);
+    procedure btnCheckIOCClick(Sender: TObject);
+  private
+    { Private declarations }
+  public
+    { Public declarations }
+  end;
+
+var
+  Form1: TForm1;
+  iocContainer : TIocContainer;
+  sumservice : ISumService;
+  multservice : IMultService;
+  bigservice : IBigService;
+  divideservice : TDivideService;
+  executions : Integer = 0;
+
+implementation
+
+{$R *.fmx}
+
+procedure TForm1.btnCheckIOCClick(Sender: TObject);
+var
+  res : Integer;
+  i : Integer;
+  times : Integer;
+  numoperations : Integer;
+begin
+  times := 100;
+  res := 0;
+  Inc(executions);
+
+  //test1: class injection as singleton
+  for i := 1 to times do
+  begin
+    sumservice := iocContainer.Resolve<ISumService>;
+    res := sumservice.Sum(2,2);
+  end;
+  if sumservice.NumOperations = times * executions + (times * (executions - 1)) then meInfo.Lines.Add('Test1: Class injection as Singleton test ok')
+    else meInfo.Lines.Add('Test1: Class injection as Singleton test error');
+  meInfo.Lines.Add(Format('SumService.Sum = %d (calls: %d)',[res,sumservice.NumOperations]));
+
+  //test2: class injection as transient
+  for i := 1 to times do
+  begin
+    multservice := iocContainer.Resolve<IMultService>;
+    res := multservice.Mult(2,4);
+  end;
+  if multservice.NumOperations = 1 then meInfo.Lines.Add('Test2: Class injection as Transient test ok')
+    else meInfo.Lines.Add('Test2: Class injection as Transient test error');
+  meInfo.Lines.Add(Format('MultService.Mult = %d (calls: %d)',[res,multservice.NumOperations]));
+
+  //test3: constructor injection as singleton
+  for i := 1 to times do
+  begin
+    bigservice := iocContainer.Resolve<IBigService>('one');
+    res := bigservice.Sum(2,2);
+  end;
+  if bigservice.NumOperations = times * executions then meInfo.Lines.Add('Test3: Constructor injection as Singleton test ok')
+    else meInfo.Lines.Add('Test3: Constructor injection as Singleton test error');
+  meInfo.Lines.Add(Format('BigService.Sum = %d (calls: %d to BigService / calls: %d to SumService (as singleton))',[res,bigservice.NumOperations,bigservice.sumservice.NumOperations]));
+
+  //test4: constructor injection as transient
+  for i := 1 to times do
+  begin
+    bigservice := iocContainer.Resolve<IBigService>('other');
+    res := bigservice.Mult(2,4);
+  end;
+  if bigservice.NumOperations = 1 then meInfo.Lines.Add('Test4: Constructor injection as Transient test ok')
+    else meInfo.Lines.Add('Test4: Constructor injection as Transient test error');
+  meInfo.Lines.Add(Format('BigService.Mult = %d (calls: %d to BigService / calls: %d to MultService (as transient))',[res,bigservice.NumOperations,bigservice.multservice.NumOperations]));
+
+  //test5: class instance injection as singleton
+  for i := 1 to times do
+  begin
+    divideservice := iocContainer.Resolve<TDivideService>('one');
+    res := divideservice.Divide(100,2);
+  end;
+  if divideservice.NumOperations = times * executions then meInfo.Lines.Add('Test5: Class instance injection as Singleton test ok')
+    else meInfo.Lines.Add('Test5: Class instance injection as Singleton test error');
+  meInfo.Lines.Add(Format('DivideService.Divide = %d (calls: %d)',[res,divideservice.NumOperations]));
+
+  //test6: class instance injection as transient
+  for i := 1 to times do
+  begin
+    divideservice := iocContainer.Resolve<TDivideService>('other');
+    res := divideservice.Divide(100,2);
+    numoperations := divideservice.NumOperations;
+    //transient instances must be manual free
+    divideservice.Free;
+  end;
+  if numoperations = 1 then meInfo.Lines.Add('Test6: Class instance injection as Transient test ok')
+    else meInfo.Lines.Add('Test6: Class instance injection as Transient test error');
+  meInfo.Lines.Add(Format('DivideService.Divide = %d (calls: %d)',[res,numoperations]));
+
+  meInfo.Lines.Add('Test finished');
+end;
+
+procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
+begin
+  iocContainer.Free;
+end;
+
+procedure TForm1.FormCreate(Sender: TObject);
+begin
+  iocContainer := TIocContainer.Create;
+    iocContainer.RegisterType<ISumService,TSumService>.AsSingleTon.DelegateTo(function : TSumService
+                                                                              begin
+                                                                                Result := TSumService.Create;
+                                                                              end);
+    iocContainer.RegisterType<IMultService,TMultService>.AsTransient;
+    iocContainer.RegisterType<IBigService,TBigService>('one').AsSingleTon;
+    iocContainer.RegisterType<IBigService,TBigService>('other').AsTransient;
+
+    iocContainer.RegisterInstance<TDivideService>('one').AsSingleton.DelegateTo(function : TDivideService
+                                                                                begin
+                                                                                  Result := TDivideService.Create(True);
+                                                                                end);
+    iocContainer.RegisterInstance<TDivideService>('other').AsTransient.DelegateTo(function : TDivideService
+                                                                                begin
+                                                                                  Result := TDivideService.Create(True);
+                                                                                end);
+end;
+
+end.

+ 144 - 0
samples/fpc/QuickHttpServer/HttpServerService.Logger.pas

@@ -0,0 +1,144 @@
+unit HttpServerService.Logger;
+
+interface
+
+uses
+  SysUtils,
+  Quick.Logger.Intf,
+  Quick.Logger,
+  Quick.Logger.Provider.Console;
+
+type
+  TQuickLogger = class(TInterfacedObject,ILogger)
+  public
+    procedure Init;
+    procedure Info(const aMsg : string); overload;
+    procedure Info(const aMsg : string; aValues : array of const); overload;
+    procedure Succ(const aMsg : string); overload;
+    procedure Succ(const aMsg : string; aParams : array of const); overload;
+    procedure Done(const aMsg : string); overload;
+    procedure Done(const aMsg : string; aValues : array of const); overload;
+    procedure Warn(const aMsg : string); overload;
+    procedure Warn(const aMsg : string; aValues : array of const); overload;
+    procedure Error(const aMsg : string); overload;
+    procedure Error(const aMsg : string; aValues : array of const); overload;
+    procedure Critical(const aMsg : string); overload;
+    procedure Critical(const aMsg : string; aValues : array of const); overload;
+    procedure Trace(const aMsg : string); overload;
+    procedure Trace(const aMsg : string; aValues : array of const); overload;
+    procedure Debug(const aMsg : string); overload;
+    procedure Debug(const aMsg : string; aValues : array of const); overload;
+    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;
+  end;
+
+implementation
+
+{ TQuickLogger }
+
+
+procedure TQuickLogger.Init;
+begin
+  GlobalLogConsoleProvider.LogLevel := LOG_DEBUG;
+  Logger.Providers.Add(GlobalLogConsoleProvider);
+  GlobalLogConsoleProvider.Enabled := True;
+end;
+
+procedure TQuickLogger.Info(const aMsg: string);
+begin
+  Logger.Info(aMsg);
+end;
+
+procedure TQuickLogger.Info(const aMsg: string; aValues: array of const);
+begin
+  Logger.Info(aMsg,aValues);
+end;
+
+procedure TQuickLogger.Succ(const aMsg: string);
+begin
+  Logger.Succ(aMsg);
+end;
+
+procedure TQuickLogger.Succ(const aMsg: string; aParams: array of const);
+begin
+  Logger.Succ(aMsg,aParams);
+end;
+
+procedure TQuickLogger.Done(const aMsg: string);
+begin
+  Logger.Done(aMsg);
+end;
+
+procedure TQuickLogger.Done(const aMsg: string; aValues: array of const);
+begin
+  Logger.Done(aMsg,aValues);
+end;
+
+procedure TQuickLogger.Warn(const aMsg: string);
+begin
+  Logger.Warn(aMsg);
+end;
+
+procedure TQuickLogger.Warn(const aMsg: string; aValues: array of const);
+begin
+  Logger.Warn(aMsg,aValues);
+end;
+
+procedure TQuickLogger.Error(const aMsg: string);
+begin
+  Logger.Error(aMsg);
+end;
+
+procedure TQuickLogger.Error(const aMsg: string; aValues: array of const);
+begin
+  Logger.Error(aMsg,aValues);
+end;
+
+procedure TQuickLogger.Critical(const aMsg: string);
+begin
+  Logger.Critical(aMsg);
+end;
+
+procedure TQuickLogger.Critical(const aMsg: string; aValues: array of const);
+begin
+  Logger.Critical(aMsg,aValues);
+end;
+
+procedure TQuickLogger.Trace(const aMsg: string);
+begin
+  Logger.Trace(aMsg);
+end;
+
+procedure TQuickLogger.Trace(const aMsg: string; aValues: array of const);
+begin
+  Logger.Trace(aMsg,aValues);
+end;
+
+procedure TQuickLogger.Debug(const aMsg: string);
+begin
+  Logger.Debug(aMsg);
+end;
+
+procedure TQuickLogger.Debug(const aMsg: string; aValues: array of const);
+begin
+  Logger.Debug(aMsg,aValues);
+end;
+
+procedure TQuickLogger.&Except(const aMsg: string; aValues: array of const);
+begin
+  Logger.&Except(aMsg,aValues);
+end;
+
+procedure TQuickLogger.&Except(const aMsg: string; aValues: array of const; const aException, aStackTrace: string);
+begin
+  Logger.&Except(aMsg,aValues,aException,aStacktrace);
+end;
+
+procedure TQuickLogger.&Except(const aMsg, aException, aStackTrace: string);
+begin
+  Logger.&Except(aMsg,aException,aStackTrace);
+end;
+
+end.
+

+ 66 - 0
samples/fpc/QuickHttpServer/HttpServerService.lpi

@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CONFIG>
+  <ProjectOptions>
+    <Version Value="11"/>
+    <PathDelim Value="\"/>
+    <General>
+      <Flags>
+        <MainUnitHasCreateFormStatements Value="False"/>
+        <MainUnitHasTitleStatement Value="False"/>
+        <MainUnitHasScaledStatement Value="False"/>
+      </Flags>
+      <SessionStorage Value="InProjectDir"/>
+      <MainUnit Value="0"/>
+      <Title Value="HttpServerService"/>
+      <UseAppBundle Value="False"/>
+      <ResourceType Value="res"/>
+    </General>
+    <BuildModes Count="1">
+      <Item1 Name="Default" Default="True"/>
+    </BuildModes>
+    <PublishOptions>
+      <Version Value="2"/>
+    </PublishOptions>
+    <RunParams>
+      <FormatVersion Value="2"/>
+      <Modes Count="0"/>
+    </RunParams>
+    <RequiredPackages Count="1">
+      <Item1>
+        <PackageName Value="indylaz"/>
+      </Item1>
+    </RequiredPackages>
+    <Units Count="1">
+      <Unit0>
+        <Filename Value="HttpServerService.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit0>
+    </Units>
+  </ProjectOptions>
+  <CompilerOptions>
+    <Version Value="11"/>
+    <PathDelim Value="\"/>
+    <Target>
+      <Filename Value="HttpServerService"/>
+    </Target>
+    <SearchPaths>
+      <IncludeFiles Value="$(ProjOutDir)"/>
+      <Libraries Value="..\..\..;..\..\..\..\QuickLogger"/>
+      <OtherUnitFiles Value="..\..\..;..\..\..\..\QuickLogger"/>
+      <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
+    </SearchPaths>
+  </CompilerOptions>
+  <Debugging>
+    <Exceptions Count="3">
+      <Item1>
+        <Name Value="EAbort"/>
+      </Item1>
+      <Item2>
+        <Name Value="ECodetoolError"/>
+      </Item2>
+      <Item3>
+        <Name Value="EFOpenError"/>
+      </Item3>
+    </Exceptions>
+  </Debugging>
+</CONFIG>

+ 73 - 0
samples/fpc/QuickHttpServer/HttpServerService.pas

@@ -0,0 +1,73 @@
+program HttpServerService;
+
+uses
+  SysUtils,
+  Quick.Commons,
+  Quick.Logger.Intf,
+  Quick.Console,
+  Quick.AppService,
+  Quick.HttpServer,
+  Quick.HttpServer.Request,
+  Quick.HttpServer.Response,
+  HttpServerService.Logger;
+
+type
+  TMyHttpServer = class(THttpServer)
+  public
+    procedure ProcessRequest(aRequest: IHttpRequest; aResponse: IHttpResponse); override;
+  end;
+
+  procedure TMyHttpServer.ProcessRequest(aRequest: IHttpRequest; aResponse: IHttpResponse);
+  begin
+    aResponse.ContentText := 'Hello world!';
+  end;
+
+var
+  HttpServer : TMyHttpServer;
+  Port : Integer;
+  Logger : TQuickLogger;
+
+begin
+  try
+    {$IFNDEF FPC}
+    ReportMemoryLeaksOnShutdown := True;
+    {$ENDIF}
+    //run as console
+    Logger := TQuickLogger.Create;
+    Logger.Init;
+    if not AppService.IsRunningAsService then
+    begin
+      //create server
+      cout('Init server...',etInfo);
+      if ParamCount > 0 then
+      begin
+        Integer.TryParse(ParamStr(1),Port)
+      end;
+      //start server
+      if Port = 0 then Port := 8080;
+      HttpServer := TMyHttpServer.Create('127.0.0.1',Port,False,Logger);
+      try
+        HttpServer.Start;
+        //Wait for Exit
+        cout(' ',ccWhite);
+        cout('Press [Enter] to quit',ccYellow);
+        ConsoleWaitForEnterKey;
+      finally
+        HttpServer.Free;
+      end;
+    end
+    else //run as a service
+    begin
+      AppService.DisplayName := 'Remote Server';
+      AppService.ServiceName := 'RemoteServerSvc';
+      AppService.CanInstallWithOtherName := True;
+      HttpServer := TMyHttpServer.Create('127.0.0.1',Port,False,Logger);
+      AppService.OnStop := @HttpServer.Free;
+      AppService.OnExecute := @HttpServer.Start;
+      AppService.CheckParams;
+    end;
+  except
+    on E: Exception do
+      Writeln(E.ClassName, ': ', E.Message);
+  end;
+end.

Some files were not shown because too many files changed in this diff