浏览代码

Merge branch 'develop'

Exilon 4 年之前
父节点
当前提交
42d0550a18

+ 53 - 34
Quick.Amazon.pas

@@ -7,7 +7,7 @@
   Author      : Kike Pérez
   Version     : 1.4
   Created     : 18/11/2016
-  Modified    : 21/02/2018
+  Modified    : 11/09/2020
 
   This file is part of QuickLib: https://github.com/exilon/QuickLib
 
@@ -29,6 +29,8 @@
 
 unit Quick.Amazon;
 
+{$i QuickLib.inc}
+
 interface
 
 uses
@@ -111,7 +113,9 @@ type
       function ListBuckets(var amResponseInfo : TAmazonResponseInfo) : TStrings;
       function CreateBucket(amBucket : string; amBucketRegion : TAmazonRegion; amACLType : TAmazonACLAccess; var amResponseInfo : TAmazonResponseInfo) : Boolean;
       function DeleteBucket(amBucket : string; amBucketRegion : TAmazonRegion; var amResponseInfo : TAmazonResponseInfo) : Boolean;
+      {$IFNDEF DELPHISYDNEY_UP}
       class function GetAWSRegion(Region: TAmazonRegion): string; overload;
+      {$ENDIF}
       class function GetAWSRegion(const Region : string) : TAmazonRegion; overload;
   end;
 
@@ -228,7 +232,6 @@ var
   Content : TArray<Byte>;
   CloudResponseInfo : TCloudResponseInfo;
 begin
-  Result := False;
   AmazonS3 := TAmazonStorage.Create(fconAmazon);
   if amBucket = '' then amBucket := '$root';
   CloudResponseInfo := TCloudResponseInfo.Create;
@@ -258,13 +261,16 @@ begin
     try
       //AmazonS3.Timeout := fTimeout;
       CloudResponseInfo := TCloudResponseInfo.Create;
-      //CloudResponseInfo.Headers.AddPair();
-      Content := StreamToArray(cStream);
-      Result := AmazonS3.UploadObject(amBucket,amObjectName,Content,False,nil,nil,amACLType,CloudResponseInfo);
-      amResponseInfo := GetResponseInfo(CloudResponseInfo);
+      try
+        //CloudResponseInfo.Headers.AddPair();
+        Content := StreamToArray(cStream);
+        Result := AmazonS3.UploadObject(amBucket,amObjectName,Content,False,nil,nil,amACLType,CloudResponseInfo);
+        amResponseInfo := GetResponseInfo(CloudResponseInfo);
+      finally
+        CloudResponseInfo.Free;
+      end;
     finally
       AmazonS3.Free;
-      CloudResponseInfo.Free;
       SetLength(Content,0);
       Content := nil;
     end;
@@ -278,7 +284,7 @@ var
   AmazonS3 : TAmazonStorage;
   fs : TFileStream;
   CloudResponseInfo : TCloudResponseInfo;
-  amParams : TAmazonGetObjectOptionals;
+  //amParams : TAmazonGetObjectOptionals;
 begin
   Result := False;
   if amBucket = '' then amBucket := '$root';
@@ -309,7 +315,6 @@ end;
 function TQuickAmazon.GetObject(amBucket, amObjectName : string; var amResponseInfo : TAmazonResponseInfo) : TMemoryStream;
 var
   AmazonS3 : TAmazonStorage;
-  fs : TFileStream;
   CloudResponseInfo : TCloudResponseInfo;
 begin
   Result := TMemoryStream.Create;
@@ -320,14 +325,17 @@ begin
     //AmazonS3.Timeout := fTimeout;
     CloudResponseInfo := TCloudResponseInfo.Create;
     try
-      AmazonS3.GetObject(amBucket,amObjectName,Result,CloudResponseInfo);
-      amResponseInfo := GetResponseInfo(CloudResponseInfo);
-    except
-      Result := nil;
+      try
+        AmazonS3.GetObject(amBucket,amObjectName,Result,CloudResponseInfo);
+        amResponseInfo := GetResponseInfo(CloudResponseInfo);
+      except
+        Result := nil;
+      end;
+    finally
+      CloudResponseInfo.Free;
     end;
   finally
     AmazonS3.Free;
-    CloudResponseInfo.Free;
   end;
 end;
 
@@ -361,18 +369,20 @@ var
   AmazonS3 : TAmazonStorage;
   CloudResponseInfo : TCloudResponseInfo;
 begin
-  Result := False;
   if amBucket = '' then amBucket := '$root';
   if amObjectName.StartsWith('/') then amObjectName := Copy(amObjectName,2,Length(amObjectName));
   AmazonS3 := TAmazonStorage.Create(fconAmazon);
   try
     //AmazonS3.Timeout := fTimeout;
     CloudResponseInfo := TCloudResponseInfo.Create;
-    Result := AmazonS3.DeleteObject(amBucket,amObjectName,CloudResponseInfo);
-    amResponseInfo := GetResponseInfo(CloudResponseInfo);
+    try
+      Result := AmazonS3.DeleteObject(amBucket,amObjectName,CloudResponseInfo);
+      amResponseInfo := GetResponseInfo(CloudResponseInfo);
+    finally
+      CloudResponseInfo.Free;
+    end;
   finally
     AmazonS3.Free;
-    CloudResponseInfo.Free;
   end;
 end;
 
@@ -385,7 +395,6 @@ var
   CloudResponseInfo : TCloudResponseInfo;
   cNextMarker : string;
   amParams : TStrings;
-  a : TAmazonBucketResult;
 begin
   Result := TAmazonObjects.Create(True);
   cNextMarker := '';
@@ -437,7 +446,6 @@ var
   CloudResponseInfo : TCloudResponseInfo;
   cNextMarker : string;
   amParams : TStrings;
-  a : TAmazonBucketResult;
 begin
   Result := TStringList.Create;
   cNextMarker := '';
@@ -510,20 +518,23 @@ begin
   try
     //AmazonS3.Timeout := fTimeout;
     CloudResponseInfo := TCloudResponseInfo.Create;
-    Buckets := AmazonS3.ListBuckets(CloudResponseInfo);
     try
-      Result.Capacity := Buckets.Count;
-      for i := 0 to Buckets.Count -1 do
-      begin
-        Result.Add(Buckets.Names[i]);
+      Buckets := AmazonS3.ListBuckets(CloudResponseInfo);
+      try
+        Result.Capacity := Buckets.Count;
+        for i := 0 to Buckets.Count -1 do
+        begin
+          Result.Add(Buckets.Names[i]);
+        end;
+        amResponseInfo := GetResponseInfo(CloudResponseInfo);
+      finally
+        Buckets.Free;
       end;
-      amResponseInfo := GetResponseInfo(CloudResponseInfo);
     finally
-      Buckets.Free;
+      CloudResponseInfo.Free;
     end;
   finally
     AmazonS3.Free;
-    CloudResponseInfo.Free;
   end;
 end;
 
@@ -538,11 +549,14 @@ begin
   AmazonS3 := TAmazonStorageService.Create(fconAmazon);
   try
     CloudResponseInfo := TCloudResponseInfo.Create;
-    Result := AmazonS3.CreateBucket(amBucket,amACLType,amBucketRegion,CloudResponseInfo);
-    amResponseInfo := GetResponseInfo(CloudResponseInfo);
+    try
+      Result := AmazonS3.CreateBucket(amBucket,amACLType,amBucketRegion,CloudResponseInfo);
+      amResponseInfo := GetResponseInfo(CloudResponseInfo);
+    finally
+      CloudResponseInfo.Free;
+    end;
   finally
     AmazonS3.Free;
-    CloudResponseInfo.Free;
   end;
 end;
 
@@ -557,11 +571,14 @@ begin
   AmazonS3 := TAmazonStorageService.Create(fconAmazon);
   try
     CloudResponseInfo := TCloudResponseInfo.Create;
-    Result := AmazonS3.DeleteBucket(amBucket,CloudResponseInfo,amBucketRegion);
-    amResponseInfo := GetResponseInfo(CloudResponseInfo);
+    try
+      Result := AmazonS3.DeleteBucket(amBucket,CloudResponseInfo,amBucketRegion);
+      amResponseInfo := GetResponseInfo(CloudResponseInfo);
+    finally
+      CloudResponseInfo.Free;
+    end;
   finally
     AmazonS3.Free;
-    CloudResponseInfo.Free;
   end;
 end;
 
@@ -570,9 +587,11 @@ begin
   Result := TAmazonStorageService.GetRegionFromString(Region);
 end;
 
+{$IFNDEF DELPHISYDNEY_UP}
 class function TQuickAmazon.GetAWSRegion(Region: TAmazonRegion): string;
 begin
   Result := TAmazonStorageService.GetRegionString(Region);
 end;
+{$ENDIF}
 
 end.

+ 1 - 0
Quick.AppService.pas

@@ -188,6 +188,7 @@ begin
   fStatus := TSvcStatus.ssStopped;
   fCanInstallWithOtherName := False;
   fOnExecute := nil;
+  IsQuickServiceApp := True;
 end;
 
 destructor TAppService.Destroy;

+ 21 - 1
Quick.Commons.pas

@@ -7,7 +7,7 @@
   Author      : Kike Pérez
   Version     : 2.0
   Created     : 14/07/2017
-  Modified    : 14/07/2020
+  Modified    : 06/08/2020
 
   This file is part of QuickLib: https://github.com/exilon/QuickLib
 
@@ -304,6 +304,8 @@ type
   function GetComputerName : string;
   //Changes incorrect delims in path
   function NormalizePathDelim(const cPath : string; const Delim : Char) : string;
+  //combine paths normalized with delim
+  function CombinePaths(const aFirstPath, aSecondPath: string; aDelim : Char): string;
   //Removes last segment of a path
   function RemoveLastPathSegment(cDir : string) : string;
   //returns path delimiter if found
@@ -386,6 +388,8 @@ type
 
 var
   path : TEnvironmentPath;
+  //Enabled if QuickService is defined
+  IsQuickServiceApp : Boolean;
 
 implementation
 
@@ -985,6 +989,22 @@ begin
     else Result := StringReplace(cPath,'\',Delim,[rfReplaceAll]);
 end;
 
+function CombinePaths(const aFirstPath, aSecondPath: string; aDelim : Char): string;
+begin
+  var path1 := NormalizePathDelim(aFirstPath,aDelim);
+  var path2 := NormalizePathDelim(aSecondPath,aDelim);
+  if path1.EndsWith(aDelim) then
+  begin
+    if path2.StartsWith(aDelim) then Result := path1 + path2.Substring(1)
+      else Result := path1 + path2;
+  end
+  else
+  begin
+     if path2.StartsWith(aDelim) then Result := path1 + path2
+      else result := path1 + aDelim + path2;
+  end;
+end;
+
 function RemoveLastPathSegment(cDir : string) : string;
 var
   posi : Integer;

+ 20 - 0
Quick.Console.pas

@@ -169,6 +169,7 @@ type
   procedure cout(const cMsg : Double; cEventType : TLogEventType); overload;
   procedure cout(const cMsg : string; cEventType : TLogEventType); overload;
   procedure cout(const cMsg : string; cColor : TConsoleColor); overload;
+  procedure coutSL(const cMsg : string; cColor : TConsoleColor);
   procedure cout(const cMsg : string; params : array of const; cEventType : TLogEventType); overload;
   procedure coutXY(x,y : Integer; const cMsg : string; cEventType : TLogEventType); overload;
   procedure coutXY(x,y : Integer; const cMsg : string; cColor : TConsoleColor); overload;
@@ -327,6 +328,25 @@ begin
   end;
 end;
 
+procedure coutSL(const cMsg : string; cColor : TConsoleColor);
+begin
+  EnterCriticalSection(CSConsole);
+  try
+    {$IFDEF MSWINDOWS}
+      if hStdOut <> 0 then
+    {$ENDIF}
+    begin
+      TextColor(cColor);
+      {$I-}
+      Write(cMsg{$IFDEF LINUX} +#13{$ENDIF});
+      {$I+}
+      TextColor(LastMode);
+    end;
+  finally
+    LeaveCriticalSection(CSConsole);
+  end;
+end;
+
 procedure cout(const cMsg : string; params : array of const; cEventType : TLogEventType);
 begin
   cout(Format(cMsg,params),cEventType);

+ 1 - 0
Quick.Debug.Utils.pas

@@ -198,6 +198,7 @@ end;
 
 class procedure TDebugger.SetLogger(aLogger: ILogger);
 begin
+  if aLogger = nil then raise Exception.Create('Debugger logger cannot be nil!');
   fLogger := aLogger;
   fShowTime := False;
 end;

+ 117 - 1
Quick.Files.pas

@@ -224,6 +224,21 @@ type
   end;
   {$ENDIF FPC}
 
+  TDirItem = record
+  private
+    fName : string;
+    fIsDirectory : Boolean;
+    fSize : Int64;
+    fCreationDate : TDateTime;
+    fLastModified : TDateTime;
+  public
+    property Name : string read fName write fName;
+    property IsDirectory : Boolean read fIsDirectory write fIsDirectory;
+    property Size : Int64 read fSize write fSize;
+    property CreationDate : TDateTime read fCreationDate write fCreationDate;
+    property LastModified : TDateTime read fLastModified write fLastModified;
+  end;
+
   function CreateDummyFile(const aFilename : string; const aSize : Int64) : Boolean;
   procedure SplitFile(const aFileName : string; aSplitByteSize : Int64);
   procedure MergeFiles(const aFirstSplitFileName, aOutFileName : string); overload;
@@ -242,7 +257,11 @@ type
   function FindDelimiter(const Delimiters, S: string; StartIdx: Integer = 1): Integer;
   {$ENDIF}
   function ConvertDateTimeToFileTime(const DateTime: TDateTime; const UseLocalTimeZone: Boolean): TFileTime;
+  function ConvertFileTimeToDateTime(const FileTime : TFileTime; const UseLocalTimeZone : Boolean) : TDateTime;
   procedure SetDateTimeInfo(const Path: string; const CreationTime, LastAccessTime, LastWriteTime: PDateTime; const UseLocalTimeZone: Boolean);
+  function GetFiles(const Path : string; Recursive : Boolean) : TArray<TDirItem>;
+  function GetDirectories(const Path : string; Recursive : Boolean) : TArray<TDirItem>;
+  function GetFilesAndDirectories(const Path : string; Recursive : Boolean) : TArray<TDirItem>;
 
 implementation
 
@@ -731,7 +750,6 @@ var
   i : Integer;
   buf : string;
 Begin
-  Result := False;
   fs := TFileStream.Create(aFilename,fmCreate);
   buf := 'A';
   try
@@ -969,6 +987,7 @@ var
   lft: TFileTime;
   h:   THandle;
 begin
+  Result := 0;
   {$IFDEF FPC}
   h := FindFirstFile(PAnsiChar(aFileName), ffd);
   {$ELSE}
@@ -990,6 +1009,7 @@ var
   lft: TFileTime;
   h:   THandle;
 begin
+  Result := 0;
   {$IFDEF FPC}
   h := FindFirstFile(PAnsiChar(aFileName), ffd);
   {$ELSE}
@@ -1011,6 +1031,7 @@ var
   lft: TFileTime;
   h:   THandle;
 begin
+  Result := 0;
   {$IFDEF FPC}
   h := FindFirstFile(PAnsiChar(aFileName), ffd);
   {$ELSE}
@@ -1123,6 +1144,17 @@ begin
     else
       Result := LFileTime;
 end;
+function ConvertFileTimeToDateTime(const FileTime : TFileTime; const UseLocalTimeZone : Boolean) : TDateTime;
+var
+  dft: DWORD;
+  lft: TFileTime;
+begin
+  FileTimeToLocalFileTime(FileTime, lft);
+  FileTimeToDosDateTime(lft, LongRec(dft).Hi, LongRec(dft).Lo);
+  Result := FileDateToDateTime(dft);
+end;
+
+
 {$ENDIF}
 {$If Defined(FPC) AND Defined(LINUX)}
 function ConvertDateTimeToFileTime(const DateTime: TDateTime; const UseLocalTimeZone: Boolean): TFileTime;
@@ -1256,4 +1288,88 @@ begin
 end;
 {$ENDIF}
 
+function GetFiles(const Path : string; Recursive : Boolean) : TArray<TDirItem>;
+var
+  rec : TSearchRec;
+  diritem : TDirItem;
+begin
+  if FindFirst(IncludeTrailingPathDelimiter(Path) + '*', faAnyFile, rec) = 0 then
+  try
+    repeat
+      if (rec.Attr and faDirectory) <> faDirectory then
+      begin
+        diritem.Name := rec.Name;
+        diritem.IsDirectory := False;
+        diritem.Size := rec.Size;
+        diritem.CreationDate := ConvertFileTimeToDateTime(rec.FindData.ftCreationTime,True);
+        diritem.LastModified := ConvertFileTimeToDateTime(rec.FindData.ftLastWriteTime,True);
+        Result := Result + [diritem];
+      end
+      else
+      begin
+        if Recursive then Result := Result + GetFiles(IncludeTrailingPathDelimiter(Path) + diritem.Name,Recursive);
+      end;
+    until FindNext(rec) <> 0;
+  finally
+    SysUtils.FindClose(rec);
+  end;
+end;
+
+function GetDirectories(const Path : string; Recursive : Boolean) : TArray<TDirItem>;
+var
+  rec : TSearchRec;
+  diritem : TDirItem;
+begin
+  if FindFirst(IncludeTrailingPathDelimiter(Path) + '*', faAnyFile, rec) = 0 then
+  try
+    repeat
+      if ((rec.Attr and faDirectory) = faDirectory) and (rec.Name <> '.') and (rec.Name <> '..') then
+      begin
+        diritem.Name := rec.Name;
+        diritem.IsDirectory := True;
+        diritem.Size := rec.Size;
+        diritem.CreationDate := ConvertFileTimeToDateTime(rec.FindData.ftCreationTime,True);
+        diritem.LastModified := ConvertFileTimeToDateTime(rec.FindData.ftLastWriteTime,True);
+        Result := Result + [diritem];
+        if Recursive then Result := Result + GetFiles(IncludeTrailingPathDelimiter(Path) + diritem.Name,Recursive);
+      end;
+    until FindNext(rec) <> 0;
+  finally
+    SysUtils.FindClose(rec);
+  end;
+end;
+
+function GetFilesAndDirectories(const Path : string; Recursive : Boolean) : TArray<TDirItem>;
+var
+  rec : TSearchRec;
+  diritem : TDirItem;
+begin
+  if FindFirst(IncludeTrailingPathDelimiter(Path) + '*', faAnyFile, rec) = 0 then
+  try
+    repeat
+      if (rec.Attr and faDirectory) <> faDirectory then
+      begin
+        diritem.Name := rec.Name;
+        diritem.IsDirectory := False;
+        diritem.Size := rec.Size;
+        diritem.CreationDate := ConvertFileTimeToDateTime(rec.FindData.ftCreationTime,True);
+        diritem.LastModified := ConvertFileTimeToDateTime(rec.FindData.ftLastWriteTime,True);
+        Result := Result + [diritem];
+      end
+      else if (rec.Name <> '.') and (rec.Name <> '..') then
+      begin
+        diritem.Name := rec.Name;
+        diritem.IsDirectory := True;
+        diritem.Size := rec.Size;
+        diritem.CreationDate := ConvertFileTimeToDateTime(rec.FindData.ftCreationTime,True);
+        diritem.LastModified := ConvertFileTimeToDateTime(rec.FindData.ftLastWriteTime,True);
+        Result := Result + [diritem];
+        if Recursive then Result := Result + GetFiles(IncludeTrailingPathDelimiter(Path) + diritem.Name,Recursive);
+      end;
+    until FindNext(rec) <> 0;
+  finally
+    SysUtils.FindClose(rec);
+  end;
+end;
+
 end.

+ 3 - 3
Quick.HttpServer.pas

@@ -391,7 +391,8 @@ begin
     on E : Exception do
     begin
       //get unexpected exception
-      if E.ClassType <> EControlledException then
+      if E.InheritsFrom(EControlledException) then response.ContentText := response.ContentText + '<BR>' + e.Message
+      else
       begin
         if response.StatusCode = 200 then
         begin
@@ -399,8 +400,7 @@ begin
           response.StatusText := 'Internal server error';
         end;
         response.ContentText := e.Message;
-      end
-      else response.ContentText := response.ContentText + '<BR>' + e.Message;
+      end;
     end;
   end;
   //check if need return error page

+ 705 - 0
Quick.Parameters.pas

@@ -0,0 +1,705 @@
+{ ***************************************************************************
+
+  Copyright (c) 2016-2020 Kike Pérez
+
+  Unit        : Quick.Parameters
+  Description : Map comandline to class
+  Author      : Kike Pérez
+  Version     : 1.4
+  Created     : 12/07/2020
+  Modified    : 29/07/2020
+
+  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.Parameters;
+
+{$i QuickLib.inc}
+
+interface
+
+uses
+  Classes,
+  SysUtils,
+  StrUtils,
+  Generics.Collections,
+  Quick.Commons,
+  {$IFDEF CONSOLE}
+  Quick.Console,
+  {$ENDIF}
+  rtti,
+  TypInfo,
+  Quick.RTTI.Utils;
+
+type
+
+  CommandDescription = class(TCustomAttribute)
+  private
+    fDescription : string;
+  public
+    constructor Create(const aDescription : string);
+    property Description : string read fDescription;
+  end;
+
+  ParamCommand = class(TCustomAttribute)
+  private
+    fPosition : Integer;
+  public
+    constructor Create(aPosition : Integer);
+    property Position : Integer read fPosition;
+  end;
+
+  ParamName = class(TCustomAttribute)
+  private
+    fName : string;
+    fAlias : string;
+  public
+    constructor Create(const aName: string; const aAlias : string = '');
+    property Name : string read fName;
+    property Alias : string read fAlias;
+  end;
+
+  ParamValueIsNextParam = class(TCustomAttribute);
+
+  ParamHelp = class(TCustomAttribute)
+  private
+    fHelp : string;
+    fValueName : string;
+  public
+    constructor Create(const aHelp : string; const aValueName : string = '');
+    property Help : string read fHelp;
+    property ValueName : string read fValueName;
+  end;
+
+  ParamSwitchChar = class(TCustomAttribute)
+  private
+    fSwithChar : string;
+  public
+    constructor Create(const aSwitchChar : string);
+    property SwitchChar : string read fSwithChar write fSwithChar;
+  end;
+
+  ParamValueSeparator = class(TCustomAttribute)
+  private
+    fValueSeparator : string;
+  public
+    constructor Create(const aValueSeparator : string);
+    property ValueSeparator : string read fValueSeparator write fValueSeparator;
+  end;
+
+  ParamRequired = class(TCustomAttribute);
+
+  {$IFDEF CONSOLE}
+  TColorizeHelp = class
+  private
+    fCommandName : TConsoleColor;
+    fCommandDescription : TConsoleColor;
+    fCommandUsage : TConsoleColor;
+    fSections : TConsoleColor;
+    fArgumentName : TConsoleColor;
+    fArgumentDescription : TConsoleColor;
+  public
+    property CommandName : TConsoleColor read fCommandName write fCommandName;
+    property CommandDescription : TConsoleColor read fCommandDescription write fCommandDescription;
+    property CommandUsage : TConsoleColor read fCommandUsage write fCommandUsage;
+    property Sections : TConsoleColor read fSections write fSections;
+    property ArgumentName : TConsoleColor read fArgumentName write fArgumentName;
+    property ArgumentDescription : TConsoleColor read fArgumentDescription write fArgumentDescription;
+  end;
+  {$ENDIF}
+
+  TParameters = class
+  type
+    TValueType = (vtString, vtInteger, vtFloat, vtBoolean, vtEnumeration);
+    TParam = class
+    private
+      fName : string;
+      fAlias : string;
+      fValue : string;
+      fPrecisePosition : Integer;
+      fParamType: TValueType;
+      fRequired : Boolean;
+      fHelp : string;
+      fValueName : string;
+      fValueIsNextParam: Boolean;
+      fSwitchChar: string;
+      fValueSeparator: string;
+      fIsPresent: Boolean;
+    public
+      constructor Create;
+      property Name : string read fName write fName;
+      property Alias : string read fAlias write fAlias;
+      property Value : string read fValue write fValue;
+      property PrecisePosition : Integer read fPrecisePosition write fPrecisePosition;
+      property ParamType : TValueType read fParamType write fParamType;
+      property Required : Boolean read fRequired write fRequired;
+      property SwitchChar : string read fSwitchChar write fSwitchChar;
+      property ValueSeparator : string read fValueSeparator write fValueSeparator;
+      property Help : string read fHelp write fHelp;
+      property HepValueName : string read fValueName write fValueName;
+      property ValueIsNextParam : Boolean read fValueIsNextParam write fValueIsNextParam;
+      property IsPresent : Boolean read fIsPresent write fIsPresent;
+      function IsSwitch : Boolean;
+      function IsCommand : Boolean;
+    end;
+  private
+    fParams : TObjectList<TParam>;
+    fDescription : string;
+    fHelp: Boolean;
+    {$IFDEF CONSOLE}
+    fColorizeHelp: TColorizeHelp;
+    {$ENDIF}
+    function ExistParam(aParameter : TParam; const aParam : string) : Boolean;
+    function GetParamName(aParameter : TParam; const aParam : string) : string;
+    function GetParamValue(aParameter : TParam; const aParam : string) : string;
+    function ValueType(const aProp : TRttiProperty) : TValueType;
+    procedure ParseParams;
+    function CheckHelpSwitch : Boolean;
+  protected
+  {$IFDEF CONSOLE}
+    procedure GetColors; virtual;
+  {$ENDIF}
+    procedure Validate; virtual;
+  public
+    constructor Create; virtual;
+    destructor Destroy; override;
+    property Description : string read fDescription write fDescription;
+    {$IFDEF CONSOLE}
+    property ColorizeHelp : TColorizeHelp read fColorizeHelp write fColorizeHelp;
+    procedure ShowHelp; virtual;
+    {$ENDIF}
+    function GetHelp : TStringList;
+    property Help : Boolean read fHelp write fHelp;
+  end;
+
+  TServiceParameters = class(TParameters)
+  private
+    fInstance : string;
+    fInstall : Boolean;
+    fRemove : Boolean;
+    fConsole : Boolean;
+  published
+    [ParamHelp('Install service with a custom name','Service name')]
+    property Instance : string read fInstance write fInstance;
+
+    [ParamHelp('Install as a service')]
+    property Install : Boolean read fInstall write fInstall;
+
+    [ParamHelp('Remove service')]
+    property &Remove : Boolean read fRemove write fRemove;
+
+    [ParamHelp('Force run as a console application (when runned from another service)')]
+    property Console : Boolean read fConsole write fConsole;
+  end;
+
+  ENotValidCommandlineParameter = class(Exception);
+  ERequiredParameterNotFound = class(Exception);
+  EParameterValueNotFound = class(Exception);
+  EParamValueNotSupported = class(Exception);
+
+implementation
+
+{ TParameter }
+
+constructor TParameters.Create;
+begin
+  {$IFDEF CONSOLE}
+  fColorizeHelp := TColorizeHelp.Create;
+  GetColors;
+  {$ENDIF}
+  fParams := TObjectList<TParam>.Create(True);
+  ParseParams;
+  {$IFDEF CONSOLE}
+  if fHelp then
+  begin
+    ShowHelp;
+    Halt;
+  end;
+  {$ENDIF}
+  Validate;
+end;
+
+destructor TParameters.Destroy;
+begin
+  fParams.Free;
+  {$IFDEF CONSOLE}
+  fColorizeHelp.Free;
+  {$ENDIF}
+  inherited;
+end;
+
+function TParameters.ExistParam(aParameter : TParam; const aParam : string) : Boolean;
+var
+  i : Integer;
+  parName : string;
+begin
+  Result := False;
+  if aParam.IsEmpty then Exit;
+  for i := 1 to ParamCount do
+  begin
+    parName := ParamStr(i);
+    if parName = aParameter.ValueSeparator then raise ENotValidCommandlineParameter.CreateFmt('Not valid commandline "%s"', [parName]);
+    parName := GetParamName(aParameter,ParamStr(i));
+    if CompareText(parName,aParam) = 0 then Exit(True);
+  end;
+end;
+
+function TParameters.GetParamName(aParameter : TParam; const aParam : string) : string;
+var
+  switch : string;
+begin
+  if CompareText(aParam,'-' + aParameter.Alias) = 0 then switch := '-'
+    else switch := aParameter.SwitchChar;
+
+  if aParam.StartsWith(switch) then Result := aParam.Substring(switch.Length);
+  if Result.Contains(aParameter.ValueSeparator) then Result := Result.Substring(0,Result.IndexOf(aParameter.ValueSeparator));
+end;
+
+function TParameters.GetParamValue(aParameter : TParam; const aParam : string) : string;
+var
+  i : Integer;
+  parName : string;
+  param : string;
+begin
+  Result := '';
+  for i := 1 to ParamCount do
+  begin
+    param := ParamStr(i);
+    parName := GetParamName(aParameter,param);
+    if CompareText(parName,aParam) = 0 then
+    begin
+      if aParameter.ValueIsNextParam then
+      begin
+        if i < ParamCount then Result := ParamStr(i+1);
+      end
+      else
+      begin
+        if param.Contains(aParameter.ValueSeparator) then Result := param.Substring(param.IndexOf(aParameter.ValueSeparator)+(aParameter.ValueSeparator.Length));
+      end;
+      Exit;
+    end;
+  end;
+end;
+
+function TParameters.CheckHelpSwitch: Boolean;
+var
+  param : TParam;
+begin
+  param := TParam.Create;
+  param.Name := 'help';
+  param.Alias := 'h';
+  try
+    Result := ExistParam(param,param.Name);
+  finally
+    param.Free;
+  end;
+end;
+
+procedure TParameters.ParseParams;
+var
+  param : TParam;
+  value : TValue;
+  valueint : Int64;
+  valuefloat : Extended;
+  rType : TRttiType;
+  rProp : TRttiProperty;
+  attr : TCustomAttribute;
+  pinfo : PTypeInfo;
+  found : Boolean;
+begin
+  fHelp := CheckHelpSwitch;
+  rType := TRTTI.GetType(Self.ClassInfo);
+  //get main info
+  for attr in rType.GetAttributes do
+  begin
+    if attr is CommandDescription then Self.Description := CommandDescription(attr).Description;
+  end;
+  //get parameters
+  for rProp in TRTTI.GetProperties(rType,TRttiPropertyOrder.roFirstBase) do
+  begin
+    if rProp.Visibility <> TMemberVisibility.mvPublished then continue;
+    param := TParam.Create;
+    fParams.Add(param);
+    param.Name := rProp.Name;
+    for attr in rProp.GetAttributes do
+    begin
+      if attr is ParamHelp then
+      begin
+        param.Help := ParamHelp(attr).Help;
+        param.HepValueName := ParamHelp(attr).ValueName;
+      end;
+      if attr is ParamName then
+      begin
+        param.Name := ParamName(attr).Name;
+        param.Alias := ParamName(attr).Alias;
+      end;
+      if attr is ParamCommand then param.PrecisePosition := ParamCommand(attr).Position;      
+      if attr is ParamRequired then param.Required := True;
+      if attr is ParamSwitchChar then param.SwitchChar := ParamSwitchChar(attr).SwitchChar;
+      if attr is ParamValueSeparator then param.ValueSeparator := ParamValueSeparator(attr).ValueSeparator;
+      if attr is ParamValueIsNextParam then param.ValueIsNextParam := True;
+      
+    end;
+    param.ParamType := ValueType(rProp);
+    if param.IsCommand then
+    begin
+      found := ParamCount >= param.PrecisePosition;
+      param.SwitchChar := '  ';
+    end
+    else found := (ExistParam(param,param.Name)) or (ExistParam(param,param.Alias));
+    value := nil;
+    if found then    
+    begin
+      if param.IsSwitch then
+      begin
+        value := True;
+      end
+      else
+      begin
+        if param.IsCommand then param.Value := ParamStr(param.PrecisePosition)
+          else param.Value := GetParamValue(param,param.Name);
+        if (param.Value.IsEmpty) and (not param.Alias.IsEmpty) then param.Value := GetParamValue(param,param.Alias);
+
+        if (not param.Value.IsEmpty) and (not fHelp) then
+        case param.ParamType of
+          TValueType.vtString :
+            begin
+              value := param.Value;
+            end;
+          TValueType.vtInteger :
+            begin
+              if not TryStrToInt64(param.Value,valueint) then raise EParamValueNotSupported.CreateFmt('Parameter "%s" needs a numeric value',[param.Name]);
+              value := valueint;
+            end;
+          TValueType.vtFloat :
+            begin
+             if not TryStrToFloat(param.Value,valuefloat) then raise EParamValueNotSupported.CreateFmt('Parameter "%s" needs a float value',[param.Name]);
+             value := valuefloat;
+            end;
+          TValueType.vtEnumeration :
+            begin
+              pinfo := TRTTI.GetPropertyValue(Self,param.Name).TypeInfo;
+              if not IsInteger(param.Value) then TValue.Make(GetEnumValue(pinfo,param.Value),pinfo,value)
+                else TValue.Make(StrToInt(param.Value),pinfo,value);
+            end;
+        end;
+      end;
+      param.IsPresent := True;
+      if not value.IsEmpty then rProp.SetValue(Self,value);
+    end;
+  end;
+  //add help
+  param := TParam.Create;
+  param.Name := 'Help';
+  param.Alias := 'h';
+  param.ParamType := TValueType.vtBoolean;
+  param.Help := 'Show this documentation';
+  fParams.Add(param);
+end;
+
+procedure TParameters.Validate;
+var
+  param : TParam;
+begin
+  if help then Exit;
+
+  for param in fParams do
+  begin
+    if param.IsPresent then
+    begin
+      if (not param.IsSwitch) and (param.Value.IsEmpty) then raise EParamValueNotSupported.CreateFmt('Value for parameter "%s" not specified',[param.Name]);
+    end
+    else
+    begin
+      if param.Required then raise ERequiredParameterNotFound.CreateFmt('Required parameter "%s" not found',[param.Name]);
+    end;
+  end;
+end;
+
+function TParameters.ValueType(const aProp: TRttiProperty): TValueType;
+var
+  rType : TRttiType;
+begin
+  rType := aProp.PropertyType;
+  case rType.TypeKind of
+    tkString, tkWideString, tkChar, tkUnicodeString : Result := TValueType.vtString;
+    tkInteger, tkInt64 : Result := TValueType.vtInteger;
+    tkFloat : Result := TValueType.vtFloat;
+    tkEnumeration :
+      begin
+        if TRTTI.GetPropertyValue(Self,aProp.Name).TypeInfo = System.TypeInfo(Boolean) then Result := TValueType.vtBoolean
+          else Result := TValueType.vtEnumeration;
+      end;
+    else raise EParamValueNotSupported.CreateFmt('Parameter "%s": Value not supported',[aProp.Name]);
+  end;
+end;
+
+{$IFDEF CONSOLE}
+procedure TParameters.ShowHelp;
+var
+  version : string;
+  arg : string;
+  value : string;
+  usage : string;
+  commands : string;
+  param : TParam;
+  maxlen : Integer;
+  arglen : Integer;
+begin
+  //show app and version
+  version := GetAppVersionStr;
+  if version.IsEmpty then cout(GetAppName,fColorizeHelp.CommandName)
+    else cout(Format('%s v.%s',[GetAppName,GetAppVersionStr]),fColorizeHelp.CommandName);
+  usage := '';
+  maxlen := 0;
+  commands := '';
+  //show usage
+  arglen := 0;
+  for param in fParams do
+  begin
+    if (param.Name.Length + param.Alias.Length) > maxlen then maxlen := param.Name.Length + param.Alias.Length;
+
+    if param.Required then arg := '<' + param.SwitchChar + param.Name +'%s>'
+      else arg := '[' + param.SwitchChar + param.Name + '%s]';
+
+    if param.IsSwitch then
+    begin
+      arg := Format(arg,['']);
+    end
+    else if param.IsCommand then
+    begin
+      if param.HepValueName.IsEmpty then value := param.Name
+        else value := param.HepValueName;
+      if param.Required then  commands := commands + Format('<%s> ',[value])
+        else commands := commands + Format('[%s] ',[value]);
+      Continue;
+    end
+    else
+    begin
+      if param.ValueIsNextParam then value := ' <value>'
+        else value := param.ValueSeparator + '<value>';
+      if not param.HepValueName.IsEmpty then value := StringReplace(value,'value',param.HepValueName,[rfIgnoreCase,rfReplaceAll]);
+      arg := Format(arg,[value]);
+    end; 
+
+    //fit usage line
+    arglen := arglen + arg.Length;
+    if arglen > 80 then
+    begin
+      usage := usage + #10 + FillStr(' ',8 + (GetAppName.Length));
+      arglen := arg.Length;
+    end;
+        
+    usage := usage + arg + ' ';
+  end;
+    
+  maxlen := maxlen + 5;
+  coutSL('Usage: ',fColorizeHelp.Sections); 
+  coutSL(Format('%s %s%s',[GetAppName,commands,usage]),fColorizeHelp.CommandUsage);
+  cout('',ccWhite);
+  cout('',ccWhite);
+  //show description
+  cout(Description,fColorizeHelp.CommandDescription);
+  cout('',ccWhite);
+  //show arguments
+  cout('Arguments:',fColorizeHelp.Sections);
+  cout('',ccWhite);
+  for param in fParams do
+  begin
+    //if param.IsCommand then Continue;
+    
+    if param.Alias.IsEmpty then
+    begin
+      coutSL(Format('  %s%s%s',[param.SwitchChar,param.Name,FillStr(' ',maxlen - param.Name.Length)]),fColorizeHelp.ArgumentName);
+    end
+    else
+    begin
+      coutSL(Format('  %s%s, -%s%s',[param.SwitchChar,param.Name,param.Alias,FillStr(' ',maxlen - (param.Name.Length + param.Alias.Length + 3))]),fColorizeHelp.ArgumentName);
+    end;
+    coutSL(param.Help,fColorizeHelp.ArgumentDescription);
+    cout('',ccWhite);
+  end;
+  cout('',ccWhite);
+end;
+
+procedure TParameters.GetColors;
+begin
+  fColorizeHelp.CommandName := ccLightCyan;
+  fColorizeHelp.CommandDescription := ccDarkGray;
+  fColorizeHelp.CommandUsage := ccLightGray;
+  fColorizeHelp.fSections := ccWhite;
+  fColorizeHelp.ArgumentName := ccWhite;
+  fColorizeHelp.ArgumentDescription := ccLightGray;
+end;
+{$ENDIF}
+
+function TParameters.GetHelp : TStringList;
+var
+  line : string;
+  version : string;
+  arg : string;
+  value : string;
+  usage : string;
+  commands : string;
+  param : TParam;
+  maxlen : Integer;
+  arglen : Integer;
+begin
+  Result := TStringList.Create;
+  line := '';
+  //show app and version
+  version := GetAppVersionStr;
+  if version.IsEmpty then Result.Add(GetAppName)
+    else Result.Add(Format('%s v.%s',[GetAppName,GetAppVersionStr]));
+  usage := '';
+  maxlen := 0;
+  commands := '';
+  //show usage
+  arglen := 0;
+  for param in fParams do
+  begin
+    if (param.Name.Length + param.Alias.Length) > maxlen then maxlen := param.Name.Length + param.Alias.Length;
+
+    if param.Required then arg := '<' + param.SwitchChar + param.Name +'%s>'
+      else arg := '[' + param.SwitchChar + param.Name + '%s]';
+
+    if param.IsSwitch then
+    begin
+      arg := Format(arg,['']);
+    end
+    else if param.IsCommand then
+    begin
+      if param.HepValueName.IsEmpty then value := param.Name
+        else value := param.HepValueName;
+      if param.Required then  commands := commands + Format('<%s> ',[value])
+        else commands := commands + Format('[%s] ',[value]);
+      Continue;
+    end
+    else
+    begin
+      if param.ValueIsNextParam then value := ' <value>'
+        else value := param.ValueSeparator + '<value>';
+      if not param.HepValueName.IsEmpty then value := StringReplace(value,'value',param.HepValueName,[rfIgnoreCase,rfReplaceAll]);
+      arg := Format(arg,[value]);
+    end;
+
+    //fit usage line
+    arglen := arglen + arg.Length;
+    if arglen > 80 then
+    begin
+      usage := usage + #10 + FillStr(' ',8 + (GetAppName.Length));
+      arglen := arg.Length;
+    end;
+
+    usage := usage + arg + ' ';
+  end;
+
+  maxlen := maxlen + 5;
+  Result.Add(Format('Usage: %s %s%s',[GetAppName,commands,usage]));
+  Result.Add('');
+  Result.Add('');
+  //show description
+  Result.Add(Description);
+  Result.Add('');
+  //show arguments
+  Result.Add('Arguments:');
+  Result.Add('');
+  for param in fParams do
+  begin
+    //if param.IsCommand then Continue;
+    line := '';
+    if param.Alias.IsEmpty then
+    begin
+      line := line + Format('  %s%s%s',[param.SwitchChar,param.Name,FillStr(' ',maxlen - param.Name.Length)]);
+    end
+    else
+    begin
+      line := line + Format('  %s%s, -%s%s',[param.SwitchChar,param.Name,param.Alias,FillStr(' ',maxlen - (param.Name.Length + param.Alias.Length + 3))]);
+    end;
+    line := line + param.Help;
+    Result.Add(line);
+    Result.Add('');
+  end;
+end;
+
+{ CommandDescription }
+
+constructor CommandDescription.Create(const aDescription: string);
+begin
+  fDescription := aDescription;
+end;
+
+{ ParamName }
+
+constructor ParamName.Create(const aName: string; const aAlias : string = '');
+begin
+  fName := aName;
+  fAlias := aAlias;
+end;
+
+{ ParamHelp }
+
+constructor ParamHelp.Create(const aHelp : string; const aValueName : string = '');
+begin
+  fHelp := aHelp;
+  if not aValueName.IsEmpty then fValueName := aValueName
+    else fValueName := 'value';
+end;
+
+{ TParameters.TParam }
+
+constructor TParameters.TParam.Create;
+begin
+  IsPresent := False;
+  fSwitchChar := '--';
+  fValueSeparator := '=';
+  fPrecisePosition := 0;
+end;
+
+function TParameters.TParam.IsCommand: Boolean;
+begin
+  Result := fPrecisePosition > 0;
+end;
+
+function TParameters.TParam.IsSwitch: Boolean;
+begin
+  Result := fParamType = TValueType.vtBoolean;
+end;
+
+{ ParamSwitchChar }
+
+constructor ParamSwitchChar.Create(const aSwitchChar: string);
+begin
+  fSwithChar := aSwitchChar;
+end;
+
+{ ParamValueSeparator }
+
+constructor ParamValueSeparator.Create(const aValueSeparator: string);
+begin
+  fValueSeparator := aValueSeparator;
+end;
+
+{ ParamCommand }
+
+constructor ParamCommand.Create(aPosition: Integer);
+begin
+  fPosition := aPosition;
+end;
+
+end.

+ 3 - 3
QuickLib.inc

@@ -128,7 +128,7 @@
       {$define DELPHIRX103_UP}
 	    {$define DELPHIRIO_UP}
     {$ifend}
-    {$if CompilerVersion >= 33.0} //Delphi RX10.4 Sydney
+    {$if CompilerVersion >= 34.0} //Delphi RX10.4 Sydney
       {$define DELPHIRX104_UP}
 	    {$define DELPHISYDNEY_UP}
       {$if defined(ANDROID) OR defined(LINUX) OR defined(IOS)}
@@ -161,8 +161,8 @@
 
 //Debug library
 {$IFDEF DEBUG}
-  {.$DEFINE DEBUG_SERIALIZER}
-  {.$DEFINE DEBUG_HTTPSERVER}
+  {$DEFINE DEBUG_SERIALIZER}
+  {$DEFINE DEBUG_HTTPSERVER}
 {$ENDIF}
 
 

+ 117 - 0
README.md

@@ -22,6 +22,7 @@ Small delphi/Firemonkey(Windows, Linux, Android, OSX & IOS) and fpc(Windows & Li
 * **Caching:**: Cache string or objects to retrieve fast later.
 * **Templating:** Simple string templating with dictionaries.
 * **Debuging:** Utils to debug your code.
+* **Parameters:** Work with commandline parameters.
 
 **Main units description:**
 
@@ -56,10 +57,12 @@ Small delphi/Firemonkey(Windows, Linux, Android, OSX & IOS) and fpc(Windows & Li
 * **Quick.Pooling:** Creation of object pool to avoid external resource consum exhausts and overheads.
 * **Quick.Template:** String template replacing with dictionary or delegate.
 * **Quick.Debug.Utils:** Simple debugging and code benchmark utils.
+* **Quick.Parameters:** Work with commandline parameters like a class.
 
 
 **Updates:**
 
+* NEW: QuickParameters to work with commandline arguments like a class.
 * NEW: HttpServer custom and dynamic error pages.
 * NEW: Debug utils
 * NEW: String Template
@@ -1221,4 +1224,118 @@ end;
 //29-06-2020 22:58:47.810  [EXIT] >> TCalculator.Mult in 2,00s
 ```
 
+**Quick.Parameters:**
+--
+Working with commandline parameters will be easy using commandline extension.
+Define a class inherited from TParameters or TServiceParameters (if working with QuickAppServices) with your possible arguments as published properties:
+```delphi
+uses
+  Quick.Parameters;
+type
+  TCommand = (Copy, Move, Remove);
+  TMyMode = (mdAdd, mdSelect, mdRemove);
+
+  [CommandDescription('Simple console application example with Quick.Parameters')]
+  TMyParameter = class(TParameters)
+  private
+    fCommand : TCommand;
+    fHost : string;
+    fPort : Integer;
+    fRetries : Integer;
+    fUseTCP : Boolean;
+    fConfigFile: string;
+    fSilent: Boolean;
+    fMyMode: TMyMode;
+    fLogErrorsConsole: Boolean;
+    fLogErrors: Boolean;
+    fShowReport: Boolean;
+  published
+    [ParamCommand(1)]
+    [ParamRequired]
+    [ParamHelp('Command action.','command-action')]
+    property Command : TCommand read fCommand write fCommand;
+
+    [ParamName('HostName'),ParamRequired]
+    [ParamHelp('Define host to connect.','host')]
+    property Host : string read fHost write fHost;
+
+    [ParamName('Port','p')]
+    [ParamValueIsNextParam]
+    [ParamHelp('Define Port to connect (default 80)','port')]
+    property Port : Integer read fPort write fPort;
+
+    [ParamHelp('Number of max retries.')]
+    property Retries : Integer read fRetries write fRetries;
+
+    [ParamHelp('Path to config.','path')]
+    [ParamName('Config-file')]
+    property ConfigFile : String read fConfigFile write fConfigFile;
+
+    [ParamHelp('Silent mode.')]
+    property Silent : Boolean read fSilent write fSilent;
+
+    [ParamHelp('Modes (mdAdd, mdSelect, mdRemove)')]
+    property Mode : TMyMode read fMyMode write fMyMode;
+  end;
+
+```
+And pass to de commandline extension:
+```delphi
+services.AddCommandline<TArguments>;
+```
+When you call your exe with --help you get documentation. If you need to check for a switch or value, you can do like this:
+```delphi
+if services.Commandline<TArguments>.Port = 0 then ...
+if services.Commandline<TArguments>.Silent then ...
+```
+QuickParameters uses custom attributes to define special parameter conditions:
+
+- **CommandDescription:** Defines text to describe your application in help documentation.
+
+- **ParamCommand(number):** Defines static position into commandline for single parameters.
+
+- **ParamName(name,alias):** Define a diferent name for parameter. Allows to use special characters not allowed for class properties (like file-name or config.file). Optional Alias argument defines an alternative (normally short name) parameter name.
+
+- **ParamHelp(helptext,valuename):** Defines a commandline help text and value name in usage section.
+
+- **ParamSwitchChar(sign):** Defines string or char to indicate switch or parameter. If not defined, a double dash (--) will be used by default.
+
+- **ParamValueSeparator(sign):** Defines string or char to separate parameter name from value (filename=config.json). If not defined, equal sign (=) will be used by default.
+
+- **ParamValueIsNextParam:** Defines a parameter with a value without value separator (filename c:\config.ini)
+
+- **ParamRequired:** Defines a parameter as required. If param not found, an exception will be raised.
+
+QuickParameter automatically checks for value types. If you define a parameter value as Integer, and pass an alfanumeric, an exception will be raised.
+
+Help customization:
+You can define your own color customization with ColorizeHelp. Enabled property will use custom colors, otherwise b/w will be used.
+```delphi
+Parameters.ColorizeHelp.Enabled := True;
+Parameters.ColorizeHelp.CommandName := ccCyan;
+Parameters.ColorizeHelp.CommandUsage := ccBlue;
+```
+When parameters detects help parameter, help documentation will be showed.
+
+Parameters.ShowHelp: Shows help documentation, generated automatically:
+```
+Parameters v.1.0
+Usage: Parameters <command-action> <--HostName=<host>> [--Port <port>] [--Retries=<value>]
+                  [--Config-file=<path>] [--UseTCP] [--Silent] [--Mode=<value>]
+                  [--ShowReport] [--Help]
+
+Simple console application example with Quick.Parameters
+
+Arguments:
+
+    Command                  Command action.
+  --HostName                 Define host to connect.
+  --Port, -p                 Define Port to connect (default 80)
+  --Retries                  Number of max retries.
+  --Config-file              Path to config.
+  --UseTCP                   Use TCP connection if present.
+  --Silent                   Silent mode.
+  --Mode                     Modes (mdAdd, mdSelect, mdRemove)
+  --Help, -h                 Show this documentation
+```
 

+ 102 - 0
samples/delphi/QuickParameters/Parameters.dpr

@@ -0,0 +1,102 @@
+program Parameters;
+
+{$APPTYPE CONSOLE}
+
+{$R *.res}
+
+uses
+  System.SysUtils,
+  Quick.Commons,
+  Quick.Console,
+  Quick.Parameters;
+
+type
+  TCommand = (Copy, Move, Remove);
+  TMyMode = (mdAdd, mdSelect, mdRemove);
+
+  [CommandDescription('Simple console application example with Quick.Parameters')]
+  TMyParameter = class(TParameters)
+  private
+    fCommand : TCommand;
+    fHost : string;
+    fPort : Integer;
+    fRetries : Integer;
+    fUseTCP : Boolean;
+    fConfigFile: string;
+    fSilent: Boolean;
+    fMyMode: TMyMode;
+    fLogErrorsConsole: Boolean;
+    fLogErrors: Boolean;
+    fShowReport: Boolean;
+  published
+    [ParamCommand(1)]
+    [ParamRequired]
+    [ParamHelp('Command action.','command-action')]
+    property Command : TCommand read fCommand write fCommand;
+
+    [ParamName('HostName'),ParamRequired]
+    [ParamHelp('Define host to connect.','host')]
+    property Host : string read fHost write fHost;
+
+    [ParamName('Port','p')]
+    [ParamValueIsNextParam]
+    [ParamHelp('Define Port to connect (default 80)','port')]
+    property Port : Integer read fPort write fPort;
+
+    [ParamHelp('Number of max retries.')]
+    property Retries : Integer read fRetries write fRetries;
+
+    [ParamHelp('Path to config.','path')]
+    [ParamName('Config-file')]
+    property ConfigFile : String read fConfigFile write fConfigFile;
+
+    [ParamHelp('Use TCP connection if present.')]
+    property UseTCP : Boolean read fUseTCP write fUseTCP;
+
+    [ParamHelp('Silent mode.')]
+    property Silent : Boolean read fSilent write fSilent;
+
+    [ParamHelp('Modes (mdAdd, mdSelect, mdRemove)')]
+    property Mode : TMyMode read fMyMode write fMyMode;
+
+    [ParamHelp('Show report on finish.')]
+    property ShowReport : Boolean read fShowReport write fShowReport;
+
+    [ParamHelp('Log errors to file.')]
+    [ParamName('LogErrors-to-file')]
+    property LogErrorsFile : Boolean read fLogErrors write fLogErrors;
+
+    [ParamHelp('Log errors to console.')]
+    [ParamName('LogErrors-to-console')]
+    property LogErrorsConsole : Boolean read fLogErrorsConsole write fLogErrorsConsole;
+  end;
+
+var
+  params : TMyParameter;
+
+begin
+  try
+    params := TMyParameter.Create;
+    if params.Help then Exit;
+      
+    coutFmt('Command = %d',[Integer(params.Command)],etInfo);
+    coutFmt('Host = %s',[params.Host],etInfo);
+    coutFmt('Port = %d',[params.Port],etInfo);
+    coutFmt('Retries = %d',[params.Retries],etInfo);
+    coutFmt('Config-File = %s',[params.ConfigFile],etInfo);
+    coutFmt('Mode = %d',[Integer(params.Mode)],etInfo);
+    if params.UseTCP then cout('Use tcp detected',ccYellow);
+    if params.Silent then cout('Silent mode detected',ccYellow);
+    if params.ShowReport then cout('ShowReport detected',ccYellow);
+    if params.LogErrorsFile then cout('LogErrorsFile detected',ccYellow);
+    if params.LogErrorsConsole then cout('LogErrorsConsole detected',ccYellow);
+    cout('Press <ENTER> to Exit',ccYellow);
+    ConsoleWaitForEnterKey;
+  except
+    on E: Exception do
+    begin
+      cout('%s : %s',[E.ClassName,e.Message],etError);
+      cout('Type "Parameters --help" to get documentation',ccYellow);
+    end;
+  end;
+end.

+ 1126 - 0
samples/delphi/QuickParameters/Parameters.dproj

@@ -0,0 +1,1126 @@
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+    <PropertyGroup>
+        <ProjectGuid>{720C5968-A995-48C1-B4EC-2DC16A29D2EF}</ProjectGuid>
+        <ProjectVersion>19.0</ProjectVersion>
+        <FrameworkType>None</FrameworkType>
+        <MainSource>Parameters.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)'=='Android64' and '$(Base)'=='true') or '$(Base_Android64)'!=''">
+        <Base_Android64>true</Base_Android64>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='iOSDevice64' and '$(Base)'=='true') or '$(Base_iOSDevice64)'!=''">
+        <Base_iOSDevice64>true</Base_iOSDevice64>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='iOSSimulator' and '$(Base)'=='true') or '$(Base_iOSSimulator)'!=''">
+        <Base_iOSSimulator>true</Base_iOSSimulator>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='OSX64' and '$(Base)'=='true') or '$(Base_OSX64)'!=''">
+        <Base_OSX64>true</Base_OSX64>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''">
+        <Base_Win32>true</Base_Win32>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Base)'=='true') or '$(Base_Win64)'!=''">
+        <Base_Win64>true</Base_Win64>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_1)'!=''">
+        <Cfg_1>true</Cfg_1>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_1)'=='true') or '$(Cfg_1_Win32)'!=''">
+        <Cfg_1_Win32>true</Cfg_1_Win32>
+        <CfgParent>Cfg_1</CfgParent>
+        <Cfg_1>true</Cfg_1>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_2)'!=''">
+        <Cfg_2>true</Cfg_2>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base)'!=''">
+        <DCC_DcuOutput>.\$(Platform)\$(Config)</DCC_DcuOutput>
+        <DCC_ExeOutput>.\$(Platform)\$(Config)</DCC_ExeOutput>
+        <DCC_E>false</DCC_E>
+        <DCC_N>false</DCC_N>
+        <DCC_S>false</DCC_S>
+        <DCC_F>false</DCC_F>
+        <DCC_K>false</DCC_K>
+        <DCC_Namespace>System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace)</DCC_Namespace>
+        <SanitizedProjectName>Parameters</SanitizedProjectName>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Android)'!=''">
+        <DCC_UsePackage>DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;FMXComponents;tethering;bindcompfmx;FmxTeeUI;FireDACIBDriver;fmx;dbexpress;IndyCore;dsnap;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;inet;bindcompdbx;IndyIPCommon;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;ibmonitor;FMXTee;soaprtl;DbxCommonDriver;ibxpress;xmlrtl;soapmidas;ibxbindings;rtl;DbxClientDriver;CustomIPTransport;bindcomp;CoolTrayIcon_D210_XE7;IndyIPClient;dbxcds;Gauge3D;dsnapxml;dbrtl;IndyProtocols;$(DCC_UsePackage)</DCC_UsePackage>
+        <Android_LauncherIcon36>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_36x36.png</Android_LauncherIcon36>
+        <Android_LauncherIcon48>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_48x48.png</Android_LauncherIcon48>
+        <Android_LauncherIcon72>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_72x72.png</Android_LauncherIcon72>
+        <Android_LauncherIcon96>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_96x96.png</Android_LauncherIcon96>
+        <Android_LauncherIcon144>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_144x144.png</Android_LauncherIcon144>
+        <Android_SplashImage426>$(BDS)\bin\Artwork\Android\FM_SplashImage_426x320.png</Android_SplashImage426>
+        <Android_SplashImage470>$(BDS)\bin\Artwork\Android\FM_SplashImage_470x320.png</Android_SplashImage470>
+        <Android_SplashImage640>$(BDS)\bin\Artwork\Android\FM_SplashImage_640x480.png</Android_SplashImage640>
+        <Android_SplashImage960>$(BDS)\bin\Artwork\Android\FM_SplashImage_960x720.png</Android_SplashImage960>
+        <Android_NotificationIcon24>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_24x24.png</Android_NotificationIcon24>
+        <Android_NotificationIcon36>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_36x36.png</Android_NotificationIcon36>
+        <Android_NotificationIcon48>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_48x48.png</Android_NotificationIcon48>
+        <Android_NotificationIcon72>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_72x72.png</Android_NotificationIcon72>
+        <Android_NotificationIcon96>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_96x96.png</Android_NotificationIcon96>
+        <EnabledSysJars>android-support-v4.dex.jar;cloud-messaging.dex.jar;com-google-android-gms.play-services-ads-base.17.2.0.dex.jar;com-google-android-gms.play-services-ads-identifier.16.0.0.dex.jar;com-google-android-gms.play-services-ads-lite.17.2.0.dex.jar;com-google-android-gms.play-services-ads.17.2.0.dex.jar;com-google-android-gms.play-services-analytics-impl.16.0.8.dex.jar;com-google-android-gms.play-services-analytics.16.0.8.dex.jar;com-google-android-gms.play-services-base.16.0.1.dex.jar;com-google-android-gms.play-services-basement.16.2.0.dex.jar;com-google-android-gms.play-services-gass.17.2.0.dex.jar;com-google-android-gms.play-services-identity.16.0.0.dex.jar;com-google-android-gms.play-services-maps.16.1.0.dex.jar;com-google-android-gms.play-services-measurement-base.16.4.0.dex.jar;com-google-android-gms.play-services-measurement-sdk-api.16.4.0.dex.jar;com-google-android-gms.play-services-stats.16.0.1.dex.jar;com-google-android-gms.play-services-tagmanager-v4-impl.16.0.8.dex.jar;com-google-android-gms.play-services-tasks.16.0.1.dex.jar;com-google-android-gms.play-services-wallet.16.0.1.dex.jar;com-google-firebase.firebase-analytics.16.4.0.dex.jar;com-google-firebase.firebase-common.16.1.0.dex.jar;com-google-firebase.firebase-iid-interop.16.0.1.dex.jar;com-google-firebase.firebase-iid.17.1.1.dex.jar;com-google-firebase.firebase-measurement-connector.17.0.1.dex.jar;com-google-firebase.firebase-messaging.17.5.0.dex.jar;fmx.dex.jar;google-play-billing.dex.jar;google-play-licensing.dex.jar</EnabledSysJars>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Android64)'!=''">
+        <DCC_UsePackage>DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;tethering;bindcompfmx;FmxTeeUI;FireDACIBDriver;fmx;dbexpress;IndyCore;dsnap;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;inet;bindcompdbx;IndyIPCommon;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;ibmonitor;FMXTee;soaprtl;DbxCommonDriver;ibxpress;xmlrtl;soapmidas;ibxbindings;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;dbrtl;IndyProtocols;$(DCC_UsePackage)</DCC_UsePackage>
+        <Android_LauncherIcon36>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_36x36.png</Android_LauncherIcon36>
+        <Android_LauncherIcon48>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_48x48.png</Android_LauncherIcon48>
+        <Android_LauncherIcon72>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_72x72.png</Android_LauncherIcon72>
+        <Android_LauncherIcon96>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_96x96.png</Android_LauncherIcon96>
+        <Android_LauncherIcon144>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_144x144.png</Android_LauncherIcon144>
+        <Android_SplashImage426>$(BDS)\bin\Artwork\Android\FM_SplashImage_426x320.png</Android_SplashImage426>
+        <Android_SplashImage470>$(BDS)\bin\Artwork\Android\FM_SplashImage_470x320.png</Android_SplashImage470>
+        <Android_SplashImage640>$(BDS)\bin\Artwork\Android\FM_SplashImage_640x480.png</Android_SplashImage640>
+        <Android_SplashImage960>$(BDS)\bin\Artwork\Android\FM_SplashImage_960x720.png</Android_SplashImage960>
+        <Android_NotificationIcon24>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_24x24.png</Android_NotificationIcon24>
+        <Android_NotificationIcon36>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_36x36.png</Android_NotificationIcon36>
+        <Android_NotificationIcon48>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_48x48.png</Android_NotificationIcon48>
+        <Android_NotificationIcon72>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_72x72.png</Android_NotificationIcon72>
+        <Android_NotificationIcon96>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_96x96.png</Android_NotificationIcon96>
+        <EnabledSysJars>android-support-v4.dex.jar;cloud-messaging.dex.jar;com-google-android-gms.play-services-ads-base.17.2.0.dex.jar;com-google-android-gms.play-services-ads-identifier.16.0.0.dex.jar;com-google-android-gms.play-services-ads-lite.17.2.0.dex.jar;com-google-android-gms.play-services-ads.17.2.0.dex.jar;com-google-android-gms.play-services-analytics-impl.16.0.8.dex.jar;com-google-android-gms.play-services-analytics.16.0.8.dex.jar;com-google-android-gms.play-services-base.16.0.1.dex.jar;com-google-android-gms.play-services-basement.16.2.0.dex.jar;com-google-android-gms.play-services-gass.17.2.0.dex.jar;com-google-android-gms.play-services-identity.16.0.0.dex.jar;com-google-android-gms.play-services-maps.16.1.0.dex.jar;com-google-android-gms.play-services-measurement-base.16.4.0.dex.jar;com-google-android-gms.play-services-measurement-sdk-api.16.4.0.dex.jar;com-google-android-gms.play-services-stats.16.0.1.dex.jar;com-google-android-gms.play-services-tagmanager-v4-impl.16.0.8.dex.jar;com-google-android-gms.play-services-tasks.16.0.1.dex.jar;com-google-android-gms.play-services-wallet.16.0.1.dex.jar;com-google-firebase.firebase-analytics.16.4.0.dex.jar;com-google-firebase.firebase-common.16.1.0.dex.jar;com-google-firebase.firebase-iid-interop.16.0.1.dex.jar;com-google-firebase.firebase-iid.17.1.1.dex.jar;com-google-firebase.firebase-measurement-connector.17.0.1.dex.jar;com-google-firebase.firebase-messaging.17.5.0.dex.jar;fmx.dex.jar;google-play-billing.dex.jar;google-play-licensing.dex.jar</EnabledSysJars>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_iOSDevice64)'!=''">
+        <DCC_UsePackage>DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;tethering;bindcompfmx;FmxTeeUI;FireDACIBDriver;fmx;dbexpress;IndyCore;dsnap;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;inet;bindcompdbx;IndyIPCommon;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;ibmonitor;FMXTee;soaprtl;DbxCommonDriver;ibxpress;xmlrtl;soapmidas;ibxbindings;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;dbrtl;IndyProtocols;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_iOSSimulator)'!=''">
+        <DCC_UsePackage>DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;tethering;bindcompfmx;FmxTeeUI;FireDACIBDriver;fmx;dbexpress;IndyCore;dsnap;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;inet;bindcompdbx;IndyIPCommon;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;ibmonitor;FMXTee;soaprtl;DbxCommonDriver;ibxpress;xmlrtl;soapmidas;ibxbindings;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;dbrtl;IndyProtocols;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_OSX64)'!=''">
+        <DCC_UsePackage>DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;tethering;bindcompfmx;inetdb;FmxTeeUI;FireDACIBDriver;fmx;fmxdae;dbexpress;IndyCore;dsnap;FireDACCommon;RESTBackendComponents;soapserver;bindengine;DBXMySQLDriver;CloudService;FireDACMySQLDriver;FireDACCommonODBC;FireDACCommonDriver;inet;bindcompdbx;IndyIPCommon;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;FireDACPgDriver;ibmonitor;FMXTee;soaprtl;DbxCommonDriver;ibxpress;xmlrtl;soapmidas;ibxbindings;fmxobj;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;dbrtl;inetdbxpress;IndyProtocols;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
+        <DCC_ConsoleTarget>true</DCC_ConsoleTarget>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Win32)'!=''">
+        <DCC_UsePackage>DBXSqliteDriver;RESTComponents;UbuntuProgressPackage;DBXInterBaseDriver;vclactnband;vclFireDAC;FMXComponents;tethering;svnui;FireDACADSDriver;tmswizdXE12;vcwdedXE12;vcltouch;vcldb;bindcompfmx;svn;Spring.Data;inetdb;CoreMvcExpert;FmxTeeUI;FireDACIBDriver;fmx;fmxdae;vclib;dbexpress;IndyCore;vclx;dsnap;FireDACCommon;RESTBackendComponents;VCLRESTComponents;soapserver;JclDeveloperTools;vclie;bindengine;DBXMySQLDriver;CloudService;FireDACMySQLDriver;FireDACCommonODBC;FireDACCommonDriver;FMXComponentEd;inet;bindcompdbx;IndyIPCommon;GR32_D;vcl;IndyIPServer;PngComponents;IndySystem;dsnapcon;tmsxlsdXE12;FireDACMSAccDriver;fmxFireDAC;vclimg;TeeDB;FireDAC;Jcl;tmsdXE12;FireDACSqliteDriver;FireDACPgDriver;ibmonitor;FMXTee;soaprtl;DbxCommonDriver;ibxpress;Tee;xmlrtl;soapmidas;ibxbindings;fmxobj;vclwinx;GR32_R;rtl;DbxClientDriver;QuickVCL;tmsexdXE12;CustomIPTransport;vcldsnap;vcwdXE12;bindcomp;appanalytics;CoolTrayIcon_D210_XE7;IndyIPClient;bindcompvcl;TeeUI;dbxcds;VclSmp;TMSFMXPackPkgDXE12;adortl;JclVcl;Gauge3D;dsnapxml;dbrtl;inetdbxpress;IndyProtocols;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;DBXInterBaseDriver;vclactnband;vclFireDAC;tethering;FireDACADSDriver;vcltouch;vcldb;bindcompfmx;Spring.Data;inetdb;FmxTeeUI;FireDACIBDriver;fmx;fmxdae;vclib;dbexpress;IndyCore;vclx;dsnap;FireDACCommon;RESTBackendComponents;VCLRESTComponents;soapserver;vclie;bindengine;DBXMySQLDriver;CloudService;FireDACMySQLDriver;FireDACCommonODBC;FireDACCommonDriver;inet;bindcompdbx;IndyIPCommon;vcl;IndyIPServer;PngComponents;IndySystem;dsnapcon;tmsxlsdXE12;FireDACMSAccDriver;fmxFireDAC;vclimg;TeeDB;FireDAC;tmsdXE12;FireDACSqliteDriver;FireDACPgDriver;ibmonitor;FMXTee;soaprtl;DbxCommonDriver;ibxpress;Tee;xmlrtl;soapmidas;ibxbindings;fmxobj;vclwinx;GR32_R;rtl;DbxClientDriver;QuickVCL;tmsexdXE12;CustomIPTransport;vcldsnap;vcwdXE12;bindcomp;appanalytics;IndyIPClient;bindcompvcl;TeeUI;dbxcds;VclSmp;adortl;dsnapxml;dbrtl;inetdbxpress;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>
+        <Debugger_RunParams>copy -p 8080 --hostname=127.0.0.1 --usetcp --Mode=mdSelect --Config-file=&quot;C:\My program\data.conf&quot; --Retries=10 --Silent</Debugger_RunParams>
+        <VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
+        <VerInfo_Locale>1033</VerInfo_Locale>
+        <Manifest_File>(None)</Manifest_File>
+    </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">Parameters.dpr</Source>
+                </Source>
+                <Excluded_Packages>
+                    <Excluded_Packages Name="$(BDSBIN)\bcboffice2k260.bpl">Embarcadero C++Builder Office 2000 Servers Package</Excluded_Packages>
+                    <Excluded_Packages Name="$(BDSBIN)\bcbofficexp260.bpl">Embarcadero C++Builder Office XP Servers Package</Excluded_Packages>
+                    <Excluded_Packages Name="$(BDSBIN)\dcloffice2k260.bpl">Microsoft Office 2000 Sample Automation Server Wrapper Components</Excluded_Packages>
+                    <Excluded_Packages Name="$(BDSBIN)\dclofficexp260.bpl">Microsoft Office XP Sample Automation Server Wrapper Components</Excluded_Packages>
+                </Excluded_Packages>
+            </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\Parameters.exe" Configuration="Debug" Class="ProjectOutput">
+                    <Platform Name="Win32">
+                        <RemoteName>Parameters.exe</RemoteName>
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployClass Name="AdditionalDebugSymbols">
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidClassesDexFile">
+                    <Platform Name="Android">
+                        <RemoteDir>classes</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>classes</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidFileProvider">
+                    <Platform Name="Android">
+                        <RemoteDir>res\xml</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\xml</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidGDBServer">
+                    <Platform Name="Android">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidLibnativeArmeabiFile">
+                    <Platform Name="Android">
+                        <RemoteDir>library\lib\armeabi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\armeabi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidLibnativeArmeabiv7aFile">
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidLibnativeMipsFile">
+                    <Platform Name="Android">
+                        <RemoteDir>library\lib\mips</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\mips</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidServiceOutput">
+                    <Platform Name="Android">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\arm64-v8a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidServiceOutput_Android32">
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidSplashImageDef">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidSplashStyles">
+                    <Platform Name="Android">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidSplashStylesV21">
+                    <Platform Name="Android">
+                        <RemoteDir>res\values-v21</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\values-v21</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_Colors">
+                    <Platform Name="Android">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_DefaultAppIcon">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon144">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon36">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-ldpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-ldpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon48">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-mdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-mdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon72">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-hdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-hdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon96">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_NotificationIcon24">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-mdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-mdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_NotificationIcon36">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-hdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-hdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_NotificationIcon48">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_NotificationIcon72">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_NotificationIcon96">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xxxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xxxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_SplashImage426">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-small</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-small</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_SplashImage470">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-normal</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-normal</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_SplashImage640">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-large</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-large</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_SplashImage960">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xlarge</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xlarge</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_Strings">
+                    <Platform Name="Android">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="DebugSymbols">
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="DependencyFramework">
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.framework</Extensions>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.framework</Extensions>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="DependencyModule">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                        <Extensions>.dll;.bpl</Extensions>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Required="true" Name="DependencyPackage">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                        <Extensions>.bpl</Extensions>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="File">
+                    <Platform Name="Android">
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice32">
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\Resources\StartUp\</RemoteDir>
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\Resources\StartUp\</RemoteDir>
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="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_Launch2x">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_Launch768x1024">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_LaunchDark2x">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="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_Launch2x">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch320">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch3x">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch640">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </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="iPhone_LaunchDark2x">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_LaunchDark3x">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectAndroidManifest">
+                    <Platform Name="Android">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectiOSDeviceDebug">
+                    <Platform Name="iOSDevice32">
+                        <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="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="ProjectiOSLaunchScreen">
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen</RemoteDir>
+                        <Operation>64</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <RemoteDir>..\$(PROJECTNAME).launchscreen</RemoteDir>
+                        <Operation>64</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectiOSResource">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectOSXDebug">
+                    <Platform Name="OSX64">
+                        <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectOSXEntitlements">
+                    <Platform Name="OSX32">
+                        <RemoteDir>..\</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>..\</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectOSXInfoPList">
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectOSXResource">
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\Resources</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\Resources</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Required="true" Name="ProjectOutput">
+                    <Platform Name="Android">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\arm64-v8a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Linux64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX64">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectOutput_Android32">
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectUWPManifest">
+                    <Platform Name="Win32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win64">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="UWP_DelphiLogo150">
+                    <Platform Name="Win32">
+                        <RemoteDir>Assets</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win64">
+                        <RemoteDir>Assets</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="UWP_DelphiLogo44">
+                    <Platform Name="Win32">
+                        <RemoteDir>Assets</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win64">
+                        <RemoteDir>Assets</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <ProjectRoot Platform="iOSDevice64" Name="$(PROJECTNAME).app"/>
+                <ProjectRoot Platform="Win64" Name="$(PROJECTNAME)"/>
+                <ProjectRoot Platform="iOSDevice32" Name="$(PROJECTNAME).app"/>
+                <ProjectRoot Platform="Linux64" Name="$(PROJECTNAME)"/>
+                <ProjectRoot Platform="Win32" Name="$(PROJECTNAME)"/>
+                <ProjectRoot Platform="OSX32" Name="$(PROJECTNAME).app"/>
+                <ProjectRoot Platform="Android" Name="$(PROJECTNAME)"/>
+                <ProjectRoot Platform="OSX64" Name="$(PROJECTNAME).app"/>
+                <ProjectRoot Platform="iOSSimulator" Name="$(PROJECTNAME).app"/>
+                <ProjectRoot Platform="Android64" Name="$(PROJECTNAME)"/>
+            </Deployment>
+            <Platforms>
+                <Platform value="Android">False</Platform>
+                <Platform value="Android64">False</Platform>
+                <Platform value="iOSDevice64">False</Platform>
+                <Platform value="iOSSimulator">False</Platform>
+                <Platform value="OSX64">False</Platform>
+                <Platform value="Win32">True</Platform>
+                <Platform value="Win64">False</Platform>
+            </Platforms>
+        </BorlandProject>
+        <ProjectFileVersion>12</ProjectFileVersion>
+    </ProjectExtensions>
+    <Import Project="$(BDS)\Bin\CodeGear.Delphi.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')"/>
+    <Import Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj" Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')"/>
+    <Import Project="$(MSBuildProjectName).deployproj" Condition="Exists('$(MSBuildProjectName).deployproj')"/>
+</Project>