Browse Source

Merge branch 'develop'

Exilon 5 years ago
parent
commit
23ced22362

+ 8 - 5
Quick.Json.Serializer.pas

@@ -7,7 +7,7 @@
   Author      : Kike Pérez
   Version     : 1.10
   Created     : 21/05/2018
-  Modified    : 10/11/2019
+  Modified    : 16/12/2019
 
   This file is part of QuickLib: https://github.com/exilon/QuickLib
 
@@ -910,11 +910,14 @@ begin
   end
   else
   begin
-    for i := 0 to aJson.Count - 1 do
+    if aJson <> nil then
     begin
-      Result := aJson.Pairs[I];
-      if Result.JsonValue = nil then Exit(nil);
-      if CompareText(Result.JsonString{$IFNDEF FPC}.Value{$ENDIF},aName) = 0 then Exit;
+      for i := 0 to aJson.Count - 1 do
+      begin
+        Result := aJson.Pairs[I];
+        if Result.JsonValue = nil then Exit(nil);
+        if CompareText(Result.JsonString{$IFNDEF FPC}.Value{$ENDIF},aName) = 0 then Exit;
+      end;
     end;
   end;
   Result := nil;

+ 71 - 22
Quick.Options.pas

@@ -7,7 +7,7 @@
   Author      : Kike Pérez
   Version     : 1.0
   Created     : 18/10/2019
-  Modified    : 28/11/2019
+  Modified    : 16/12/2019
 
   This file is part of QuickLib: https://github.com/exilon/QuickLib
 
@@ -90,14 +90,16 @@ type
   TOptions = class(TInterfacedObject,IOptionsValidator)
   private
     fName : string;
-    procedure ValidateRequired(aProperty : TRttiProperty);
-    procedure ValidateStringLength(aProperty: TRttiProperty; aValidation : StringLength);
-    procedure ValidateRange(aProperty : TRttiProperty; aValidation : Range);
+    procedure ValidateRequired(const aInstance : TObject; aProperty: TRttiProperty);
+    procedure ValidateStringLength(const aInstance : TObject; aProperty: TRttiProperty; aValidation : StringLength);
+    procedure ValidateRange(const aInstance : TObject; aProperty: TRttiProperty; aValidation : Range);
     procedure DoValidateOptions; virtual;
+    procedure ValidateObject(aObj : TObject);
+    procedure ValidateArray(aValue : TValue);
   public
     constructor Create;
     property Name : string read fName write fName;
-    procedure DefaultValues; virtual; abstract;
+    procedure DefaultValues; virtual;
     function ConfigureOptions<T : TOptions>(aOptionsFunc : TConfigureOptionsProc<T>) : IOptionsValidator;
     procedure ValidateOptions;
   end;
@@ -122,7 +124,7 @@ type
   ['{A593C8BB-53CF-4AA4-9641-BF974E45CBD1}']
     function AddSection(aOption : TOptionsClass; const aOptionsName : string = '') : TOptions;
     function GetOptions(aOptionClass : TOptionsClass): TOptions;
-    function GetSection(aOptionsSection : TOptionsClass; aOptions : TOptions) : Boolean; overload;
+    function GetSection(aOptionsSection : TOptionsClass; var vOptions : TOptions) : Boolean; overload;
   end;
 
   TSectionList = TObjectList<TOptions>;
@@ -167,7 +169,7 @@ type
     procedure SetReloadIfFileChanged(const Value: Boolean);
     function GetOptions(aOptionClass : TOptionsClass): TOptions; overload;
     function GetOptions(aIndex : Integer) : TOptions; overload;
-    function GetSection(aOptionsSection : TOptionsClass; aOptions : TOptions) : Boolean; overload;
+    function GetSection(aOptionsSection : TOptionsClass; var vOptions : TOptions) : Boolean; overload;
   public
     constructor Create(const aFilename : string; aOptionsSerializer : IOptionsSerializer; aReloadIfFileChanged : Boolean = False);
     destructor Destroy; override;
@@ -282,7 +284,7 @@ begin
   Result := fSections[aIndex];
 end;
 
-function TOptionsContainer.GetSection(aOptionsSection: TOptionsClass; aOptions: TOptions): Boolean;
+function TOptionsContainer.GetSection(aOptionsSection: TOptionsClass; var vOptions: TOptions): Boolean;
 var
   option : TOptions;
 begin
@@ -291,7 +293,7 @@ begin
   begin
     if option is TOptionsClass then
     begin
-      aOptions := option as TOptionsClass;
+      vOptions := option as TOptionsClass;
       Exit;
     end;
   end;
@@ -396,16 +398,27 @@ begin
   fName := '';
 end;
 
+procedure TOptions.DefaultValues;
+begin
+  //nothing
+end;
+
 procedure TOptions.DoValidateOptions;
+begin
+  ValidateObject(Self);
+end;
+
+procedure TOptions.ValidateObject(aObj : TObject);
 var
   ctx : TRttiContext;
   rtype : TRttiType;
   rprop : TRttiProperty;
   attrib : TCustomAttribute;
+  rvalue : TValue;
 begin
   ctx := TRttiContext.Create;
   try
-    rtype := ctx.GetType(Self.ClassInfo);
+    rtype := ctx.GetType(aObj.ClassInfo);
     for rprop in rtype.GetProperties do
     begin
       //check only published properties
@@ -414,9 +427,45 @@ begin
         //check validation option attributes
         for attrib in rprop.GetAttributes do
         begin
-          if attrib is Required  then ValidateRequired(rprop)
-          else if attrib is StringLength then ValidateStringLength(rprop,StringLength(attrib))
-          else if attrib is Range then ValidateRange(rprop,Range(attrib));
+          if attrib is Required  then ValidateRequired(aObj,rprop)
+          else if attrib is StringLength then ValidateStringLength(aObj,rprop,StringLength(attrib))
+          else if attrib is Range then ValidateRange(aObj,rprop,Range(attrib));
+        end;
+        rvalue := rprop.GetValue(aObj);
+        if not rvalue.IsEmpty then
+        begin
+          case rvalue.Kind of
+            tkClass : ValidateObject(rvalue.AsObject);
+            tkDynArray : ValidateArray(rvalue);
+          end;
+        end;
+      end;
+    end;
+  finally
+    ctx.Free;
+  end;
+end;
+
+procedure TOptions.ValidateArray(aValue : TValue);
+type
+  PPByte = ^PByte;
+var
+  ctx : TRttiContext;
+  rDynArray : TRttiDynamicArrayType;
+  itvalue : TValue;
+  i : Integer;
+begin
+  ctx := TRttiContext.Create;
+  try
+    rDynArray := ctx.GetType(aValue.TypeInfo) as TRTTIDynamicArrayType;
+    for i := 0 to aValue.GetArrayLength - 1 do
+    begin
+      TValue.Make(PPByte(aValue.GetReferenceToRawData)^ + rDynArray.ElementType.TypeSize * i, rDynArray.ElementType.Handle,itvalue);
+      if not itvalue.IsEmpty then
+      begin
+        case itvalue.Kind of
+          tkClass : ValidateObject(itvalue.AsObject);
+          tkDynArray : ValidateArray(itvalue);
         end;
       end;
     end;
@@ -437,19 +486,19 @@ begin
   end;
 end;
 
-procedure TOptions.ValidateRange(aProperty: TRttiProperty; aValidation : Range);
+procedure TOptions.ValidateRange(const aInstance : TObject; aProperty: TRttiProperty; aValidation : Range);
 var
   value : TValue;
   msg : string;
 begin
-  value := aProperty.GetValue(Self);
+  value := aProperty.GetValue(aInstance);
   if not value.IsEmpty then
   begin
     if value.Kind = tkFloat then
     begin
       if (value.AsExtended < aValidation.Min) or (value.AsExtended > aValidation.Max) then
       begin
-        if aValidation.ErrorMsg.IsEmpty then msg := Format('Option "%s.%s" exceeds predefined range (%2f - %2f)',[Self.Name,aProperty.Name,aValidation.Min,aValidation.Max])
+        if aValidation.ErrorMsg.IsEmpty then msg := Format('Option %s "%s.%s" exceeds predefined range (%2f - %2f)',[Self.Name,aInstance.ClassName,aProperty.Name,aValidation.Min,aValidation.Max])
           else msg := aValidation.ErrorMsg;
         raise EOptionValidationError.Create(msg);
       end;
@@ -458,7 +507,7 @@ begin
     begin
       if (value.AsInt64 < aValidation.Min) or (value.AsInt64 > aValidation.Max) then
       begin
-        if aValidation.ErrorMsg.IsEmpty then msg := Format('Option "%s.%s" exceeds predefined range (%d - %d)',[Self.Name,aProperty.Name,Round(aValidation.Min),Round(aValidation.Max)])
+        if aValidation.ErrorMsg.IsEmpty then msg := Format('Option %s "%s.%s" exceeds predefined range (%d - %d)',[Self.Name,aInstance.ClassName,aProperty.Name,Round(aValidation.Min),Round(aValidation.Max)])
           else msg := aValidation.ErrorMsg;
         raise EOptionValidationError.Create(msg);
       end;
@@ -466,20 +515,20 @@ begin
   end;
 end;
 
-procedure TOptions.ValidateRequired(aProperty: TRttiProperty);
+procedure TOptions.ValidateRequired(const aInstance : TObject; aProperty: TRttiProperty);
 begin
-  if aProperty.GetValue(Self).IsEmpty then raise EOptionValidationError.CreateFmt('Option "%s.%s" is required',[Self.Name,aProperty.Name]);
+  if aProperty.GetValue(aInstance).IsEmpty then raise EOptionValidationError.CreateFmt('Option %s "%s.%s" is required',[Self.Name,aInstance.ClassName,aProperty.Name]);
 end;
 
-procedure TOptions.ValidateStringLength(aProperty: TRttiProperty; aValidation : StringLength);
+procedure TOptions.ValidateStringLength(const aInstance : TObject; aProperty: TRttiProperty; aValidation : StringLength);
 var
   value : TValue;
   msg : string;
 begin
-  value := aProperty.GetValue(Self);
+  value := aProperty.GetValue(aInstance);
   if (not value.IsEmpty) and (value.AsString.Length > aValidation.MaxLength) then
   begin
-    if aValidation.ErrorMsg.IsEmpty then msg := Format('Option "%s.%s" exceeds max length (%d)',[Self.Name,aProperty.Name,aValidation.MaxLength])
+    if aValidation.ErrorMsg.IsEmpty then msg := Format('Option %s "%s.%s" exceeds max length (%d)',[Self.Name,aInstance.ClassName,aProperty.Name,aValidation.MaxLength])
       else msg := aValidation.ErrorMsg;
 
     raise EOptionValidationError.Create(msg);

+ 2 - 2
Quick.YAML.Serializer.pas

@@ -7,7 +7,7 @@
   Author      : Kike Pérez
   Version     : 1.0
   Created     : 12/04/2019
-  Modified    : 27/04/2019
+  Modified    : 10/12/2019
 
   This file is part of QuickLib: https://github.com/exilon/QuickLib
 
@@ -866,7 +866,7 @@ begin
     for i := 0 to aYaml.Count - 1 do
     begin
       candidate := aYaml.Pairs[I];
-      if candidate.Value = nil then Exit(nil);
+      if (candidate = nil) or (candidate.Value = nil) then Exit(nil);
       if CompareText(candidate.Name,aName) = 0 then
         Exit(candidate);
     end;

+ 31 - 12
Quick.YAML.pas

@@ -7,7 +7,7 @@
   Author      : Kike Pérez
   Version     : 1.1
   Created     : 17/04/2019
-  Modified    : 03/07/2019
+  Modified    : 14/12/2019
 
   This file is part of QuickLib: https://github.com/exilon/QuickLib
 
@@ -36,6 +36,7 @@ interface
 uses
   Classes,
   SysUtils,
+  Quick.Commons,
   Generics.Collections,
   Quick.Value;
 
@@ -246,6 +247,7 @@ implementation
 
 const
   CRLF = #13#10;
+  NUM_INDENT = 2;
 
 
 { TYamlAncestor }
@@ -343,7 +345,7 @@ var
   trimed : string;
 begin
   trimed := aValue.Trim;
-  if trimed.StartsWith(#9) or trimed.IsEmpty or trimed.StartsWith('#') then Exit(99999);
+  if trimed.IsEmpty or trimed.StartsWith('#') then Exit(99999);
 
   for i := Low(aValue) to aValue.Length do
   begin
@@ -498,16 +500,19 @@ procedure TYamlObject.ParseYaml(const aData: string);
 var
   yaml : TList<string>;
   line : string;
+  data : string;
   yamlvalue : TYamlAncestor;
   vIndex : Integer;
 begin
   yaml := TList<string>.Create;
   try
     vIndex := 0;
+    //normalize tabs
+    data := StringReplace(aData,#9,Spaces(4),[rfReplaceAll]);
     {$IFNDEF LINUX}
-    for line in aData.Split([#13]) do yaml.Add(StringReplace(line,#10,'',[rfReplaceAll]));
+    for line in data.Split([#13]) do yaml.Add(StringReplace(line,#10,'',[rfReplaceAll]));
     {$ELSE}
-    for line in aData.Split([#10]) do yaml.Add(StringReplace(line,#13,'',[rfReplaceAll]));
+    for line in data.Split([#10]) do yaml.Add(StringReplace(line,#13,'',[rfReplaceAll]));
     {$ENDIF}
     while yaml.Count > vIndex do
     begin
@@ -524,16 +529,19 @@ class function TYamlObject.ParseYamlValue(const aData : string) : TYamlAncestor;
 var
   yaml : TList<string>;
   line : string;
+  data : string;
   yamlvalue : TYamlAncestor;
   vIndex : Integer;
 begin
   yaml := TList<string>.Create;
   try
     vIndex := 0;
+    //normalize tabs
+    data := StringReplace(aData,#9,Spaces(4),[rfReplaceAll]);
     {$IFNDEF LINUX}
-    for line in aData.Split([#13]) do yaml.Add(StringReplace(line,#10,'',[rfReplaceAll]));
+    for line in data.Split([#13]) do yaml.Add(StringReplace(line,#10,'',[rfReplaceAll]));
     {$ELSE}
-    for line in aData.Split([#10]) do yaml.Add(StringReplace(line,#13,'',[rfReplaceAll]));
+    for line in data.Split([#10]) do yaml.Add(StringReplace(line,#13,'',[rfReplaceAll]));
     {$ENDIF}
     if yaml[0].TrimLeft.StartsWith('- ') then Result := TYamlArray.Create
       else Result := TYamlObject.Create;
@@ -576,35 +584,45 @@ end;
 
 function TYamlObject.ParseToYaml(aIndent : Integer) : string;
 var
+  i : Integer;
   member : TYamlPair;
   yaml : TYamlWriter;
   yvalue : TYamlAncestor;
   indent : string;
   isscalar : Boolean;
+  scalar : string;
   rarray : string;
 begin
   yaml := TYamlWriter.Create;
   try
     indent := StringOfChar(' ',aIndent);
-    for member in fMembers do
+    for i := 0 to fMembers.Count - 1 do
     begin
+      member := fMembers[i];
       if member = nil then continue;
 
       yvalue := member.Value;
       if yvalue.IsScalar then
       begin
         if yvalue is TYamlComment then yaml.Writeln(Format('#%s%s',[indent,TYamlComment(member.Value).AsString]))
-          else yaml.Writeln(Format('%s%s: %s',[indent,member.Name,member.Value.Value.AsString]));
+        else
+        begin
+          scalar := member.Value.Value.AsString;
+          if scalar.IsEmpty then scalar := '""';
+          yaml.Writeln(Format('%s%s: %s',[indent,member.Name,scalar]));
+          if (i < fMembers.Count - 1) and (fMembers[i+1].Value is TYamlComment) then yaml.Writeln('');
+        end;
       end
       else if (yvalue is TYamlObject) then
       begin
         yaml.Writeln(Format('%s%s:',[indent,member.Name]));
-        yaml.Write((yvalue as TYamlObject).ParseToYaml(aIndent + 2));
+        yaml.Write((yvalue as TYamlObject).ParseToYaml(aIndent + NUM_INDENT));
+        if aIndent = 0 then yaml.Writeln('');
       end
       else if (yvalue is TYamlArray) then
       begin
         isscalar := False;
-        rarray := (yvalue as TYamlArray).ParseToYaml(aIndent + 2,isscalar);
+        rarray := (yvalue as TYamlArray).ParseToYaml(aIndent + NUM_INDENT,isscalar);
         if isscalar then yaml.Writeln(Format('%s%s: %s',[indent,member.Name,rarray]))
         else
         begin
@@ -925,12 +943,13 @@ begin
       end
       else if (yvalue is TYamlObject) then
       begin
-        yaml.Write(indent + '- ' + (yvalue as TYamlObject).ParseToYaml(aIndent + 2).TrimLeft);
+        yaml.Write(indent + '- ' + (yvalue as TYamlObject).ParseToYaml(aIndent + NUM_INDENT).TrimLeft);
       end
       else if (yvalue is TYamlArray) then
       begin
-        yaml.Write(Format('%s%s',[indent,(yvalue as TYamlArray).ParseToYaml(aIndent + 2,isscalar)]))
+        yaml.Write(Format('%s%s',[indent,(yvalue as TYamlArray).ParseToYaml(aIndent + NUM_INDENT,isscalar)]))
       end;
+      yaml.Writeln('');
     end;
     if yvalue.IsScalar then
     begin

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

@@ -13,12 +13,30 @@ uses
   Quick.Options.Serializer.Yaml;
 
 type
+  TLogConfig = class
+  private
+    fVerbose : Boolean;
+    fTimePrecission : Boolean;
+    fEnvironment : string;
+  published
+    property Verbose : Boolean read fVerbose write fVerbose;
+    property TimePrecission : Boolean read fTimePrecission write fTimePrecission;
+    [Required, StringLength(5)]
+    property Environment : string read fEnvironment write fEnvironment;
+  end;
+
   TLoggingOptions = class(TOptions)
   private
     fPath : string;
+    fConfig : TLogConfig;
+  public
+    constructor Create;
+    destructor Destroy; override;
   published
     [Required, StringLength(255,'Path too long')]
     property Path : string read fPath write fPath;
+    [Required]
+    property Config : TLogConfig read fConfig write fConfig;
   end;
 
   TGlobalOptions = class(TOptions)
@@ -50,6 +68,19 @@ var
   GlobalOptions : TGlobalOptions;
   UIOptions : TUIOptions;
 
+{ TLoggingOptions }
+
+constructor TLoggingOptions.Create;
+begin
+  fConfig := TLogConfig.Create;
+end;
+
+destructor TLoggingOptions.Destroy;
+begin
+  fConfig.Free;
+  inherited;
+end;
+
 begin
   try
     Options := TOptionsContainer.Create('.\options.conf',TJsonOptionsSerializer.Create,True);
@@ -61,6 +92,8 @@ begin
     Options.AddSection<TLoggingOptions>('Logging').ConfigureOptions(procedure(aOptions : TLoggingOptions)
                                                             begin
                                                               aOptions.Path := 'C:\';
+                                                              aOptions.Config.Verbose := True;
+                                                              aOptions.Config.Environment := 'PRO';
                                                             end
                                                             ).ValidateOptions;
     Options.AddSection<TGlobalOptions>('GlobalOptions').ConfigureOptions(procedure(aOptions : TGlobalOptions)
@@ -83,6 +116,7 @@ begin
     GlobalOptions := Options.GetSectionInterface<TGlobalOptions>.Value;
 
     coutFmt('Logging.Path = %s',[LoggingOptions.Path],etInfo);
+    coutFmt('Logging.Config.Environment = %s',[LoggingOptions.Config.Environment],etInfo);
     coutFmt('UIOptions.BackgroundColor = %d',[UIOptions.BackgroundColor],etInfo);
     coutFmt('GlobalOptions.StarMinimized = %s',[BoolToStr(GlobalOptions.StartMinimized,True)],etInfo);
 

+ 159 - 1
samples/delphi/QuickOptions/Optionsdemo.dproj

@@ -1,7 +1,7 @@
 <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
     <PropertyGroup>
         <ProjectGuid>{9267CD38-C083-435E-9993-922395B29892}</ProjectGuid>
-        <ProjectVersion>18.7</ProjectVersion>
+        <ProjectVersion>18.8</ProjectVersion>
         <FrameworkType>None</FrameworkType>
         <MainSource>Optionsdemo.dpr</MainSource>
         <Base>True</Base>
@@ -18,6 +18,11 @@
         <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)'=='iOSDevice32' and '$(Base)'=='true') or '$(Base_iOSDevice32)'!=''">
         <Base_iOSDevice32>true</Base_iOSDevice32>
         <CfgParent>Base</CfgParent>
@@ -93,6 +98,29 @@
         <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)'!=''">
+        <VerInfo_Keys>package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=</VerInfo_Keys>
+        <BT_BuildType>Debug</BT_BuildType>
+        <Base_Android>true</Base_Android>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+        <DCC_UsePackage>DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;FMXComponents;emsclientfiredac;DataSnapFireDAC;tethering;bindcompfmx;FmxTeeUI;FireDACIBDriver;fmx;RadiantShapesFmx;FlatButtonSet;FireDACDBXDriver;dbexpress;IndyCore;dsnap;DataSnapCommon;emsclient;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;DataSnapClient;inet;bindcompdbx;IndyIPCommon;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;ibmonitor;FMXTee;soaprtl;DbxCommonDriver;ibxpress;xmlrtl;soapmidas;DataSnapNativeClient;ibxbindings;rtl;DbxClientDriver;FireDACDSDriver;CustomIPTransport;bindcomp;CoolTrayIcon_D210_XE7;IndyIPClient;dbxcds;RadiantShapesFmx_Design;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;$(DCC_UsePackage);$(DCC_UsePackage)</DCC_UsePackage>
+        <Android_LauncherIcon36>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_36x36.png</Android_LauncherIcon36>
+        <Android_LauncherIcon48>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_48x48.png</Android_LauncherIcon48>
+        <Android_LauncherIcon72>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_72x72.png</Android_LauncherIcon72>
+        <Android_LauncherIcon96>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_96x96.png</Android_LauncherIcon96>
+        <Android_LauncherIcon144>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_144x144.png</Android_LauncherIcon144>
+        <Android_SplashImage426>$(BDS)\bin\Artwork\Android\FM_SplashImage_426x320.png</Android_SplashImage426>
+        <Android_SplashImage470>$(BDS)\bin\Artwork\Android\FM_SplashImage_470x320.png</Android_SplashImage470>
+        <Android_SplashImage640>$(BDS)\bin\Artwork\Android\FM_SplashImage_640x480.png</Android_SplashImage640>
+        <Android_SplashImage960>$(BDS)\bin\Artwork\Android\FM_SplashImage_960x720.png</Android_SplashImage960>
+        <Android_NotificationIcon24>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_24x24.png</Android_NotificationIcon24>
+        <Android_NotificationIcon36>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_36x36.png</Android_NotificationIcon36>
+        <Android_NotificationIcon48>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_48x48.png</Android_NotificationIcon48>
+        <Android_NotificationIcon72>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_72x72.png</Android_NotificationIcon72>
+        <Android_NotificationIcon96>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_96x96.png</Android_NotificationIcon96>
+        <EnabledSysJars>android-support-v4.dex.jar;cloud-messaging.dex.jar;com-google-android-gms.play-services-ads-base.17.2.0.dex.jar;com-google-android-gms.play-services-ads-identifier.16.0.0.dex.jar;com-google-android-gms.play-services-ads-lite.17.2.0.dex.jar;com-google-android-gms.play-services-ads.17.2.0.dex.jar;com-google-android-gms.play-services-analytics-impl.16.0.8.dex.jar;com-google-android-gms.play-services-analytics.16.0.8.dex.jar;com-google-android-gms.play-services-base.16.0.1.dex.jar;com-google-android-gms.play-services-basement.16.2.0.dex.jar;com-google-android-gms.play-services-gass.17.2.0.dex.jar;com-google-android-gms.play-services-identity.16.0.0.dex.jar;com-google-android-gms.play-services-maps.16.1.0.dex.jar;com-google-android-gms.play-services-measurement-base.16.4.0.dex.jar;com-google-android-gms.play-services-measurement-sdk-api.16.4.0.dex.jar;com-google-android-gms.play-services-stats.16.0.1.dex.jar;com-google-android-gms.play-services-tagmanager-v4-impl.16.0.8.dex.jar;com-google-android-gms.play-services-tasks.16.0.1.dex.jar;com-google-android-gms.play-services-wallet.16.0.1.dex.jar;com-google-firebase.firebase-analytics.16.4.0.dex.jar;com-google-firebase.firebase-common.16.1.0.dex.jar;com-google-firebase.firebase-iid-interop.16.0.1.dex.jar;com-google-firebase.firebase-iid.17.1.1.dex.jar;com-google-firebase.firebase-measurement-connector.17.0.1.dex.jar;com-google-firebase.firebase-messaging.17.5.0.dex.jar;fmx.dex.jar;google-play-billing.dex.jar;google-play-licensing.dex.jar</EnabledSysJars>
+    </PropertyGroup>
     <PropertyGroup Condition="'$(Base_iOSDevice32)'!=''">
         <DCC_UsePackage>DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;emsclientfiredac;DataSnapFireDAC;tethering;bindcompfmx;FmxTeeUI;FireDACIBDriver;fmx;RadiantShapesFmx;FireDACDBXDriver;dbexpress;IndyCore;dsnap;DataSnapCommon;emsclient;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;DataSnapClient;inet;bindcompdbx;IndyIPCommon;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;ibmonitor;FMXTee;soaprtl;DbxCommonDriver;ibxpress;xmlrtl;soapmidas;DataSnapNativeClient;ibxbindings;rtl;DbxClientDriver;FireDACDSDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;RadiantShapesFmx_Design;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
     </PropertyGroup>
@@ -207,12 +235,20 @@
                         <RemoteDir>classes</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>classes</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="AndroidFileProvider">
                     <Platform Name="Android">
                         <RemoteDir>res\xml</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\xml</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="AndroidGDBServer">
                     <Platform Name="Android">
@@ -225,138 +261,242 @@
                         <RemoteDir>library\lib\armeabi</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\armeabi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidLibnativeArmeabiv7aFile">
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="AndroidLibnativeMipsFile">
                     <Platform Name="Android">
                         <RemoteDir>library\lib\mips</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\mips</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="AndroidServiceOutput">
                     <Platform Name="Android">
                         <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\arm64-v8a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidServiceOutput_Android32">
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="AndroidSplashImageDef">
                     <Platform Name="Android">
                         <RemoteDir>res\drawable</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="AndroidSplashStyles">
                     <Platform Name="Android">
                         <RemoteDir>res\values</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="AndroidSplashStylesV21">
                     <Platform Name="Android">
                         <RemoteDir>res\values-v21</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\values-v21</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="Android_Colors">
                     <Platform Name="Android">
                         <RemoteDir>res\values</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="Android_DefaultAppIcon">
                     <Platform Name="Android">
                         <RemoteDir>res\drawable</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="Android_LauncherIcon144">
                     <Platform Name="Android">
                         <RemoteDir>res\drawable-xxhdpi</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="Android_LauncherIcon36">
                     <Platform Name="Android">
                         <RemoteDir>res\drawable-ldpi</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-ldpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="Android_LauncherIcon48">
                     <Platform Name="Android">
                         <RemoteDir>res\drawable-mdpi</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-mdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="Android_LauncherIcon72">
                     <Platform Name="Android">
                         <RemoteDir>res\drawable-hdpi</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-hdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="Android_LauncherIcon96">
                     <Platform Name="Android">
                         <RemoteDir>res\drawable-xhdpi</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="Android_NotificationIcon24">
                     <Platform Name="Android">
                         <RemoteDir>res\drawable-mdpi</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-mdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="Android_NotificationIcon36">
                     <Platform Name="Android">
                         <RemoteDir>res\drawable-hdpi</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-hdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="Android_NotificationIcon48">
                     <Platform Name="Android">
                         <RemoteDir>res\drawable-xhdpi</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="Android_NotificationIcon72">
                     <Platform Name="Android">
                         <RemoteDir>res\drawable-xxhdpi</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="Android_NotificationIcon96">
                     <Platform Name="Android">
                         <RemoteDir>res\drawable-xxxhdpi</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xxxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="Android_SplashImage426">
                     <Platform Name="Android">
                         <RemoteDir>res\drawable-small</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-small</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="Android_SplashImage470">
                     <Platform Name="Android">
                         <RemoteDir>res\drawable-normal</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-normal</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="Android_SplashImage640">
                     <Platform Name="Android">
                         <RemoteDir>res\drawable-large</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-large</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="Android_SplashImage960">
                     <Platform Name="Android">
                         <RemoteDir>res\drawable-xlarge</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\drawable-xlarge</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="Android_Strings">
                     <Platform Name="Android">
                         <RemoteDir>res\values</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="DebugSymbols">
                     <Platform Name="iOSSimulator">
@@ -445,6 +585,9 @@
                     <Platform Name="Android">
                         <Operation>0</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <Operation>0</Operation>
+                    </Platform>
                     <Platform Name="iOSDevice32">
                         <Operation>0</Operation>
                     </Platform>
@@ -734,6 +877,9 @@
                     <Platform Name="Android">
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <Operation>1</Operation>
+                    </Platform>
                 </DeployClass>
                 <DeployClass Name="ProjectiOSDeviceDebug">
                     <Platform Name="iOSDevice32">
@@ -826,6 +972,10 @@
                         <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
                         <Operation>1</Operation>
                     </Platform>
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\arm64-v8a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
                     <Platform Name="iOSDevice32">
                         <Operation>1</Operation>
                     </Platform>
@@ -850,6 +1000,12 @@
                         <Operation>0</Operation>
                     </Platform>
                 </DeployClass>
+                <DeployClass Name="ProjectOutput_Android32">
+                    <Platform Name="Android64">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
                 <DeployClass Name="ProjectUWPManifest">
                     <Platform Name="Win32">
                         <Operation>1</Operation>
@@ -887,9 +1043,11 @@
                 <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="iOSDevice32">False</Platform>
                 <Platform value="iOSDevice64">False</Platform>
                 <Platform value="iOSSimulator">False</Platform>