Commit be5e30ed by Mac Stephens

Added maintenance mode in dpr for client to ignore xdata connection on startup -…

Added maintenance mode in dpr for client to ignore xdata connection on startup - can be removed when site is developed
parent b581c1da
*.exe
*.bpl
*.bpi
*.dcp
*.so
*.apk
*.drc
*.map
*.dres
*.rsm
*.tds
*.dcu
*.lib
*.a
*.o
*.ocx
*.cfg
*.hpp
*Resource.rc
*.local
*.identcache
*.projdata
*.tvsconfig
*.dsk
__history/*
__recovery/*
envoyInternationalWeb/TMSWeb*
envoyInternationalWeb/Win32*
*.~*
*.stat
*.dxsettings
*.skincfg
envoyInternationalServer/source/__recovery/
*.zip
*.res
*.log
[Settings]
memoLogLevel=3
fileLogLevel=4
LogFileNum=53
webClientVersion=1.0.3
[SMTP]
Host=mail.em-sys.net
Port=587
Username=em-sys\emsys
Password=Ridge!4043
EmailWebsiteUses=emsys@em-sys.net
RecipientEmail=mac@em-sys.net
[Options]
LogFileNum=22
{
"Url": "http://localhost:2002/website",
"JwtTokenSecret": "super_secret0123super_secret4567",
"AdminPassword": "whatisthisusedfor",
"WebAppFolder": "static",
"ConsoleLogLevel": 3,
"FileLogLevel": 4
}
program emSystemsWebServer;
uses
System.SyncObjs,
System.SysUtils,
Vcl.StdCtrls,
IniFiles,
Vcl.Forms,
Api.Database in 'source\Api.Database.pas' {ApiDatabase: TDataModule},
Api.Server.Module in 'source\Api.Server.Module.pas' {ApiServerModule: TDataModule},
Common.Logging in 'source\Common.Logging.pas',
Api.Service in 'source\Api.Service.pas',
Api.ServiceImpl in 'source\Api.ServiceImpl.pas',
Main in 'source\Main.pas' {FMain},
App.Server.Module in 'source\App.Server.Module.pas' {AppServerModule: TDataModule},
Common.Config in 'source\Common.Config.pas',
Common.Middleware.Logging in 'source\Common.Middleware.Logging.pas';
type
TMemoLogAppender = class( TInterfacedObject, ILogAppender )
private
FLogLevel: Integer;
FLogMemo: TMemo;
FCriticalSection: TCriticalSection;
public
constructor Create(ALogLevel: Integer; ALogMemo: TMemo);
destructor Destroy; override;
procedure Send(logLevel: Integer; Log: ILog);
end;
TFileLogAppender = class( TInterfacedObject, ILogAppender )
private
FLogLevel: Integer;
FFilename: string;
FLogDirectory: string;
FCriticalSection: TCriticalSection;
public
constructor Create(ALogLevel: Integer; AFilename: string);
destructor Destroy; override;
procedure Send(logLevel: Integer; Log: ILog);
end;
TTaggedFileLogAppender = class( TInterfacedObject, ILogAppender )
private
FLogLevel: Integer;
FFilename: string;
FLogDirectory: string;
FTagPrefix: string;
FCriticalSection: TCriticalSection;
public
constructor Create(ALogLevel: Integer; AFilename: string; ATagPrefix: string);
destructor Destroy; override;
procedure Send(logLevel: Integer; Log: ILog);
end;
{ TMemoLogAppender }
constructor TMemoLogAppender.Create(ALogLevel: Integer; ALogMemo: TMemo);
begin
FLogLevel := ALogLevel;
FLogMemo := ALogMemo;
FCriticalSection := TCriticalSection.Create;
end;
destructor TMemoLogAppender.Destroy;
begin
FCriticalSection.Free;
inherited;
end;
procedure TMemoLogAppender.Send(logLevel: Integer; Log: ILog);
var
FormattedMessage: string;
LogTime: TDateTime;
LogMsg: string;
begin
FCriticalSection.Acquire;
try
LogTime := Now;
FormattedMessage := FormatDateTime('[yyyy-mm-dd HH:nn:ss.zzz]', LogTime);
LogMsg := Log.GetMessage;
if LogMsg.IsEmpty then
FormattedMessage := ''
else
FormattedMessage := FormattedMessage + '[' + IntToStr(logLevel) +'] ' + LogMsg;
if logLevel <= FLogLevel then
FLogMemo.Lines.Add(FormattedMessage);
finally
FCriticalSection.Release;
end;
end;
{ TFileLogAppender }
constructor TFileLogAppender.Create(ALogLevel: integer; AFilename: string);
var
iniFile: TIniFile;
fileNum: integer;
begin
FLogLevel := ALogLevel;
FCriticalSection := TCriticalSection.Create;
FLogDirectory := ExtractFilePath(Application.ExeName) + 'logs\';
if not DirectoryExists(FLogDirectory) then
CreateDir(FLogDirectory);
iniFile := TIniFile.Create(ChangeFileExt(Application.ExeName, '.ini'));
try
fileNum := iniFile.ReadInteger('Settings', 'LogFileNum', 0);
FFilename := AFilename + Format('%.4d', [fileNum]);
iniFile.WriteInteger('Settings', 'LogFileNum', fileNum + 1);
finally
iniFile.Free;
end;
end;
destructor TFileLogAppender.Destroy;
begin
FCriticalSection.Free;
inherited;
end;
procedure TFileLogAppender.Send(logLevel: integer; Log: ILog);
var
FormattedMessage: string;
LogFile: string;
LogTime: TDateTime;
LogMsg: string;
FLogFile: TextFile;
begin
FCriticalSection.Acquire;
try
LogTime := Now;
LogFile := FLogDirectory + FFilename + '.log';
FormattedMessage := FormatDateTime('[yyyy-mm-dd HH:nn:ss.zzz]', LogTime);
LogMsg := Log.GetMessage;
if LogMsg.IsEmpty then
FormattedMessage := ''
else
FormattedMessage := FormattedMessage + '[' + IntToStr(logLevel) +'] ' + LogMsg;
try
AssignFile(FLogFile, LogFile);
if logLevel <= FLogLevel then
begin
if FileExists(LogFile) then
Append(FLogFile)
else
Rewrite(FLogFile);
WriteLn(FLogFile, FormattedMessage);
end;
finally
CloseFile(FLogFile);
end;
finally
FCriticalSection.Release;
end;
end;
{ TTaggedFileLogAppender }
constructor TTaggedFileLogAppender.Create(ALogLevel: Integer; AFilename: string; ATagPrefix: string);
begin
FLogLevel := ALogLevel;
FTagPrefix := ATagPrefix;
FCriticalSection := TCriticalSection.Create;
FLogDirectory := ExtractFilePath(Application.ExeName) + 'logs\';
if not DirectoryExists(FLogDirectory) then
CreateDir(FLogDirectory);
FFilename := AFilename;
end;
destructor TTaggedFileLogAppender.Destroy;
begin
FCriticalSection.Free;
inherited;
end;
procedure TTaggedFileLogAppender.Send(logLevel: Integer; Log: ILog);
var
FormattedMessage: string;
LogFile: string;
LogTime: TDateTime;
LogMsg: string;
FLogFile: TextFile;
begin
if logLevel > FLogLevel then
Exit;
LogMsg := Log.GetMessage;
if LogMsg.IsEmpty then
Exit;
if (FTagPrefix <> '') and (Copy(LogMsg, 1, Length(FTagPrefix)) <> FTagPrefix) then
Exit;
FCriticalSection.Acquire;
try
LogTime := Now;
LogFile := FLogDirectory + FFilename + '.log';
FormattedMessage := FormatDateTime('[yyyy-mm-dd HH:nn:ss.zzz]', LogTime);
FormattedMessage := FormattedMessage + '[' + IntToStr(logLevel) +'] ' + LogMsg;
try
AssignFile(FLogFile, LogFile);
if FileExists(LogFile) then
Append(FLogFile)
else
Rewrite(FLogFile);
WriteLn(FLogFile, FormattedMessage);
finally
CloseFile(FLogFile);
end;
finally
FCriticalSection.Release;
end;
end;
{$R *.res}
var
iniFile: TIniFile;
memoLogLevel: Integer;
fileLogLevel: Integer;
begin
ReportMemoryLeaksOnShutdown := False;
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TFMain, FMain);
IniFile := TIniFile.Create(ChangeFileExt(Application.ExeName, '.ini'));
try
memoLogLevel := IniFile.ReadInteger('Settings', 'memoLogLevel', 3);
fileLogLevel := IniFile.ReadInteger('Settings', 'fileLogLevel', 4);
finally
IniFile.Free;
end;
Logger.AddAppender(TMemoLogAppender.Create(memoLogLevel, FMain.memoInfo));
Logger.AddAppender(TFileLogAppender.Create(fileLogLevel, 'emSystemsWebServer'));
Logger.AddAppender(TTaggedFileLogAppender.Create(fileLogLevel, 'contact', '[CONTACT]'));
Logger.AddAppender(TTaggedFileLogAppender.Create(fileLogLevel, 'demo', '[DEMO]'));
Application.Run;
end.
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{2A3028D9-BC39-4625-9BA5-0338012E2824}</ProjectGuid>
<ProjectVersion>20.4</ProjectVersion>
<FrameworkType>VCL</FrameworkType>
<Base>True</Base>
<Config Condition="'$(Config)'==''">Release</Config>
<Platform Condition="'$(Platform)'==''">Win32</Platform>
<TargetedPlatforms>3</TargetedPlatforms>
<AppType>Application</AppType>
<MainSource>emSystemsWebServer.dpr</MainSource>
<ProjectName Condition="'$(ProjectName)'==''">emSystemsWebServer</ProjectName>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
<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="('$(Platform)'=='Win64' and '$(Cfg_1)'=='true') or '$(Cfg_1_Win64)'!=''">
<Cfg_1_Win64>true</Cfg_1_Win64>
<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="('$(Platform)'=='Win32' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win32)'!=''">
<Cfg_2_Win32>true</Cfg_2_Win32>
<CfgParent>Cfg_2</CfgParent>
<Cfg_2>true</Cfg_2>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win64)'!=''">
<Cfg_2_Win64>true</Cfg_2_Win64>
<CfgParent>Cfg_2</CfgParent>
<Cfg_2>true</Cfg_2>
<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;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace)</DCC_Namespace>
<Icon_MainIcon>$(BDS)\bin\delphi_PROJECTICON.ico</Icon_MainIcon>
<Icns_MainIcns>$(BDS)\bin\delphi_PROJECTICNS.icns</Icns_MainIcns>
<SanitizedProjectName>emSystemsWebServer</SanitizedProjectName>
<GetItPackages>Navigator-12-1.6.5.3</GetItPackages>
</PropertyGroup>
<PropertyGroup Condition="'$(Base_Win32)'!=''">
<DCC_UsePackage>gtFRExpD28;vclwinx;dacvcl280;FlexCel_Report;fmx;PKIEDB28;vclie;DbxCommonDriver;bindengine;IndyIPCommon;VCLRESTComponents;FireDACCommonODBC;aurelius;TMSCloudPkgDEDXE14;FireDACCommonDriver;sparkle;appanalytics;IndyProtocols;vclx;TatukGIS_DK11_RX11_VCL;FMXTMSFNCMapsPkgDXE14;IndyIPClient;dbxcds;vcledge;dac280;frxe28;bindcompvclwinx;gtScaleRichVwExpD28;VCLTMSFNCUIPackPkgDXE14;gtXPressExpD28;unidac280;gtPDFkitD11ProP;FlexCel_Pdf;bindcompfmx;AdvChartDEDXE14;madBasic_;VCLTMSFNCDashboardPackPkgDXE14;SKIA_FlexCel_Core;TMSVCLUIPackPkgDXE14;inetdb;TatukGIS_DK11_RX11_FMX;AcroPDF;TatukGIS_DK11_RX11;FireDACSqliteDriver;DbxClientDriver;soapmidas;vclCryptoPressStreamD28;vclactnband;gtRBExpD28;fmxFireDAC;dbexpress;DBXMySQLDriver;VclSmp;inet;unidacvcl280;dacfmx280;SigPlus;fcstudiowin;vcltouch;fmxase;VCLTMSFNCMapsPkgDXE14;ipstudiowin;TMSWEBCorePkgLibDXE14;frx28;dbrtl;QRWRunDXE11_w64;TMSWEBCorePkgDXE14;fmxdae;addict4_d28;FlexCel_XlsAdapter;gtAdvGridExpD28;FireDACMSAccDriver;VCL_FlexCel_Core;CustomIPTransport;tmsbcl;ipstudiowinwordxp;gtDocEngD28;gtRaveExpD28;FMXTMSFNCDashboardPackPkgDXE14;vcldsnap;madExcept_;DBXInterBaseDriver;frxDB28;IndySystem;ipstudiowinclient;VCLTMSFNCCorePkgDXE14;vcldb;CamRemoteD11;FMXTMSFNCUIPackPkgDXE14;TMSCloudPkgDXE14;gtQRExpD28;VirtualTreesR;WPViewPDF_RT;FlexCel_Core;vclFireDAC;vquery280;madDisAsm_;bindcomp;FireDACCommon;FlexCel_Render;unidacfmx280;FMXTMSFNCCorePkgDXE14;IndyCore;RESTBackendComponents;gtACEExpD28;bindcompdbx;rtl;FireDACMySQLDriver;FireDACADSDriver;VCL_FlexCel_Components;RESTComponents;DBXSqliteDriver;vcl;IndyIPServer;dsnapxml;dsnapcon;adortl;TMSVCLUIPackPkgExDXE14;WPViewPDF_DT;TMSVCLUIPackPkgWizDXE14;gtHtmVwExpD28;AdvChartDXE14;gtRichVwExpD28;vclimg;FireDACPgDriver;FireDAC;inetdbxpress;TMSVCLUIPackPkgXlsDXE14;xmlrtl;tethering;PKIECtrl28;crcontrols280;bindcompvcl;dsnap;xdata;CloudService;fmxobj;bindcompvclsmp;addict4db_d28;CEF4Delphi;soaprtl;soapserver;FireDACIBDriver;$(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_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
<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>
<Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
</PropertyGroup>
<PropertyGroup Condition="'$(Base_Win64)'!=''">
<DCC_UsePackage>vclwinx;FlexCel_Report;fmx;PKIEDB28;vclie;DbxCommonDriver;bindengine;IndyIPCommon;VCLRESTComponents;FireDACCommonODBC;FireDACCommonDriver;appanalytics;IndyProtocols;vclx;FMXTMSFNCMapsPkgDXE14;IndyIPClient;dbxcds;vcledge;bindcompvclwinx;VCLTMSFNCUIPackPkgDXE14;FlexCel_Pdf;bindcompfmx;VCLTMSFNCDashboardPackPkgDXE14;TMSVCLUIPackPkgDXE14;inetdb;FireDACSqliteDriver;DbxClientDriver;soapmidas;vclactnband;fmxFireDAC;dbexpress;DBXMySQLDriver;VclSmp;inet;fcstudiowin;vcltouch;fmxase;VCLTMSFNCMapsPkgDXE14;ipstudiowin;dbrtl;QRWRunDXE11_w64;fmxdae;FlexCel_XlsAdapter;FireDACMSAccDriver;VCL_FlexCel_Core;CustomIPTransport;vcldsnap;DBXInterBaseDriver;IndySystem;ipstudiowinclient;VCLTMSFNCCorePkgDXE14;vcldb;CamRemoteD11;FMXTMSFNCUIPackPkgDXE14;VirtualTreesR;WPViewPDF_RT;FlexCel_Core;vclFireDAC;bindcomp;FireDACCommon;FlexCel_Render;FMXTMSFNCCorePkgDXE14;IndyCore;RESTBackendComponents;bindcompdbx;rtl;FireDACMySQLDriver;FireDACADSDriver;VCL_FlexCel_Components;RESTComponents;DBXSqliteDriver;vcl;IndyIPServer;dsnapxml;dsnapcon;adortl;TMSVCLUIPackPkgExDXE14;AdvChartDXE14;vclimg;FireDACPgDriver;FireDAC;inetdbxpress;TMSVCLUIPackPkgXlsDXE14;xmlrtl;tethering;PKIECtrl28;bindcompvcl;dsnap;CloudService;fmxobj;bindcompvclsmp;soaprtl;soapserver;FireDACIBDriver;$(DCC_UsePackage)</DCC_UsePackage>
<DCC_Namespace>Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace)</DCC_Namespace>
<BT_BuildType>Debug</BT_BuildType>
<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
<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>
<Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
</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>
<DCC_IntegerOverflowCheck>true</DCC_IntegerOverflowCheck>
<DCC_RangeChecking>true</DCC_RangeChecking>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_1_Win32)'!=''">
<DCC_RemoteDebug>false</DCC_RemoteDebug>
<AppDPIAwarenessMode>PerMonitorV2</AppDPIAwarenessMode>
<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
<VerInfo_Locale>1033</VerInfo_Locale>
<DCC_ExeOutput>bin</DCC_ExeOutput>
<DCC_UnitSearchPath>C:\RADTools\FastMM4;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_1_Win64)'!=''">
<AppDPIAwarenessMode>PerMonitorV2</AppDPIAwarenessMode>
</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>
<PropertyGroup Condition="'$(Cfg_2_Win32)'!=''">
<AppDPIAwarenessMode>PerMonitorV2</AppDPIAwarenessMode>
<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
<VerInfo_Locale>1033</VerInfo_Locale>
<DCC_UnitSearchPath>C:\RADTools\FastMM4;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
<DCC_ExeOutput>bin</DCC_ExeOutput>
<VerInfo_Release>3</VerInfo_Release>
<VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.3.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_2_Win64)'!=''">
<AppDPIAwarenessMode>PerMonitorV2</AppDPIAwarenessMode>
</PropertyGroup>
<ItemGroup>
<DelphiCompile Include="$(MainSource)">
<MainSource>MainSource</MainSource>
</DelphiCompile>
<DCCReference Include="source\Api.Database.pas">
<Form>ApiDatabase</Form>
<FormType>dfm</FormType>
<DesignClass>TDataModule</DesignClass>
</DCCReference>
<DCCReference Include="source\Api.Server.Module.pas">
<Form>ApiServerModule</Form>
<FormType>dfm</FormType>
<DesignClass>TDataModule</DesignClass>
</DCCReference>
<DCCReference Include="source\Common.Logging.pas"/>
<DCCReference Include="source\Api.Service.pas"/>
<DCCReference Include="source\Api.ServiceImpl.pas"/>
<DCCReference Include="source\Main.pas">
<Form>FMain</Form>
<FormType>dfm</FormType>
</DCCReference>
<DCCReference Include="source\App.Server.Module.pas">
<Form>AppServerModule</Form>
<FormType>dfm</FormType>
<DesignClass>TDataModule</DesignClass>
</DCCReference>
<DCCReference Include="source\Common.Config.pas"/>
<DCCReference Include="source\Common.Middleware.Logging.pas"/>
<BuildConfiguration Include="Base">
<Key>Base</Key>
</BuildConfiguration>
<BuildConfiguration Include="Debug">
<Key>Cfg_1</Key>
<CfgParent>Base</CfgParent>
</BuildConfiguration>
<BuildConfiguration Include="Release">
<Key>Cfg_2</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">emSystemsWebServer.dpr</Source>
</Source>
<Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\bcboffice2k290.bpl">Embarcadero C++Builder Office 2000 Servers Package</Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\bcbofficexp290.bpl">Embarcadero C++Builder Office XP Servers Package</Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\dcloffice2k290.bpl">Microsoft Office 2000 Sample Automation Server Wrapper Components</Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\dclofficexp290.bpl">Microsoft Office XP Sample Automation Server Wrapper Components</Excluded_Packages>
</Excluded_Packages>
</Delphi.Personality>
<Deployment Version="5">
<DeployFile LocalName="Win32\Debug\emSystemsWebServer.exe" Configuration="Debug" Class="ProjectOutput"/>
<DeployFile LocalName="bin\emSystemsWebServer.exe" Configuration="Debug" Class="ProjectOutput">
<Platform Name="Win32">
<RemoteName>emSystemsWebServer.exe</RemoteName>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="bin\emSystemsWebServer.exe" Configuration="Release" Class="ProjectOutput">
<Platform Name="Win32">
<RemoteName>emSystemsWebServer.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="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="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="AndroidSplashImageDefV21">
<Platform Name="Android">
<RemoteDir>res\drawable-anydpi-v21</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-anydpi-v21</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="AndroidSplashStylesV31">
<Platform Name="Android">
<RemoteDir>res\values-v31</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\values-v31</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidSplashStylesV35">
<Platform Name="Android">
<RemoteDir>res\values-v35</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\values-v35</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_AdaptiveIcon">
<Platform Name="Android">
<RemoteDir>res\drawable-anydpi-v26</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-anydpi-v26</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_AdaptiveIconBackground">
<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_AdaptiveIconForeground">
<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_AdaptiveIconMonochrome">
<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_AdaptiveIconV33">
<Platform Name="Android">
<RemoteDir>res\drawable-anydpi-v33</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-anydpi-v33</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_ColorsDark">
<Platform Name="Android">
<RemoteDir>res\values-night-v21</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\values-night-v21</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_DefaultAppIcon">
<Platform Name="Android">
<RemoteDir>res\drawable</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_LauncherIcon144">
<Platform Name="Android">
<RemoteDir>res\drawable-xxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-xxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_LauncherIcon192">
<Platform Name="Android">
<RemoteDir>res\drawable-xxxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-xxxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_LauncherIcon36">
<Platform Name="Android">
<RemoteDir>res\drawable-ldpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-ldpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_LauncherIcon48">
<Platform Name="Android">
<RemoteDir>res\drawable-mdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-mdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_LauncherIcon72">
<Platform Name="Android">
<RemoteDir>res\drawable-hdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-hdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_LauncherIcon96">
<Platform Name="Android">
<RemoteDir>res\drawable-xhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-xhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_NotificationIcon24">
<Platform Name="Android">
<RemoteDir>res\drawable-mdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-mdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_NotificationIcon36">
<Platform Name="Android">
<RemoteDir>res\drawable-hdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-hdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_NotificationIcon48">
<Platform Name="Android">
<RemoteDir>res\drawable-xhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-xhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_NotificationIcon72">
<Platform Name="Android">
<RemoteDir>res\drawable-xxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-xxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_NotificationIcon96">
<Platform Name="Android">
<RemoteDir>res\drawable-xxxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-xxxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_SplashImage426">
<Platform Name="Android">
<RemoteDir>res\drawable-small</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-small</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_SplashImage470">
<Platform Name="Android">
<RemoteDir>res\drawable-normal</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-normal</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_SplashImage640">
<Platform Name="Android">
<RemoteDir>res\drawable-large</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-large</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_SplashImage960">
<Platform Name="Android">
<RemoteDir>res\drawable-xlarge</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-xlarge</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_Strings">
<Platform Name="Android">
<RemoteDir>res\values</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\values</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_VectorizedNotificationIcon">
<Platform Name="Android">
<RemoteDir>res\drawable-anydpi-v24</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-anydpi-v24</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_VectorizedSplash">
<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_VectorizedSplashDark">
<Platform Name="Android">
<RemoteDir>res\drawable-night-anydpi-v21</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-night-anydpi-v21</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_VectorizedSplashV31">
<Platform Name="Android">
<RemoteDir>res\drawable-anydpi-v31</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-anydpi-v31</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_VectorizedSplashV31Dark">
<Platform Name="Android">
<RemoteDir>res\drawable-night-anydpi-v31</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-night-anydpi-v31</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="OSXARM64">
<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="iOSSimARM64">
<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="OSXARM64">
<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="iOSSimARM64">
<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="OSXARM64">
<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="iOSSimARM64">
<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="OSXARM64">
<RemoteDir>Contents\Resources\StartUp\</RemoteDir>
<Operation>0</Operation>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectAndroidManifest">
<Platform Name="Android">
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectOSXDebug">
<Platform Name="OSX64">
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="OSXARM64">
<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>
<Platform Name="OSXARM64">
<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>
<Platform Name="OSXARM64">
<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>
<Platform Name="OSXARM64">
<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="iOSSimARM64">
<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="OSXARM64">
<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>
<Platform Name="Win64x">
<Operation>1</Operation>
</Platform>
<Platform Name="WinARM64EC">
<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>
<Platform Name="iOSSimARM64">
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSEntitlements">
<Platform Name="iOSDevice32">
<RemoteDir>..\</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<RemoteDir>..\</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<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="iOSSimARM64">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSLaunchScreen">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen</RemoteDir>
<Operation>64</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<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="iOSSimARM64">
<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>
<Platform Name="WinARM64EC">
<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>
<Platform Name="WinARM64EC">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iOS_AppStore1024">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_AppIcon152">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_AppIcon167">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch2x">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_LaunchDark2x">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Notification40">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Setting58">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_SpotLight80">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_AppIcon120">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_AppIcon180">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch2x">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch3x">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_LaunchDark2x">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<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="iOSSimARM64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Notification40">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Notification60">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Setting58">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Setting87">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Spotlight120">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Spotlight80">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<ProjectRoot Platform="Android" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="Android64" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="iOSDevice32" Name="$(PROJECTNAME).app"/>
<ProjectRoot Platform="iOSDevice64" Name="$(PROJECTNAME).app"/>
<ProjectRoot Platform="iOSSimARM64" Name="$(PROJECTNAME).app"/>
<ProjectRoot Platform="Linux64" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="OSX32" Name="$(PROJECTNAME).app"/>
<ProjectRoot Platform="OSX64" Name="$(PROJECTNAME).app"/>
<ProjectRoot Platform="OSXARM64" Name="$(PROJECTNAME).app"/>
<ProjectRoot Platform="Win32" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="Win64" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="Win64x" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="WinARM64EC" Name="$(PROJECTNAME)"/>
</Deployment>
<Platforms>
<Platform value="Win32">True</Platform>
<Platform value="Win64">True</Platform>
</Platforms>
</BorlandProject>
<ProjectFileVersion>12</ProjectFileVersion>
</ProjectExtensions>
<Import Project="$(BDS)\Bin\CodeGear.Delphi.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')"/>
<Import Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj" Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')"/>
<Import Project="$(MSBuildProjectName).deployproj" Condition="Exists('$(MSBuildProjectName).deployproj')"/>
</Project>
object ApiDatabase: TApiDatabase
Height = 218
Width = 444
object ucBooking: TUniConnection
ProviderName = 'PostgreSQL'
LoginPrompt = False
Left = 41
Top = 63
end
object PostgreSQLUniProvider1: TPostgreSQLUniProvider
Left = 156
Top = 64
end
object UniQuery1: TUniQuery
Connection = ucBooking
Left = 287
Top = 62
end
end
unit Api.Database;
interface
uses
System.SysUtils, System.Classes, Data.DB, MemDS, DBAccess, Uni, UniProvider,
PostgreSQLUniProvider;
type
TApiDatabase = class(TDataModule)
ucBooking: TUniConnection;
PostgreSQLUniProvider1: TPostgreSQLUniProvider;
UniQuery1: TUniQuery;
private
{ Private declarations }
public
{ Public declarations }
class procedure ExecSQL(const SQL: string);
end;
var
ApiDatabase: TApiDatabase;
implementation
{%CLASSGROUP 'Vcl.Controls.TControl'}
{$R *.dfm}
class procedure TApiDatabase.ExecSQL(const SQL: string);
var
DB: TApiDatabase;
begin
DB := TApiDatabase.Create(nil);
try
DB.UniQuery1.SQL.Text := SQL;
DB.UniQuery1.ExecSQL;
finally
DB.Free;
end;
end;
end.
object ApiServerModule: TApiServerModule
Height = 179
Width = 190
object SparkleHttpSysDispatcher: TSparkleHttpSysDispatcher
Left = 74
Top = 16
end
object XDataServer: TXDataServer
Dispatcher = SparkleHttpSysDispatcher
EntitySetPermissions = <>
SwaggerOptions.Enabled = True
SwaggerOptions.AuthMode = Jwt
SwaggerUIOptions.Enabled = True
SwaggerUIOptions.ShowFilter = True
SwaggerUIOptions.TryItOutEnabled = True
Left = 70
Top = 88
object XDataServerCompress: TSparkleCompressMiddleware
end
object XDataServerCORS: TSparkleCorsMiddleware
end
object XDataServerGeneric: TSparkleGenericMiddleware
OnMiddlewareCreate = XDataServerGenericMiddlewareCreate
end
end
end
unit Api.Server.Module;
interface
uses
System.SysUtils, System.Classes, System.IniFiles,
Sparkle.HttpServer.Module, Sparkle.HttpServer.Context,
Sparkle.Comp.Server, Sparkle.Comp.HttpSysDispatcher,
XData.Comp.Server, XData.Comp.ConnectionPool, XData.OpenApi.Service,
Sparkle.Comp.GenericMiddleware, Sparkle.Comp.JwtMiddleware,
Sparkle.Comp.BasicAuthMiddleware, Sparkle.Comp.CorsMiddleware, Common.Middleware.Logging,
Sparkle.Comp.CompressMiddleware, VCL.Forms, XData.Server.Module, Common.Logging;
type
TApiServerModule = class(TDataModule)
SparkleHttpSysDispatcher: TSparkleHttpSysDispatcher;
XDataServer: TXDataServer;
XDataServerCompress: TSparkleCompressMiddleware;
XDataServerCORS: TSparkleCorsMiddleware;
XDataServerGeneric: TSparkleGenericMiddleware;
procedure XDataServerGenericMiddlewareCreate(Sender: TObject; var Middleware:
IHttpServerMiddleware);
public
procedure StartApiServer(ABaseUrl: string);
end;
const
SERVER_PATH_SEGMENT = 'api';
var
ApiServerModule: TApiServerModule;
implementation
{%CLASSGROUP 'Vcl.Controls.TControl'}
{$R *.dfm}
procedure TApiServerModule.StartApiServer(ABaseUrl: string);
var
Url: string;
begin
RegisterOpenApiService;
Url := ABaseUrl;
if not Url.EndsWith('/') then
Url := Url + '/';
Url := Url + SERVER_PATH_SEGMENT;
XDataServer.BaseUrl := Url;
SparkleHttpSysDispatcher.Start;
Logger.Log(1, Format('Api server module listening at "%s"', [XDataServer.BaseUrl]));
end;
procedure TApiServerModule.XDataServerGenericMiddlewareCreate(Sender: TObject;
var Middleware: IHttpServerMiddleware);
begin
Middleware := TLoggingMiddleware.Create(Logger);
end;
end.
unit Api.Service;
interface
uses
XData.Service.Common, System.JSON;
const
API_MODEL = 'api';
type
[ServiceContract]
IApiService = interface(IInvokable)
['{46B3B095-5873-4452-B338-AEE009604DED}']
[HttpGet] function SendEmail(Name, Email, Subject, Body: string): string;
[HttpGet] function VerifyVersion(ClientVersion: string): TJSONObject;
end;
implementation
initialization
RegisterServiceType(TypeInfo(IApiService));
end.
unit Api.ServiceImpl;
interface
uses
XData.Server.Module,
XData.Service.Common,
IdSMTP, IdMessage, IdSSLOpenSSL, IdText, IdExplicitTLSClientServerBase, System.NetEncoding,
IdIOHandlerSocket, IdException, IdSSL, IdSMTPBase, IdGlobal, IdStack, IdWinsock2,
IdStackConsts, IdIOHandler, IdIOHandlerStack, IdBaseComponent, System.JSON,
IdComponent, IdTCPConnection, IdTCPClient, IdMessageClient, VCL.Forms, Api.Service;
type
[ServiceImplementation]
TApiService = class(TInterfacedObject, IApiService)
public
function SendEmail(Name, Email, Subject, Body: string): string;
function VerifyVersion(ClientVersion: string): TJSONObject;
end;
implementation
uses
System.SysUtils,
System.IniFiles,
Common.Logging,
Main;
function TApiService.SendEmail(Name, Email, Subject, Body: string): string;
var
smtp: TIdSMTP;
message: TIdMessage;
confirmMsg: TIdMessage;
ssl: TIdSSLIOHandlerSocketOpenSSL;
iniFile: TIniFile;
iniPath: string;
fromEmail: string;
recipientEmail: string;
safeSenderEmail: string;
safeSubject: string;
safeName: string;
submittedOn: string;
logPrefix: string;
htmlBody: string;
confirmHtml: string;
bodyHtml: string;
textPart: TIdText;
htmlPart: TIdText;
confirmTextPart: TIdText;
confirmHtmlPart: TIdText;
confirmSubject: string;
bodyLines: TArray<string>;
i: Integer;
begin
iniPath := ChangeFileExt(Application.ExeName, '.ini');
iniFile := TIniFile.Create(iniPath);
try
fromEmail := iniFile.ReadString('SMTP', 'EmailWebsiteUses', '');
recipientEmail := iniFile.ReadString('SMTP', 'RecipientEmail', '');
safeSenderEmail := Email.Replace(#13, '').Replace(#10, '').Trim;
safeSubject := Subject.Replace(#13, '').Replace(#10, '').Trim;
safeName := Name.Trim;
if SameText(safeSubject, 'Demo Request') then
logPrefix := '[DEMO]'
else
logPrefix := '[CONTACT]';
Logger.Log(2, logPrefix + ' ----------------------------------------');
Logger.Log(2, Format('%s SubmittedOn=%s', [logPrefix, FormatDateTime('yyyy-mm-dd HH:nn:ss', Now)]));
Logger.Log(2, Format('%s Name=%s', [logPrefix, safeName]));
Logger.Log(2, Format('%s Email=%s', [logPrefix, safeSenderEmail]));
Logger.Log(2, Format('%s Subject=%s', [logPrefix, safeSubject]));
Logger.Log(2, logPrefix + ' Body:');
bodyLines := Body.Replace(#13#10, #10).Replace(#13, #10).Split([#10]);
for i := 0 to High(bodyLines) do
Logger.Log(2, logPrefix + ' ' + bodyLines[i]);
smtp := TIdSMTP.Create(nil);
message := TIdMessage.Create(nil);
confirmMsg := TIdMessage.Create(nil);
ssl := TIdSSLIOHandlerSocketOpenSSL.Create(smtp);
try
smtp.IOHandler := ssl;
smtp.UseTLS := utUseExplicitTLS;
smtp.AuthType := satDefault;
smtp.Host := iniFile.ReadString('SMTP', 'Host', '');
smtp.Port := iniFile.ReadInteger('SMTP', 'Port', 0);
smtp.Username := iniFile.ReadString('SMTP', 'Username', '');
smtp.Password := iniFile.ReadString('SMTP', 'Password', '');
ssl.SSLOptions.Method := sslvTLSv1_2;
ssl.SSLOptions.SSLVersions := [sslvTLSv1_2];
submittedOn := FormatDateTime('yyyy-mm-dd hh:nn AM/PM', Now);
bodyHtml := TNetEncoding.HTML.Encode(Body);
bodyHtml := bodyHtml.Replace(#13#10, '<br>').Replace(#10, '<br>').Replace(#13, '<br>');
htmlBody := Format(
'<html>' +
'<body style="font-family: Arial, sans-serif; font-size: 14px; color:#222;">' +
'<h2 style="color: #2E86C1; margin: 0 0 12px 0;">New %s message from EM Systems Website</h2>' +
'<p style="margin: 0 0 6px 0;"><strong>Submitted On:</strong> %s</p>' +
'<p style="margin: 0 0 6px 0;"><strong>From:</strong> %s &lt;%s&gt;</p>' +
'<p style="margin: 0 0 14px 0;"><strong>Subject:</strong> %s</p>' +
'<hr style="border:0; border-top:1px solid #ddd; margin: 14px 0;">' +
'<p style="margin: 0 0 8px 0;"><strong>Message:</strong></p>' +
'<div style="line-height: 1.4;">%s</div>' +
'</body>' +
'</html>',
[
TNetEncoding.HTML.Encode(safeSubject),
submittedOn,
TNetEncoding.HTML.Encode(safeName),
TNetEncoding.HTML.Encode(safeSenderEmail),
TNetEncoding.HTML.Encode(safeSubject),
bodyHtml
]
);
message.Clear;
message.From.Address := fromEmail;
message.Recipients.EmailAddresses := recipientEmail;
if safeSenderEmail <> '' then
message.ReplyTo.EmailAddresses := safeSenderEmail;
message.Subject := safeSubject;
message.MessageParts.Clear;
message.ContentType := 'multipart/alternative';
textPart := TIdText.Create(message.MessageParts, nil);
textPart.ContentType := 'text/plain; charset=utf-8';
textPart.Body.Text :=
'New message from EM Systems Website' + sLineBreak +
'Submitted On: ' + submittedOn + sLineBreak +
'From: ' + safeName + ' <' + safeSenderEmail + '>' + sLineBreak +
'Subject: ' + safeSubject + sLineBreak +
sLineBreak +
Body;
htmlPart := TIdText.Create(message.MessageParts, nil);
htmlPart.ContentType := 'text/html; charset=utf-8';
htmlPart.Body.Text := htmlBody;
smtp.Connect;
try
smtp.Send(message);
Logger.Log(2, Format('%s InternalNotificationSent to=%s', [logPrefix, recipientEmail]));
if (safeSenderEmail <> '') and (Pos('@', safeSenderEmail) > 1) then
begin
if SameText(safeSubject, 'Demo Request') then
confirmSubject := 'We received your demo request'
else
confirmSubject := 'We received your message';
confirmHtml := Format(
'<html>' +
'<body style="font-family: Arial, sans-serif; font-size: 14px; color:#222;">' +
'<p style="margin:0 0 10px 0;">Hi %s,</p>' +
'<p style="margin:0 0 10px 0;">Thanks for reaching out. This is a quick confirmation that we received your message.</p>' +
'<p style="margin:0 0 10px 0;"><strong>Subject:</strong> %s</p>' +
'<p style="margin:0 0 10px 0;"><strong>Submitted On:</strong> %s</p>' +
'<p style="margin:0;">Well reply as soon as we can.</p>' +
'</body>' +
'</html>',
[
TNetEncoding.HTML.Encode(safeName),
TNetEncoding.HTML.Encode(safeSubject),
submittedOn
]
);
confirmMsg.Clear;
confirmMsg.From.Address := fromEmail;
confirmMsg.Recipients.EmailAddresses := safeSenderEmail;
confirmMsg.Subject := confirmSubject;
confirmMsg.ExtraHeaders.Values['Auto-Submitted'] := 'auto-replied';
confirmMsg.ExtraHeaders.Values['X-Auto-Response-Suppress'] := 'All';
confirmMsg.MessageParts.Clear;
confirmMsg.ContentType := 'multipart/alternative';
confirmTextPart := TIdText.Create(confirmMsg.MessageParts, nil);
confirmTextPart.ContentType := 'text/plain; charset=utf-8';
confirmTextPart.Body.Text :=
'Hi ' + safeName + ',' + sLineBreak +
sLineBreak +
'Thanks for reaching out. We have received your message and will be in touch soon.' + sLineBreak +
sLineBreak +
'-EM Systems Team';
confirmHtmlPart := TIdText.Create(confirmMsg.MessageParts, nil);
confirmHtmlPart.ContentType := 'text/html; charset=utf-8';
confirmHtmlPart.Body.Text := confirmHtml;
smtp.Send(confirmMsg);
Logger.Log(2, Format('%s ConfirmationSent to=%s', [logPrefix, safeSenderEmail]));
end
else
Logger.Log(2, logPrefix + ' ConfirmationSkipped: invalid sender email');
finally
smtp.Disconnect;
end;
finally
ssl.Free;
confirmMsg.Free;
message.Free;
smtp.Free;
end;
finally
iniFile.Free;
end;
Result := 'Email sent successfully';
end;
function TApiService.VerifyVersion(ClientVersion: string): TJSONObject;
var
iniFile: TIniFile;
iniPath: string;
webClientVersion: string;
errorMsg: string;
begin
iniPath := ChangeFileExt(Application.ExeName, '.ini');
iniFile := TIniFile.Create(iniPath);
try
webClientVersion := iniFile.ReadString('Settings', 'webClientVersion', '');
finally
iniFile.Free;
end;
errorMsg := '';
if (webClientVersion <> '') and (ClientVersion <> webClientVersion) then
begin
Logger.Log(2, Format('VerifyVersion called with mismatch. Server expects %s but client is %s.',
[webClientVersion, ClientVersion]));
errorMsg := 'You are running the wrong version of the website, please click the button to update.';
end;
Result := TJSONObject.Create;
Result.AddPair('webClientVersion', webClientVersion);
if errorMsg <> '' then
Result.AddPair('error', errorMsg);
Logger.Log(2, Format('VerifyVersion: client=%s server=%s mismatch=%s',
[ClientVersion, webClientVersion, BoolToStr(errorMsg <> '', True)]));
end;
initialization
RegisterServiceType(TApiService);
end.
object AppServerModule: TAppServerModule
Height = 264
Width = 254
object SparkleStaticServer: TSparkleStaticServer
Dispatcher = SparkleHttpSysDispatcher
Left = 114
Top = 160
object SparkleStaticServerCompress: TSparkleCompressMiddleware
end
object SparkleStaticServerLogging: TSparkleLoggingMiddleware
FormatString = ':method :url :statuscode - :responsetime ms'
ExceptionFormatString = '(%1:s: %4:s) %0:s - %2:s'
ErrorResponseOptions.ErrorCode = 'ServerError'
ErrorResponseOptions.ErrorMessageFormat = 'Internal server error: %4:s'
end
end
object SparkleHttpSysDispatcher: TSparkleHttpSysDispatcher
Left = 112
Top = 66
end
end
unit App.Server.Module;
interface
uses
System.SysUtils, System.Classes, System.Generics.Collections,
Sparkle.Comp.Server, Sparkle.Comp.StaticServer, Sparkle.Comp.HttpSysDispatcher,
Sparkle.Module.Static, Sparkle.Comp.CompressMiddleware,
Sparkle.HttpServer.Module, Sparkle.HttpServer.Context,
Sparkle.Comp.LoggingMiddleware;
type
TAppServerModule = class(TDataModule)
SparkleHttpSysDispatcher: TSparkleHttpSysDispatcher;
SparkleStaticServer: TSparkleStaticServer;
SparkleStaticServerCompress: TSparkleCompressMiddleware;
SparkleStaticServerLogging: TSparkleLoggingMiddleware;
private
{ Private declarations }
public
{ Public declarations }
procedure StartAppServer(ABaseUrl: string);
end;
const
SERVER_PATH_SEGMENT = 'app';
var
AppServerModule: TAppServerModule;
implementation
uses
Sparkle.Middleware.Compress,
Common.Logging,
Common.Config;
{%CLASSGROUP 'Vcl.Controls.TControl'}
{$R *.dfm}
{ TAppServerModule }
procedure TAppServerModule.StartAppServer(ABaseUrl: string);
var
url: string;
begin
url := ABaseUrl;
if not url.EndsWith('/') then
url := url + '/';
url := url + SERVER_PATH_SEGMENT;
SparkleStaticServer.BaseUrl := url;
SparkleStaticServer.RootDir := serverConfig.webAppFolder;
SparkleHttpSysDispatcher.Start;
Logger.Log(1, Format('App server module listening at "%s", rootDir: %s', [url, serverConfig.webAppFolder]));
end;
end.
// The configuartion file for the program. Contains important info like the admin
// password and the secret token. Should likely move this to the ini file..
unit Common.Config;
interface
const
defaultServerUrl = 'http://localhost:2001/emsys/';
type
TServerConfig = class
private
Furl: string;
FJWTTokenSecret: string;
FAdminPassword: string;
FWebAppFolder: string;
FMemoLogLevel: Integer;
FFileLogLevel: Integer;
public
constructor Create;
property url: string read FUrl write FUrl;
property jwtTokenSecret: string read FJWTTokenSecret write FJWTTokenSecret;
property adminPassword: string read FAdminPassword write FAdminPassword;
property webAppFolder: string read FWebAppFolder write FWebAppFolder;
end;
procedure LoadServerConfig;
var
serverConfig: TServerConfig;
implementation
uses
Bcl.Json, System.SysUtils, System.IOUtils,
Common.Logging;
procedure LoadServerConfig;
var
configFile: string;
localConfig: TServerConfig;
begin
Logger.Log( 1, '--LoadServerConfig - start' );
configFile := 'serverconfig.json';
Logger.Log( 1, '-- Config file: ' + ConfigFile );
if TFile.Exists(ConfigFile) then
begin
Logger.Log( 1, '-- Config file found.' );
localConfig := TJson.Deserialize<TServerConfig>(TFile.ReadAllText(configFile));
Logger.Log( 1, '-- localConfig loaded from config file' );
serverConfig.Free;
Logger.Log( 1, '-- serverConfig.Free - called' );
serverConfig := localConfig;
Logger.Log( 1, '-- serverConfig := localConfig - called' );
end
else
begin
Logger.Log( 1, '-- Config file not found.' );
end;
Logger.Log( 1, '-------------------------------------------------------------' );
Logger.Log( 1, '-- serverConfig.Server url: ' + serverConfig.url );
Logger.Log( 1, '-- serverConfig.adminPassword: ' + serverConfig.adminPassword );
Logger.Log( 1, '-- serverConfig.jwtTokenSecret: ' + serverConfig.jwtTokenSecret );
Logger.Log( 1, '-- serverConfig.webAppFolder: ' + serverConfig.webAppFolder );
Logger.Log( 1, '--LoadServerConfig - end' );
end;
{ TServerConfig }
constructor TServerConfig.Create;
//var
// ConfigFile: string;
// ServerConfigStr: string;
begin
Logger.Log( 1, '--TServerConfig.Create - start' );
url := defaultServerUrl;
adminPassword := 'whatisthisusedfor';
jwtTokenSecret := 'super_secret0123super_secret4567';
webAppFolder := 'static';
// ServerConfigStr := Bcl.Json.TJson.Serialize( ServerConfig );
// ConfigFile := 'serverconfig.json';
// TFile.WriteAllText( ConfigFile, ServerConfigStr );
// Logger.Log( 1, 'ServerConfig saved to file: ' + ConfigFile );
Logger.Log( 1, '--TServerConfig.Create - end' );
end;
end.
unit Common.Logging;
interface
uses
Generics.Collections;
type
ILog = interface;
ILogAppender = interface;
ILogger = interface
['{4D667DD2-BE11-496B-B92A-C47E03520BD6}']
procedure Log(logLevel: integer; Msg: string); overload;
procedure Log(logLevel: integer; Log: ILog); overload;
procedure AddAppender(ALogAppender: ILogAppender);
function Appenders: TArray<ILogAppender>;
end;
ILogAppender = interface
['{A3B7D6FB-C75F-4BEF-8797-907B6FDAD5D2}']
procedure Send(logLevel: integer; Log: ILog);
end;
ILog = interface
['{8E9C6580-C099-47C0-8B1B-6D7A28EC4FA3}']
function GetMessage: string;
end;
TLogger = class( TInterfacedObject, ILogger )
strict private
FAppenders: TList<ILogAppender>;
public
constructor Create; overload;
constructor Create(ALogger: ILogger); overload;
destructor Destroy; override;
procedure Log(logLevel: integer; Msg: string); overload;
procedure Log(logLevel: integer; Log: ILog); overload;
procedure AddAppender(ALogAppender: ILogAppender);
function Appenders: TArray<ILogAppender>;
end;
TLogMessage = class( TInterfacedObject, ILog )
private
FMsg: string;
public
constructor Create(AMsg: string);
function GetMessage: string;
end;
function Logger: ILogger;
implementation
var
_Logger: ILogger;
function Logger: ILogger;
begin
Result := _Logger;
end;
{ TLogMessage }
constructor TLogMessage.Create(AMsg: string);
begin
FMsg := AMsg;
end;
function TLogMessage.GetMessage: string;
begin
Result := FMsg;
end;
{ TLogger }
procedure TLogger.AddAppender(ALogAppender: ILogAppender);
begin
FAppenders.Add(ALogAppender);
end;
function TLogger.Appenders: TArray<ILogAppender>;
var
I: integer;
begin
SetLength(Result, FAppenders.Count);
for I := 0 to FAppenders.Count - 1 do
Result[I] := FAppenders[I];
end;
constructor TLogger.Create(ALogger: ILogger);
var
Appender: ILogAppender;
begin
FAppenders := TList<ILogAppender>.Create;
if ALogger <> nil then
for Appender in ALogger.Appenders do
AddAppender(Appender);
end;
constructor TLogger.Create;
begin
Create(nil);
end;
destructor TLogger.Destroy;
begin
FAppenders.Free;
inherited;
end;
procedure TLogger.Log(logLevel: integer; Log: ILog);
var
Appender: ILogAppender;
begin
for Appender in FAppenders do
Appender.Send(logLevel, Log);
end;
procedure TLogger.Log(logLevel: integer; Msg: string);
begin
Log(logLevel, TLogMessage.Create(Msg));
end;
initialization
_Logger := TLogger.Create;
end.
unit Common.Middleware.Logging;
interface
uses
System.Classes, System.SysUtils,
Sparkle.HttpServer.Module,
Sparkle.HttpServer.Context,
Sparkle.Http.Headers,
Common.Logging;
type
TLoggingMiddleware = class(THttpServerMiddleware, IHttpServerMiddleware)
private
FLogger: ILogger;
function GetNewHttpRequestLog(Request: THttpServerRequest): ILog;
protected
procedure ProcessRequest(Context: THttpServerContext; Next: THttpServerProc); override;
public
constructor Create(ALogger: ILogger);
end;
THttpRequestLog = class( TInterfacedObject, ILog )
strict private
FMethod: string;
FUriPath: string;
FUriQuery: string;
FProtocol: string;
FRemoteIp: string;
FHeaders: string;
FContent: string;
FContentLength: Int64;
public
constructor Create(AMethod: string; AUriPath: string; AUriQuery: string;
AProtocol: string; ARemoteIp: string; AHeaders: string; AContent: string;
AContentLength: Int64);
function GetMessage: string;
end;
// THttpResponseLog = class( TInterfacedObject, ILog )
// strict private
// FMethod: string;
// FUriPath: string;
// FUriQuery: string;
// FProtocol: string;
// FRemoteIp: string;
// FHeaders: string;
// FContent: string;
// FContentLength: Int64;
// public
// constructor Create(AMethod: string; AUriPath: string; AUriQuery: string;
// AProtocol: string; ARemoteIp: string; AHeaders: string; AContent: string;
// AContentLength: Int64);
// function GetMessage: string;
// end;
implementation
{ TLoggingMiddleware }
constructor TLoggingMiddleware.Create(ALogger: ILogger);
begin
FLogger := TLogger.Create(ALogger);
end;
function TLoggingMiddleware.GetNewHttpRequestLog(
Request: THttpServerRequest): ILog;
var
Msg: TStrings;
Header: THttpHeaderInfo;
StringStream: TStringStream;
Headers, Content: string;
begin
Result := nil;
Msg := TStringList.Create;
try
if Length(Request.Headers.AllHeaders.ToArray) = 0 then
Headers := ''
else
begin
for Header in Request.Headers.AllHeaders do
Msg.Add(Header.Name + ': ' + Header.Value);
Headers := Msg.Text;
end;
finally
Msg.Free;
end;
StringStream := TStringStream.Create(Request.Content);
try
Content := StringStream.DataString
finally
StringStream.Free;
end;
Result := THttpRequestLog.Create(
Request.Method,
Request.Uri.Path,
Request.Uri.Query,
Request.Protocol,
Request.RemoteIp,
Headers,
Content,
Request.ContentLength
);
end;
procedure TLoggingMiddleware.ProcessRequest(Context: THttpServerContext;
Next: THttpServerProc);
var
RequestLogMessage: string;
begin
FLogger.Log(1, 'TLoggingMiddleware.ProcessRequest:');
RequestLogMessage := GetNewHttpRequestLog(Context.Request).GetMessage;
Context.Response.OnHeaders(
procedure(Resp: THttpServerResponse)
begin
FLogger.Log(1, Format('--Resp.StatusCode: %d Resp.StatusReason: %s on %s',
[Resp.StatusCode, Resp.StatusReason, RequestLogMessage]));
end
);
FLogger.Log(1, Format('--Request.RemoteIP: %s RequestLogMessage: %s',
[Context.Request.RemoteIp, RequestLogMessage]));
Next(Context);
end;
{ THttpRequestLog }
constructor THttpRequestLog.Create(AMethod, AUriPath, AUriQuery,
AProtocol, ARemoteIp, AHeaders, AContent: string; AContentLength: Int64);
begin
FMethod := AMethod;
FUriPath := AUriPath;
FUriQuery := AUriQuery;
FProtocol := AProtocol;
FRemoteIp := ARemoteIp;
FHeaders := AHeaders;
FContent := AContent;
FContentLength := AContentLength;
end;
function THttpRequestLog.GetMessage: string;
var
Msg: TStrings;
begin
Result := '';
Msg := TStringList.Create;
try
Msg.Add(Format('%s %s %s',
[
FMethod,
FUriPath + FUriQuery,
FProtocol,
FRemoteIp
]));
// if Not FHeaders.IsEmpty then
// Msg.Add(FHeaders);
// if (Not FContent.IsEmpty) then
// Msg.Add(FContent);
Result := Trim(Msg.Text);
finally
Msg.Free;
end;
end;
end.
object FData: TFData
Left = 0
Top = 0
Caption = 'FData'
ClientHeight = 442
ClientWidth = 628
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -12
Font.Name = 'Segoe UI'
Font.Style = []
TextHeight = 15
object DBAdvGrid1: TDBAdvGrid
Left = 54
Top = 138
Width = 400
Height = 250
ColCount = 2
DrawingStyle = gdsClassic
FixedColor = clWhite
RowCount = 2
FixedRows = 1
TabOrder = 0
ActiveCellFont.Charset = DEFAULT_CHARSET
ActiveCellFont.Color = 4474440
ActiveCellFont.Height = -12
ActiveCellFont.Name = 'Segoe UI'
ActiveCellFont.Style = [fsBold]
ActiveCellColor = 11565130
ActiveCellColorTo = 11565130
BorderColor = 11250603
ControlLook.FixedGradientFrom = clWhite
ControlLook.FixedGradientTo = clWhite
ControlLook.FixedGradientHoverFrom = clGray
ControlLook.FixedGradientHoverTo = clWhite
ControlLook.FixedGradientHoverMirrorFrom = clWhite
ControlLook.FixedGradientHoverMirrorTo = clWhite
ControlLook.FixedGradientHoverBorder = 11645361
ControlLook.FixedGradientDownFrom = clWhite
ControlLook.FixedGradientDownTo = clWhite
ControlLook.FixedGradientDownMirrorFrom = clWhite
ControlLook.FixedGradientDownMirrorTo = clWhite
ControlLook.FixedGradientDownBorder = 11250603
ControlLook.DropDownHeader.Font.Charset = DEFAULT_CHARSET
ControlLook.DropDownHeader.Font.Color = clWindowText
ControlLook.DropDownHeader.Font.Height = -11
ControlLook.DropDownHeader.Font.Name = 'Segoe UI'
ControlLook.DropDownHeader.Font.Style = []
ControlLook.DropDownHeader.Visible = True
ControlLook.DropDownHeader.Buttons = <>
ControlLook.DropDownFooter.Font.Charset = DEFAULT_CHARSET
ControlLook.DropDownFooter.Font.Color = clWindowText
ControlLook.DropDownFooter.Font.Height = -11
ControlLook.DropDownFooter.Font.Name = 'Segoe UI'
ControlLook.DropDownFooter.Font.Style = []
ControlLook.DropDownFooter.Visible = True
ControlLook.DropDownFooter.Buttons = <>
ControlLook.ToggleSwitch.BackgroundBorderWidth = 1.000000000000000000
ControlLook.ToggleSwitch.ButtonBorderWidth = 1.000000000000000000
ControlLook.ToggleSwitch.CaptionFont.Charset = DEFAULT_CHARSET
ControlLook.ToggleSwitch.CaptionFont.Color = clWindowText
ControlLook.ToggleSwitch.CaptionFont.Height = -12
ControlLook.ToggleSwitch.CaptionFont.Name = 'Segoe UI'
ControlLook.ToggleSwitch.CaptionFont.Style = []
ControlLook.ToggleSwitch.Shadow = False
Filter = <>
FilterDropDown.Font.Charset = DEFAULT_CHARSET
FilterDropDown.Font.Color = clWindowText
FilterDropDown.Font.Height = -12
FilterDropDown.Font.Name = 'Segoe UI'
FilterDropDown.Font.Style = []
FilterDropDown.TextChecked = 'Checked'
FilterDropDown.TextUnChecked = 'Unchecked'
FilterDropDownClear = '(All)'
FilterEdit.TypeNames.Strings = (
'Starts with'
'Ends with'
'Contains'
'Not contains'
'Equal'
'Not equal'
'Larger than'
'Smaller than'
'Clear')
FixedColWidth = 20
FixedRowHeight = 22
FixedFont.Charset = DEFAULT_CHARSET
FixedFont.Color = clWindowText
FixedFont.Height = -11
FixedFont.Name = 'Segoe UI'
FixedFont.Style = [fsBold]
FloatFormat = '%.2f'
HoverButtons.Buttons = <>
HTMLSettings.ImageFolder = 'images'
HTMLSettings.ImageBaseName = 'img'
Look = glCustom
PrintSettings.DateFormat = 'dd/mm/yyyy'
PrintSettings.Font.Charset = DEFAULT_CHARSET
PrintSettings.Font.Color = clWindowText
PrintSettings.Font.Height = -12
PrintSettings.Font.Name = 'Segoe UI'
PrintSettings.Font.Style = []
PrintSettings.FixedFont.Charset = DEFAULT_CHARSET
PrintSettings.FixedFont.Color = clWindowText
PrintSettings.FixedFont.Height = -12
PrintSettings.FixedFont.Name = 'Segoe UI'
PrintSettings.FixedFont.Style = []
PrintSettings.HeaderFont.Charset = DEFAULT_CHARSET
PrintSettings.HeaderFont.Color = clWindowText
PrintSettings.HeaderFont.Height = -12
PrintSettings.HeaderFont.Name = 'Segoe UI'
PrintSettings.HeaderFont.Style = []
PrintSettings.FooterFont.Charset = DEFAULT_CHARSET
PrintSettings.FooterFont.Color = clWindowText
PrintSettings.FooterFont.Height = -12
PrintSettings.FooterFont.Name = 'Segoe UI'
PrintSettings.FooterFont.Style = []
PrintSettings.PageNumSep = '/'
SearchFooter.ColorTo = clNone
SearchFooter.FindNextCaption = 'Find &next'
SearchFooter.FindPrevCaption = 'Find &previous'
SearchFooter.Font.Charset = DEFAULT_CHARSET
SearchFooter.Font.Color = clWindowText
SearchFooter.Font.Height = -12
SearchFooter.Font.Name = 'Segoe UI'
SearchFooter.Font.Style = []
SearchFooter.HighLightCaption = 'Highlight'
SearchFooter.HintClose = 'Close'
SearchFooter.HintFindNext = 'Find next occurrence'
SearchFooter.HintFindPrev = 'Find previous occurrence'
SearchFooter.HintHighlight = 'Highlight occurrences'
SearchFooter.MatchCaseCaption = 'Match case'
SearchFooter.ResultFormat = '(%d of %d)'
SelectionColor = 13744549
SelectionTextColor = clWindowText
SortSettings.HeaderColor = clWhite
SortSettings.HeaderColorTo = clWhite
SortSettings.HeaderMirrorColor = clWhite
SortSettings.HeaderMirrorColorTo = clWhite
Version = '2.5.1.23'
AutoCreateColumns = True
AutoRemoveColumns = True
Columns = <
item
Borders = []
BorderPen.Color = clSilver
ButtonHeight = 18
CheckFalse = 'N'
CheckTrue = 'Y'
Color = clWindow
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -12
Font.Name = 'Segoe UI'
Font.Style = []
HeaderFont.Charset = DEFAULT_CHARSET
HeaderFont.Color = 3881787
HeaderFont.Height = -12
HeaderFont.Name = 'Segoe UI'
HeaderFont.Style = []
PrintBorders = [cbTop, cbLeft, cbRight, cbBottom]
PrintFont.Charset = DEFAULT_CHARSET
PrintFont.Color = clWindowText
PrintFont.Height = -12
PrintFont.Name = 'Segoe UI'
PrintFont.Style = []
Width = 20
end
item
Borders = []
BorderPen.Color = clSilver
ButtonHeight = 18
CheckFalse = 'N'
CheckTrue = 'Y'
Color = clWindow
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -12
Font.Name = 'Segoe UI'
Font.Style = []
HeaderFont.Charset = DEFAULT_CHARSET
HeaderFont.Color = 3881787
HeaderFont.Height = -12
HeaderFont.Name = 'Segoe UI'
HeaderFont.Style = []
PrintBorders = [cbTop, cbLeft, cbRight, cbBottom]
PrintFont.Charset = DEFAULT_CHARSET
PrintFont.Color = clWindowText
PrintFont.Height = -12
PrintFont.Name = 'Segoe UI'
PrintFont.Style = []
Width = 64
end>
InvalidPicture.Data = {
055449636F6E0000010001002020200000000000A81000001600000028000000
2000000040000000010020000000000000100000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000006A6A6B256A6A6B606A6A6B946A6A6BC06A6A6BE1
6A6A6BF86A6A6BF86A6A6BE16A6A6BC06A6A6B946A6A6B606A6A6B2500000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
000000006A6A6B407575769E787879F19F9F9FF6C0C0C0FDDADADAFFEDEDEEFF
FBFBFBFFFBFBFBFFEDEDEEFFDADADAFFC0C0C0FD9F9F9FF6787879F17575769E
6A6A6B4000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000006A6A6B22
7C7C7C98888889F0BDBDBDFCE9E9EBFED9D9E9FEB5B5DDFE8B8BCDFE595AB7FF
3739A8FF2B2CA4FF4A49B1FF7171C1FFA1A2D7FFD3D3E8FFEAEAEBFEBEBEBFFC
888889F07C7C7C986A6A6B220000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000006A6A6B43838383D8
B7B7B8FAECECEFFEC0C0DFFF7977C4FF2221A0FF12129BFF1010A4FF0C0CA8FF
0A0AACFF0A0AB4FF0A0AB9FF0D0DBEFF0F0FB1FF1111A6FF5656B8FFAEADDCFF
ECECEFFEB7B7B8FA838383D86A6A6B4300000000000000000000000000000000
00000000000000000000000000000000000000006A6A6B4E878788EAD3D3D3FE
CACAE8FF4443B0FF171799FF11119CFF0C0C98FF0B0B9BFF0B0BA0FF0A0AA6FF
0909ACFF0909B2FF0808BAFF0707BFFF0B09C8FF0D0DCEFF1111CCFF1010AFFF
4A49B2FFCFCFEBFFD3D3D3FE878788EA6A6A6B4E000000000000000000000000
000000000000000000000000000000006A6A6B43878788EAE1E1E1FFA8A8DAFF
2323A0FF15159CFF0D0D92FF0C0C95FF0C0C99FF0B0B9EFF0B0BA0FF0A0AA6FF
0909ACFF0909B2FF0808B8FF0808BCFF0808C3FF0C0CC9FF0C0CD0FF0D0DD6FF
1313CFFF2222A9FFAFAFDEFFE1E1E1FF878788EA6A6A6B430000000000000000
0000000000000000000000006A6A6B22838383D8D3D3D3FEA8A8D9FF2020A4FF
13139BFF0C0C92FF0C0C95FF0C0C97FF0C0C99FF0B0B9EFF0B0BA0FF0A0AA4FF
0A0AA9FF0909B0FF0808B4FF0808BBFF0707C0FF0A0AC6FF0909CCFF0C0CD3FF
0D0DD8FF1313D3FF1A1AA8FFAEADDEFFD4D4D4FE838383D86A6A6B2200000000
0000000000000000000000007C7C7C98B7B7B8FACACAE8FF2524A3FF13139FFF
0C0C97FF0C0C95FF0C0C95FF0C0C91FF0C0C95FF0B0B9EFF0B0BA0FF0A0AA4FF
0A0AA8FF0909ADFF0909B2FF0808B8FF0808BCFF0707C0FF0808BCFF0707C5FF
0C0CD3FF0D0DD7FF1212D1FF2020A7FFCDCDEBFFB8B8B9FA7C7C7C9800000000
00000000000000006A6A6B40888889F0ECECEFFE4545B1FF1616A4FF0B0B9BFF
0C0C99FF0C0C96FF3333A2FFB9B9D0FF393A9BFF0C0C95FF0B0BA1FF0A0AA4FF
0A0AA7FF0A0AABFF0909B0FF0808B4FF0808B7FF2F2FC2FFAEAEE2FF4B4BBFFF
0707BEFF0B0BD1FF0C0CD3FF1413CCFF4848B1FFECECEFFE888889F06A6A6B40
00000000000000007575769EBFBFBFFD9B9BD5FF1C1CA6FF0C0CA1FF0B0B9FFF
0B0B9AFF3535A7FFB5B5BEFFE6E6DFFFEDEDEFFF3C3C9CFF0C0C97FF0A0AA4FF
0A0AA6FF0A0AA9FF0909ADFF0909B0FF2626B5FFCECEDEFFFFFFFBFFEEEEF1FF
4848BAFF0808BCFF0A0ACDFF0B0BCEFF1111ABFFBEC0E0FFBFC0BFFD7575769E
000000006A6A6B25787879F1E3E3E5FE4646B2FF1414A8FF0A0AA4FF0B0BA0FF
2121A9FFBDBDCAFFD0D0C8FFC5C5C5FFE3E3E1FFEDEDEFFF3E3E9EFF0C0C98FF
0A0AA6FF0A0AA8FF0A0AA9FF2B2BB0FFC0C0CDFFEAEAE2FFEBEBEBFFFEFEF8FF
EDEDEEFF2828BDFF0707C4FF0809C7FF0F0FC4FF8788CBFFEBEBECFE79797AF1
6A6A6B256A6A6B609D9E9DF6D6D7E4FF3A3AB3FF1212ADFF0A0AA8FF0A0AA4FF
1313AAFFABABCFFFD6D6CBFFCACACAFFC6C6C6FFE4E4E0FFEEEEEFFF3F3FA0FF
0C0C99FF0A0AA6FF2828ABFFB2B2BFFFD8D8CEFFD6D6D8FFE0E0E0FFF6F5EDFF
D1D1EDFF1E1CC0FF0707BEFF0707BFFF0707C0FF2120AAFFD3D5E9FE9FA0A0F6
6A6A6B606A6A6B94BDBDBDFBBABBDCFF3A39B7FF2F2FB8FF0909ADFF0A0AA9FF
0A0AA6FF1515ACFFADADCFFFD6D6CBFFCBCBCAFFC6C6C6FFE4E4E1FFEEEEEFFF
3838A1FF2222A2FFACABB8FFC8C8C0FFC7C7C8FFCDCDCDFFE1E1D9FFC8CAE1FF
2424BCFF0808B4FF0808B9FF0808BAFF0808BBFF0F0EABFFA1A2D5FEC0C0C0FC
6A6A6B946A6A6BC0D9D8D7FE9999D1FF3838BBFF3636BCFF2C2CB7FF0909ADFF
0A0AA9FF0A0AA4FF1C1CAFFFB1B1CFFFD6D6CBFFCCCCCBFFC7C7C7FFE4E4E1FF
ECECEEFFACACB7FFC2C2BCFFBEBEBFFFC0C0C0FFCFCFC6FFC1C1D5FF2727B8FF
0909ACFF0909B2FF0909B2FF0909B4FF0808B4FF0E0EB5FF6E6EBFFFD9D9D9FE
6A6A6BC06A6A6BE1EBEAEBFF7D7CC7FF3838BFFF3434BEFF3536BEFF2A2AB8FF
0909B0FF0909ACFF0A0AA8FF1C1CB1FFB2B2D0FFD7D7CCFFCBCBCBFFC7C7C8FF
C8C8C3FFC6C6C3FFBFBFC1FFBDBDBDFFC5C5BCFFB8B8CEFF2929B5FF0A0AA8FF
0909ACFF0909ADFF0909AFFF0909AFFF0909AFFF0C0CB0FF4747AFFFECECEDFF
6A6A6BE16A6A6BF8F9F9F9FF6666C1FF3838C4FF3535C2FF3434C0FF3535BEFF
3030BCFF1313B4FF0909ADFF0A0AA8FF1E1EB3FFAAAAD0FFD3D3CDFFCCCCCCFF
C8C8C8FFC3C3C3FFC2C2C1FFC4C4BFFFB2B2CBFF2B2BB4FF0A0AA4FF0A0AA8FF
0A0AA8FF0A0AA9FF0A0AA9FF0A0AA9FF0A0AA9FF0B0BA9FF3131A6FFFAFAFAFF
6A6A6BF86A6A6BF8FBFBFBFF5959BEFF3B3BCAFF3A3AC8FF3737C4FF3535C2FF
3636C0FF3636BEFF2323B8FF0909B1FF0A0AA7FF4949BEFFD6D6D4FFD3D3D1FF
CDCDCDFFC8C8C8FFC4C4C3FFEDEDEDFF5F5FB3FF0C0C98FF0A0AA7FF0A0AA6FF
0A0AA6FF0A0AA6FF0A0AA4FF0A0AA6FF0A0AA4FF0B0BA4FF2D2DA6FFFBFBFBFF
6A6A6BF86A6A6BE1EDEDEEFF7F80CBFF4041CCFF3C3CCAFF3A3AC8FF383AC8FF
3838C4FF3636C2FF3939C0FF2123B7FF4A4AC2FFCBCBDEFFE0E0DCFFD6D6D6FF
D2D2D3FFCDCDCEFFC9C9C9FFE2E2E1FFF1F1F2FF4242A3FF0C0C99FF0A0AA4FF
0A0AA4FF0A0AA4FF0B0BA3FF0B0BA3FF0B0BA1FF0E0EA1FF4443B0FFEDEDEEFF
6A6A6BE16A6A6BC0DADADAFF9C9BD5FE4949CDFF3E3DD0FF3C3DCEFF3C3CCAFF
3A3AC8FF3B39C7FF2828BDFF5C5CCCFFE5E5EDFFF4F4EDFFE5E5E6FFDEDEDEFF
DCDCD9FFD9D9D3FFCDCDCDFFC8C8C8FFE5E5E1FFF1F1F3FF3F3FA0FF0C0C99FF
0A0AA4FF0B0BA1FF0B0BA0FF0B0BA0FF0B0B9FFF1313A2FF6B6BC0FFDADADAFF
6A6A6BC06A6A6B94C0C0C0FDBDBAE1FE5655CFFF4141D4FF3F3FD2FF3F3FCEFF
3D3DCCFF2C2AC3FF5E5ED3FFEBEBF6FFFFFFFAFFF1F1F1FFEDEDEEFFF0F0E9FF
D2D2E6FFBDBDD6FFDADAD3FFCFCFCFFFC9C9CAFFE5E5E2FFF1F1F3FF3A3AA0FF
0C0C98FF0B0BA3FF0B0B9FFF0B0B9EFF0B0B9EFF1C1CA4FF9C9CD3FFC1C1C1FD
6A6A6B946A6A6B609F9F9FF6DAD9EAFF6B6BCFFF4444D7FF4143D6FF4242D3FF
3434CDFF6464DBFFEFEFFFFFFFFFFFFFFCFCFCFFF6F6F6FFFCFCF4FFE2E1F0FF
5050CCFF4040C1FFC3C3DBFFE1E1D8FFD4D4D5FFCFCFCFFFE8E8E5FFF2F2F4FF
4040A2FF0C0C99FF0F0FA2FF0F0FA0FF0F0F9DFF302FA9FFD1D1E8FEA0A0A0F6
6A6A6B606A6A6B25787879F1E9E9EBFEA7A7DAFF6060DBFF4547DBFF3C3CD6FF
5857DEFFF2F2FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE8E8F8FF5B5BD4FF
2828BDFF2A2BBDFF4949C5FFC3C3DBFFE4E4DAFFD5D5D5FFCECED0FFE8E8E5FF
F4F4F4FF4949AFFF2121A6FF2A2AA6FF2C2BA9FF5557B8FFEAEAECFE787879F1
6A6A6B25000000007575769EBEBEBEFDC9CAE6FF7A79DBFF4C4CDFFF4141DBFF
5757E0FFEAEAFFFFFFFFFFFFFFFFFFFFFFFFFFFFE8E7FFFF5B5BD7FF2E2EC6FF
3E3EC9FF3A3AC5FF2C2EC1FF4A49C8FFC2C2DDFFE3E3DAFFD5D5D4FFDADAD3FF
CACBD9FF4747BBFF2525ADFF2C2BACFF3332AEFFA5A4D8FFBFBFBFFD7575769E
00000000000000006A6A6B40888889F0ECECEFFE9696D6FF7B7BE3FF4D4BE0FF
4141DBFF5F5FE6FFE7E7FFFFFFFFFFFFE9E9FFFF5A5ADCFF3333CAFF4242CFFF
4040CBFF3D3DC9FF3D3EC8FF3030C2FF4848C9FFC0C0DDFFECEEDEFFD0D0E0FF
5554C7FF2828B3FF3232B4FF3434B1FF5453B7FFECECEFFE888889F06A6A6B40
0000000000000000000000007C7C7C98B7B7B8FAD0D0ECFF8F8FDBFF6868E3FF
4E4EE2FF3E40DBFF6565E9FFB2B2F7FF6565E4FF393BD2FF4646D7FF4343D4FF
4343D1FF4242CFFF4040CBFF3F3FCAFF3333C4FF4E4ECBFF9E9EE2FF5C5BCFFF
292ABAFF3636BCFF3938B8FF3F3EB1FFCBCBE9FFB7B7B8FA7C7C7C9800000000
0000000000000000000000006A6A6B22838383D8D3D3D3FEB5B5E2FF9E9EE4FF
6766E2FF4E50E6FF4646E0FF3D3DDAFF4444DCFF4B4BDCFF4848DBFF4847D9FF
4646D5FF4443D3FF4343D1FF4242CFFF4143CDFF3A3AC8FF312FC5FF3535C3FF
3C3CC3FF3D3DBEFF403FB5FFACACDCFFD3D3D3FE838383D86A6A6B2200000000
000000000000000000000000000000006A6A6B43878788EAE1E1E1FFB5B5E2FF
A7A6E4FF7877E5FF5151E5FF4F4FE4FF4E4EE2FF4D4DE0FF4C4CDEFF4B4BDCFF
4949DBFF4848D7FF4747D5FF4545D3FF4545D1FF4343CFFF4242CCFF3F3FCBFF
4343C2FF4645B6FFADADDCFFE1E1E1FF878788EA6A6A6B430000000000000000
00000000000000000000000000000000000000006A6A6B4E878788EAD3D3D3FE
D0D0ECFFAAA9DFFFA2A2ECFF6565E3FF5151E6FF4F4FE4FF4F4DE4FF4D4DE0FF
4D4DDFFF4D4DDCFF4C49DBFF4A4AD8FF4749D6FF4747D4FF4949CBFF4B4BC3FF
8E8ED0FFCDCCE8FFD3D3D3FE878788EA6A6A6B4E000000000000000000000000
0000000000000000000000000000000000000000000000006A6A6B43838383D8
B7B7B8FAECECEFFEC3C2E5FFADAEE1FF9E9DE8FF6F6FE0FF5C5CE1FF5452E2FF
5051E1FF4F4FDFFF4F4FDBFF5150D6FF5151CFFF5F5FC8FFA1A1D3FEC7C8E0FE
E4E4E7FEB7B7B8FA838383D86A6A6B4300000000000000000000000000000000
000000000000000000000000000000000000000000000000000000006A6A6B22
7C7C7C98888889F0BFBFBFFDEBEBECFED8D9EBFEBDBDE4FEA8A7DCFF9695D7FF
8886D4FF7F7DCEFF8C8BD2FFA1A2D9FFC0BEE1FED9D9EAFEEAEAECFEBFBFBFFD
888889F07C7C7C986A6A6B220000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
000000006A6A6B407575769E787879F19F9F9FF6C0C0C0FDDADADAFFEDEDEEFF
FBFBFBFFFBFBFBFFEDEDEEFFDADADAFFC0C0C0FD9F9F9FF6787879F17575769E
6A6A6B4000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000006A6A6B256A6A6B606A6A6B946A6A6BC06A6A6BE1
6A6A6BF86A6A6BF86A6A6BE16A6A6BC06A6A6B946A6A6B606A6A6B2500000000
0000000000000000000000000000000000000000000000000000000000000000
00000000FFC003FFFF0000FFFC00003FF800001FF000000FE0000007C0000003
C000000380000001800000010000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000080000001
80000001C0000003C0000003E0000007F000000FF800001FFC00003FFF0000FF
FFC003FF}
ShowUnicode = False
ColWidths = (
20
64)
RowHeights = (
22
22)
end
object DataSource1: TDataSource
Left = 516
Top = 63
end
end
unit Data;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, AdvUtil, Data.DB, Vcl.Grids, AdvObj,
BaseGrid, AdvGrid, DBAdvGrid, MemDS, DBAccess, Uni;
type
TFData = class(TForm)
DBAdvGrid1: TDBAdvGrid;
DataSource1: TDataSource;
private
{ Private declarations }
public
{ Public declarations }
end;
var
FData: TFData;
implementation
{$R *.dfm}
end.
object FMain: TFMain
Left = 0
Top = 0
Caption = 'emSystemsWebsiteServer'
ClientHeight = 583
ClientWidth = 764
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OnClose = FormClose
DesignSize = (
764
583)
TextHeight = 13
object memoInfo: TMemo
Left = 16
Top = 40
Width = 744
Height = 535
Anchors = [akLeft, akTop, akRight, akBottom]
ReadOnly = True
TabOrder = 0
end
object btnSwaggerUI: TButton
Left = 299
Top = 8
Width = 128
Height = 25
Caption = 'Launch SwaggerUI'
TabOrder = 1
OnClick = btnSwaggerUIClick
end
object btnExit: TButton
Left = 671
Top = 8
Width = 75
Height = 25
Caption = 'Exit'
TabOrder = 2
OnClick = btnExitClick
end
object initTimer: TTimer
Interval = 250
OnTimer = initTimerTimer
Left = 159
Top = 405
end
object ExeInfo1: TExeInfo
Version = '1.6.1.1'
Left = 246
Top = 406
end
end
unit Main;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, Winapi.ShellApi,
System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
Vcl.StdCtrls, Vcl.ExtCtrls, System.IniFiles, ExeInfo, Common.Logging, Common.Config;
type
TFMain = class(TForm)
btnExit: TButton;
initTimer: TTimer;
memoInfo: TMemo;
ExeInfo1: TExeInfo;
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure initTimerTimer(Sender: TObject);
procedure btnExitClick(Sender: TObject);
procedure btnSwaggerUIClick(Sender: TObject);
private
procedure StartServers;
end;
var
FMain: TFMain;
implementation
uses
Api.Server.Module, Sparkle.Utils, Api.Database, App.Server.Module, Api.Service, Api.ServiceImpl;
{$R *.dfm}
{ TFMain }
procedure TFMain.btnExitClick(Sender: TObject);
begin
Close;
end;
procedure TFMain.btnSwaggerUIClick(Sender: TObject);
begin
ShellExecute(Handle, 'open', PChar(TSparkleUtils.CombineUrlFast(ApiServerModule.XDataServer.BaseUrl, 'swaggerui')), nil, nil, SW_SHOWNORMAL);
end;
procedure TFMain.initTimerTimer(Sender: TObject);
begin
initTimer.Enabled := False;
Caption := Caption + ' ver ' + ExeInfo1.FileVersion;
Logger.Log(1, 'Exe version: ' + ExeInfo1.FileVersion);
try
ServerConfig := TServerConfig.Create;
LoadServerConfig;
StartServers;
except
on E: Exception do
begin
Logger.Log(5, 'Failed to initialize server: ' + E.Message);
memoInfo.Lines.Add('Failed to start server: ' + E.Message);
end;
end;
end;
procedure TFMain.StartServers;
var
appServerUrl: string;
begin
Logger.Log(1, '');
Logger.Log(1, '******************************************************');
Logger.Log(1, ' emWebsite XData Server ');
Logger.Log(1, Format(' Version: %s ', [FMain.ExeInfo1.FileVersion]));
Logger.Log(1, ' by EM Systems, Inc. ');
Logger.Log(1, '******************************************************');
Logger.Log(1, '');
try
ApiServerModule := TApiServerModule.Create(Self);
ApiServerModule.StartApiServer(ServerConfig.url);
Logger.Log(1, 'API Server started at: ' + ApiServerModule.XDataServer.BaseUrl);
AppServerModule := TAppServerModule.Create(Self);
AppServerModule.StartAppServer(ServerConfig.url);
Logger.Log(1, 'App Server started at: ' + appServerUrl);
Logger.Log(1, '');
except
on E: Exception do
begin
Logger.Log(5, 'Failed to start server modules: ' + E.Message);
memoInfo.Lines.Add('Failed to start server modules: ' + E.Message);
end;
end;
Logger.Log(1, '--- StartServers: Complete ---');
end;
procedure TFMain.FormClose(Sender: TObject; var Action: TCloseAction);
begin
ApiServerModule.Free;
AppServerModule.Free;
serverConfig.Free;
end;
end.
object DMConnection: TDMConnection
Height = 256
Width = 337
object ApiConnection: TXDataWebConnection
URL = 'http://localhost:2002/website/'
Left = 48
Top = 80
end
object xdwcApi: TXDataWebClient
Connection = ApiConnection
Left = 187
Top = 84
end
end
unit ConnectionModule;
interface
uses
System.SysUtils, System.Classes,
WEBLib.Modules,
XData.Web.Connection, XData.Web.Client;
type
TVersionCheckCallback = reference to procedure(success: Boolean; errorMessage: string);
TDMConnection = class(TWebDataModule)
ApiConnection: TXDataWebConnection;
xdwcApi: TXDataWebClient;
procedure ApiConnectionError(error: TXDataWebConnectionError);
procedure XDataWebClientError(error: TXDataClientError);
private
configLoaded: Boolean;
versionCheckPending: Boolean;
pendingCallback: TVersionCheckCallback;
procedure LoadConfig(loadedProc: TProc<Boolean>);
public
const clientVersion = '1.0.3';
procedure InitApp(readyProc: TProc);
procedure SetClientConfig(callback: TVersionCheckCallback);
end;
var
DMConnection: TDMConnection;
implementation
uses
JS, Web,
XData.Web.Request,
XData.Web.Response;
{$R *.dfm}
procedure TDMConnection.ApiConnectionError(error: TXDataWebConnectionError);
begin
if versionCheckPending and Assigned(pendingCallback) then
begin
versionCheckPending := False;
pendingCallback(False, 'Unable to reach server to verify version. Please reload.');
pendingCallback := nil;
end;
end;
procedure TDMConnection.XDataWebClientError(error: TXDataClientError);
begin
if versionCheckPending and Assigned(pendingCallback) then
begin
versionCheckPending := False;
pendingCallback(False, 'Unable to verify version. Please reload.');
pendingCallback := nil;
end;
end;
procedure TDMConnection.LoadConfig(loadedProc: TProc<Boolean>);
procedure onSuccess(response: IHttpResponse);
var
obj: TJSObject;
apiUrl: string;
begin
apiUrl := '';
if response.StatusCode = 200 then
begin
obj := TJSObject(TJSJSON.parse(response.ContentAsText));
apiUrl := JS.toString(obj['ApiUrl']);
end;
if apiUrl <> '' then
begin
ApiConnection.URL := apiUrl;
configLoaded := True;
loadedProc(True);
end
else
loadedProc(False);
end;
procedure onError;
begin
loadedProc(False);
end;
var
conn: TXDataWebConnection;
begin
if configLoaded then
begin
loadedProc(True);
Exit;
end;
conn := TXDataWebConnection.Create(nil);
try
conn.SendRequest(THttpRequest.Create('config/config.json'), @onSuccess, @onError);
finally
conn.Free;
end;
end;
procedure TDMConnection.InitApp(readyProc: TProc);
begin
if Assigned(readyProc) then
readyProc;
end;
procedure TDMConnection.SetClientConfig(callback: TVersionCheckCallback);
procedure configLoadedProc(success: Boolean);
begin
if not success then
begin
callback(False, 'Missing or invalid config/config.json (ApiUrl).');
Exit;
end;
pendingCallback := callback;
versionCheckPending := True;
xdwcApi.Connection := ApiConnection;
ApiConnection.Open(
procedure
begin
xdwcApi.RawInvoke('IApiService.VerifyVersion', [clientVersion],
procedure(response: TXDataClientResponse)
var
jsonResult: TJSObject;
errorMsg: string;
begin
versionCheckPending := False;
jsonResult := TJSObject(response.Result);
if Assigned(jsonResult) and jsonResult.HasOwnProperty('error') then
errorMsg := string(jsonResult['error'])
else
errorMsg := '';
if errorMsg <> '' then
pendingCallback(False, errorMsg)
else
pendingCallback(True, '');
pendingCallback := nil;
end);
end);
end;
begin
LoadConfig(@configLoadedProc);
end;
end.
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta content="width=device-width, initial-scale=1" name="viewport"/>
<noscript>Your browser does not support JavaScript!</noscript>
<link href="data:;base64,=" rel="icon"/>
<title>Envoy International Foreign Exchange Services</title>
<link href="https://cdnjs.cloudflare.com/ajax/libs/flag-icon-css/2.3.1/css/flag-icon.min.css" rel="stylesheet"/>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"/>
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.0/css/all.min.css" rel="stylesheet"/>
<link crossorigin="anonymous" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js" type="text/javascript"></script>
<script async="async" defer="defer" src="https://www.google.com/recaptcha/api.js"></script>
<link href="css/App.css" rel="stylesheet" type="text/css"/>
<link href="css/spinner.css" rel="stylesheet" type="text/css"/>
<script src="$(ProjectName).js" type="text/javascript"></script>
</head>
<body>
<script type="text/javascript">rtl.run();</script>
</body>
</html>
unit Site.Footer;
interface
uses
System.SysUtils, WEBLib.WebTools, WEBLib.Controls, JS, Web;
procedure InjectFooter;
procedure SetFooterVersion(const versionText: string);
implementation
const
// Note: keep this in ONE place. Edit footer here, all pages update.
FooterHtml =
'<footer class="bg-dark text-light">' +
' <div class="container-main py-4">' +
' <div class="row gy-3 align-items-start text-center text-lg-start">' +
' <div class="col-lg-4 d-flex justify-content-center justify-content-lg-start">' +
' <a href="#FHome" class="navbar-brand m-0">' +
' <img src="images/EM_Logo_2c66a0.png" alt="EM_Logo" style="height: 30px;">' +
' </a>' +
' </div>' +
' <div class="col-lg-4">' +
' <ul class="list-unstyled mb-0 small">' +
' <li class="mb-1"><a href="#FHome" id="homefooter" class="link-light text-decoration-none">Home</a></li>' +
' <li class="mb-1"><a href="#FAboutUs" id="aboutusfooter" class="link-light text-decoration-none">About Us</a></li>' +
' <li><a href="#FContactUs" id="contactusfooter" class="link-light text-decoration-none">Contact Us</a></li>' +
' </ul>' +
' </div>' +
' <div class="col-lg-4">' +
' <address class="mb-0 small opacity-75">' +
' 4043 Maple Rd, Suite 211<br>' +
' Amherst, NY 14226<br>' +
' (716) 836-4910' +
' </address>' +
' </div>' +
' </div>' +
' <div class="border-top border-secondary mt-3 pt-3">' +
' <div class="d-flex flex-column flex-sm-row justify-content-center align-items-center gap-2 text-center small opacity-75">' +
' <div> 2011-2026 EM Systems Inc</div>' +
' <span class="d-none d-sm-inline"></span>' +
' <span id="lbl_version"></span>' +
' </div>' +
' </div>' +
' </div>' +
'</footer>';
procedure InjectFooter;
var
el: TJSHTMLElement;
begin
el := TJSHTMLElement(document.getElementById('site_footer'));
if Assigned(el) then
el.innerHTML := FooterHtml;
end;
procedure SetFooterVersion(const versionText: string);
var
el: TJSHTMLElement;
begin
el := TJSHTMLElement(document.getElementById('lbl_version'));
if Assigned(el) then
el.textContent := versionText;
end;
end.
unit Site.Navbar;
interface
procedure InjectNavbar;
implementation
uses
JS, Web;
const
NavbarHtml =
'<div class="envoy-header">' +
' <div class="container envoy-container">' +
' <nav class="navbar navbar-expand-lg py-0">' +
' <div class="container-fluid px-0">' +
' <span class="navbar-brand envoy-brand me-lg-4 mb-0">' +
' <img src="images/e_head2_01.png" alt="Envoy International">' +
' </span>' +
' <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#envoyNavbar"' +
' aria-controls="envoyNavbar" aria-expanded="false" aria-label="Toggle navigation">' +
' <span class="navbar-toggler-icon"></span>' +
' </button>' +
' <div class="collapse navbar-collapse" id="envoyNavbar">' +
' <ul class="navbar-nav ms-lg-auto envoy-nav">' +
' <li class="nav-item"><span class="nav-link">Home</span></li>' +
' <li class="nav-item"><span class="nav-link">Information Guide</span></li>' +
' <li class="nav-item"><span class="nav-link">Business Services</span></li>' +
' <li class="nav-item"><span class="nav-link">Compliance</span></li>' +
' <li class="nav-item"><span class="nav-link">Industry Links</span></li>' +
' <li class="nav-item"><span class="nav-link">Contact Us</span></li>' +
' </ul>' +
' </div>' +
' </div>' +
' </nav>' +
' </div>' +
'</div>';
procedure InjectNavbar;
var
el: TJSHTMLElement;
begin
el := TJSHTMLElement(document.getElementById('site_nav'));
if Assigned(el) then
el.innerHTML := NavbarHtml;
end;
end.
unit Utils;
interface
uses
System.Classes, SysUtils, JS, Web, WEBLib.Forms;
procedure ShowStatusMessage(const AMessage, AClass: string; const AElementId: string);
procedure HideStatusMessage(const AElementId: string);
procedure ShowSpinner(SpinnerID: string);
procedure HideSpinner(SpinnerID: string);
procedure ShowNotificationModal(msg: string);
implementation
procedure ShowStatusMessage(const AMessage, AClass: string; const AElementId: string);
var
StatusMessage: TJSHTMLElement;
begin
StatusMessage := TJSHTMLElement(document.getElementById(AElementId));
if Assigned(StatusMessage) then
begin
if AMessage = '' then
begin
StatusMessage.style.setProperty('display', 'none');
StatusMessage.className := '';
StatusMessage.innerHTML := '';
end
else
begin
StatusMessage.innerHTML := AMessage;
StatusMessage.className := 'alert ' + AClass;
StatusMessage.style.setProperty('display', 'block');
end
end
else
console.log('Error: Status message element not found');
end;
procedure HideStatusMessage(const AElementId: string);
var
StatusMessage: TJSHTMLElement;
begin
StatusMessage := TJSHTMLElement(document.getElementById(AElementId));
if Assigned(StatusMessage) then
begin
StatusMessage.style.setProperty('display', 'none');
StatusMessage.className := '';
StatusMessage.innerHTML := '';
end
else
console.log('Error: Status message element not found');
end;
procedure ShowSpinner(SpinnerID: string);
var
SpinnerElement: TJSHTMLElement;
begin
SpinnerElement := TJSHTMLElement(document.getElementById(SpinnerID));
if Assigned(SpinnerElement) then
begin
// Move spinner to the <body> if it's not already there
asm
if (SpinnerElement.parentNode !== document.body) {
document.body.appendChild(SpinnerElement);
}
end;
SpinnerElement.classList.remove('d-none');
SpinnerElement.classList.add('d-block');
end;
end;
procedure HideSpinner(SpinnerID: string);
var
SpinnerElement: TJSHTMLElement;
begin
SpinnerElement := TJSHTMLElement(document.getElementById(SpinnerID));
if Assigned(SpinnerElement) then
begin
SpinnerElement.classList.remove('d-block');
SpinnerElement.classList.add('d-none');
end;
end;
procedure ShowNotificationModal(msg: string);
begin
asm
var modal = document.getElementById('contact_notification_modal');
var label = document.getElementById('contact_notification_modal_body');
var closeBtn = document.getElementById('btn_modal_close');
if (label) label.innerText = msg;
// Ensure modal is a direct child of <body>
if (modal && modal.parentNode !== document.body) {
document.body.appendChild(modal);
}
// Button simply closes the modal
if (closeBtn) {
closeBtn.onclick = function () {
var existing = bootstrap.Modal.getInstance(modal);
if (existing) {
existing.hide();
}
};
}
// Show the Bootstrap modal
var bsModal = new bootstrap.Modal(modal, { keyboard: false });
bsModal.show();
end;
end;
end.
object FAboutUs: TFAboutUs
Width = 1058
Height = 730
Caption = 'EM Systems, Inc'
CSSLibrary = cssBootstrap
ElementFont = efCSS
Font.Charset = ANSI_CHARSET
Font.Color = clBlack
Font.Height = -11
Font.Name = 'Arial'
Font.Style = []
ParentFont = False
OnShow = WebFormShow
end
<div class="d-flex flex-column min-vh-100">
<div id="site_nav"></div>
<div class="container-fluid px-0">
<div class="hero-section-aboutus bg-dark text-white text-center">
<img src="images/niagara.jpg" alt="Our Story Image" class="img-fluid hero-image-aboutus">
<div class="hero-overlay-aboutus">
<div class="row justify-content-center">
<div class="col-md-8 col-lg-6"> <!-- Adjust the column sizes as needed -->
<div class="text-wrapper-aboutus mx-auto p-3 p-md-5 rounded shadow">
<h2>Our Story</h2>
<p class="fs-6">
Located in Buffalo, New York, EM Systems has designed and delivered a wide range of custom software
solutions across multiple industries, with the strongest emphasis on Public Safety Systems. Today, more
than 75 organizations throughout New York State depend on EM Systems applications to support their
communities and agencies.
EM Systems is distinguished by its ability to develop tailored software solutions that address the
unique requirements of each client. Our mission is to deliver reliable, efficient software that enhances
and streamlines existing business or agency operations. In addition to deep expertise in software
development, we bring extensive experience in analyzing, refining, and improving operational workflows
to drive greater efficiency and effectiveness.
</p>
</div>
</div>
</div>
</div>
</div>
</div>
<div id="site_footer"></div>
</div>
unit View.AboutUs;
interface
uses
System.SysUtils, System.Classes, WEBLib.Graphics, WEBLib.Forms, Vcl.StdCtrls,
WEBLib.StdCtrls, Vcl.Controls, WEBLib.Dialogs, Vcl.Imaging.pngimage,
WEBLib.ExtCtrls, WEBLib.Controls, Web, JS, WEBLib.Menus, WEBLib.WebCtrls;
type
TFAboutUs = class(TWebForm)
[async]
procedure WebFormShow(Sender: TObject);
private
{ Private declarations }
public
procedure NavScrollSizing;
end;
var
FAboutUs: TFAboutUs;
implementation
{$R *.dfm}
uses
View.Home,
View.ContactUs,
View.CustomSoftware,
View.PublicSafety,
Site.Navbar,
Site.Footer,
ConnectionModule,
View.RecordsManagement;
procedure TFAboutUs.WebFormShow(Sender: TObject);
begin
Application.ThemeColor := clTMSWEB;
InjectNavbar;
InjectFooter;
SetFooterVersion('ver - ' + TDMConnection.clientVersion);
NavScrollSizing;
end;
procedure TFAboutUs.NavScrollSizing;
begin
asm
window.addEventListener('scroll', function() {
var navbar = document.querySelector('.em-navbar-wrap .navbar');
var logo = document.querySelector('.em-brand img');
var scrollDistance = 50; // Adjust based on your preference
if (window.scrollY > scrollDistance) {
navbar.classList.add('scrolled');
logo.classList.add('scrolled-logo');
} else {
navbar.classList.remove('scrolled');
logo.classList.remove('scrolled-logo');
}
});
end;
end;
initialization
RegisterClass(TFAboutUs);
end.
\ No newline at end of file
object FContactUs: TFContactUs
Width = 930
Height = 802
Caption = 'EM Systems, Inc'
CSSLibrary = cssBootstrap
ElementFont = efCSS
Font.Charset = ANSI_CHARSET
Font.Color = clBlack
Font.Height = -11
Font.Name = 'Arial'
Font.Style = []
ParentFont = False
OnShow = WebFormShow
object edtName: TWebEdit
Left = 24
Top = 40
Width = 100
Height = 25
TabStop = False
ElementID = 'name'
ElementFont = efCSS
ElementPosition = epRelative
HeightPercent = 100.000000000000000000
HideSelection = False
WidthPercent = 100.000000000000000000
end
object edtEmail: TWebEdit
Left = 24
Top = 75
Width = 100
Height = 25
TabStop = False
ElementID = 'email'
ElementFont = efCSS
ElementPosition = epRelative
HeightPercent = 100.000000000000000000
HideSelection = False
WidthPercent = 100.000000000000000000
end
object edtSubject: TWebEdit
Left = 24
Top = 112
Width = 100
Height = 25
TabStop = False
ElementID = 'subject'
ElementFont = efCSS
ElementPosition = epRelative
HeightPercent = 100.000000000000000000
HideSelection = False
WidthPercent = 100.000000000000000000
end
object memoMessage: TWebMemo
Left = 28
Top = 151
Width = 464
Height = 303
TabStop = False
ElementID = 'message'
ElementFont = efCSS
ElementPosition = epRelative
HeightPercent = 100.000000000000000000
Role = 'null'
SelLength = 0
SelStart = 0
WidthPercent = 100.000000000000000000
end
object btnSubmit: TWebButton
Left = 36
Top = 482
Width = 100
Height = 25
Caption = 'Send Email'
ElementID = 'submit'
ElementFont = efCSS
ElementPosition = epRelative
HeightPercent = 100.000000000000000000
Role = 'button'
TabStop = False
WidthPercent = 100.000000000000000000
OnClick = btnSubmitClick
end
object xdwcEmail: TXDataWebClient
Connection = DMConnection.ApiConnection
OnError = xdwcEmailError
Left = 412
Top = 512
end
end
<div class="d-flex flex-column min-vh-100">
<div id="site_nav"></div>
<!-- CONTACT US SECTION -->
<main class="container pt-5 mt-5 flex-grow-1">
<div class="row g-4">
<div class="col-lg-6">
<h2 class="mb-3">Contact Us</h2>
<hr class="mb-4">
<form>
<div class="mb-3">
<label for="name" class="form-label">Name*</label>
<input type="text" class="form-control" id="name" required>
</div>
<div class="mb-3">
<label for="email" class="form-label">Email*</label>
<input type="email" class="form-control" id="email" required>
</div>
<div class="mb-3">
<label for="subject" class="form-label">Subject*</label>
<input type="text" class="form-control" id="subject" required>
</div>
<div class="mb-3">
<label for="message" class="form-label">Your Message*</label>
<textarea class="form-control" id="message" rows="4" required></textarea>
</div>
<button type="submit" class="btn btn-primary" id="submit">Submit</button>
</form>
<div id="card_status_message" class="alert mt-3 d-none" role="alert"></div>
</div>
<div class="col-lg-6">
<h2 class="mb-3">EM Systems Inc.</h2>
<hr class="mb-4">
<p class="mb-1">4043 Maple Rd, Suite 211 | Amherst, NY 14226</p>
<p class="mb-3"><strong>Phone:</strong> (716) 836-4910</p>
<div class="ratio ratio-4x3 shadow-sm rounded overflow-hidden">
<iframe
src="https://www.google.com/maps/embed?pb=!1m14!1m8!1m3!1d11673.673539086676!2d-78.8117081!3d42.990524!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x89d37240e1804e2f%3A0xce8f13b6c4c68386!2sE%20M%20Systems%20Inc!5e0!3m2!1sen!2sus!4v1714072248166!5m2!1sen!2sus"
style="border:0;"
allowfullscreen=""
loading="lazy"
referrerpolicy="no-referrer-when-downgrade">
</iframe>
</div>
</div>
</div>
</main>
<div id="site_footer" class="mt-auto"></div>
</div>
<div id="spinner" class="position-fixed top-50 start-50 translate-middle d-none" style="z-index: 1100;">
<div class="lds-roller">
<div></div><div></div><div></div><div></div>
<div></div><div></div><div></div><div></div>
</div>
</div>
<div class="modal fade" id="contact_notification_modal" tabindex="-1" aria-labelledby="contact_notification_modal_label" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content shadow-lg">
<div class="modal-header">
<h5 class="modal-title" id="contact_notification_modal_label">Info</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body fs-6 fw-bold" id="contact_notification_modal_body">
Please contact EMSystems to solve the issue.
</div>
<div class="modal-footer justify-content-center">
<button type="button" id="btn_modal_close" class="btn btn-primary">Close</button>
</div>
</div>
</div>
</div>
unit View.ContactUs;
interface
uses
System.SysUtils, System.Classes, WEBLib.Graphics, WEBLib.Forms, Vcl.StdCtrls,
WEBLib.StdCtrls, Vcl.Controls, WEBLib.Dialogs, Vcl.Imaging.pngimage,
WEBLib.ExtCtrls, WEBLib.Controls, Web, JS, WEBLib.Menus, WEBLib.WebCtrls,
XData.Web.Connection, XData.Web.Client, Data.DB, Utils,
XData.Web.JsonDataset, XData.Web.Dataset, Vcl.Grids,
WEBLib.DBCtrls, WEBLib.DB, WEBLib.Grids, WEBLib.CDS, WEBLib.REST,
WEBLib.WebTools, System.NetEncoding, WebLib.RegularExpressions,
WEBLib.Toast, XData.Web.Request, XData.Web.Response;
type
TFContactUs = class(TWebForm)
edtName: TWebEdit;
edtEmail: TWebEdit;
edtSubject: TWebEdit;
memoMessage: TWebMemo;
btnSubmit: TWebButton;
xdwcEmail: TXDataWebClient;
procedure btnSubmitClick(Sender: TObject);
procedure WebFormShow(Sender: TObject);
procedure xdwcEmailError(Error: TXDataClientError);
private
{ Private declarations }
function IsInputValid: Boolean;
function IsEmailValid(const email: String): Boolean;
[async] procedure SendEmail;
public
procedure NavScrollSizing;
end;
var
FContactUs: TFContactUs;
implementation
{$R *.dfm}
uses
ConnectionModule,
View.Home,
View.PublicSafety,
View.RecordsManagement,
View.CustomSoftware,
Site.Navbar,
Site.Footer,
View.AboutUs;
procedure TFContactUs.WebFormShow(Sender: TObject);
begin
Application.ThemeColor := clTMSWEB;
InjectNavbar;
InjectFooter;
SetFooterVersion('ver - ' + TDMConnection.clientVersion);
NavScrollSizing;
end;
procedure TFContactUs.xdwcEmailError(Error: TXDataClientError);
begin
ShowNotificationModal('Error when attempting to send: ' + error.ErrorMessage);
end;
procedure TFContactUs.NavScrollSizing;
begin
asm
window.addEventListener('scroll', function() {
var navbar = document.querySelector('.em-navbar-wrap .navbar');
var logo = document.querySelector('.em-brand img');
var scrollDistance = 50;
if (window.scrollY > scrollDistance) {
navbar.classList.add('scrolled');
logo.classList.add('scrolled-logo');
} else {
navbar.classList.remove('scrolled');
logo.classList.remove('scrolled-logo');
}
});
end;
end;
function TFContactUs.IsEmailValid(const email: string): Boolean;
const
pattern = '^[^\s@]+@[^\s@]+\.[^\s@]+$';
begin
Result := TRegEx.IsMatch(email.Trim, pattern);
end;
function TFContactUs.IsInputValid: Boolean;
var
nameOk: Boolean;
emailOk: Boolean;
subjectOk: Boolean;
messageOk: Boolean;
begin
nameOk := edtName.Text.Trim <> '';
emailOk := IsEmailValid(edtEmail.Text);
subjectOk := edtSubject.Text.Trim <> '';
messageOk := memoMessage.Text.Trim <> '';
Result := nameOk and emailOk and subjectOk and messageOk;
end;
procedure TFContactUs.btnSubmitClick(Sender: TObject);
begin
if not IsInputValid then
begin
ShowNotificationModal('Please complete all fields and ensure the email address is valid.');
Exit;
end;
if not DMConnection.ApiConnection.Connected then
begin
DMConnection.ApiConnection.Open(
procedure
begin
SendEmail;
end);
Exit;
end;
SendEmail;
end;
procedure TFContactUs.SendEmail;
begin
xdwcEmail.RawInvoke('IApiService.SendEmail',
[edtName.Text, edtEmail.Text, edtSubject.Text, memoMessage.Text],
procedure(response: TXDataClientResponse)
begin
ShowNotificationModal('Your message has been sent successfully. Please check your email for a response in the next 48 hours.');
edtName.Text := '';
edtEmail.Text := '';
edtSubject.Text := '';
memoMessage.Text := '';
end);
end;
initialization
RegisterClass(TFContactUs);
end.
object FCustomSoftware: TFCustomSoftware
Width = 640
Height = 480
Caption = 'EM Systems, Inc'
CSSLibrary = cssBootstrap
ElementFont = efCSS
Font.Charset = ANSI_CHARSET
Font.Color = clBlack
Font.Height = -11
Font.Name = 'Arial'
Font.Style = []
ParentFont = False
OnShow = WebFormShow
end
<div class="d-flex flex-column min-vh-100">
<div id="site_nav"></div>
<!-- HERO SECTION -->
<div class="container-fluid px-0">
<div class="page-hero-section bg-dark text-white text-center">
<img
src="images\computer_code.jpg"
alt="Hero Image"
class="img-fluid hero-image"
/>
<div
class="hero-overlay d-flex justify-content-center align-items-center"
>
<div class="text-wrapper">
<h1 class="display-4">Custom Software</h1>
</div>
</div>
</div>
</div>
<!--MAIN CONTAINER-->
<div class="container-main">
<div class="learn-boxes">
<!-- CUSTOM SOFTWARE BOX 1 -->
<div class="row mb-4 g-4 align-items-center bg-white shadow-sm rounded">
<div class="col-md-12">
<div class="p-3 text-center">
<p class="mx-auto" style="max-width: 850px">
EM Systems started as a custom software development company. Our
Public Safety and Records Management Notification System solutions
started as custom software development projects. Over the years,
we have developed many custom programs that are currently in use
by our customers to help manage and run their operations.
</p>
</div>
</div>
</div>
<!-- CUSTOM SOFTWARE BOX 2 -->
<div class="row mb-4 g-4 align-items-center bg-grey shadow-sm rounded">
<div class="col-md-12">
<div class="p-3 text-center">
<h2>AutoPark</h2>
<p class="mx-auto" style="max-width: 850px">
AutoPark is a parking permit and ticket management system. It
streamlines and coordinates the process and procedures of managing
a parking area. From parking permits, tickets, online payments,
and appeals, this solution has it all when it comes to parking
management. This program is in use by a State University of New
York college to manage their parking services operation.
</p>
</div>
</div>
</div>
<!-- CUSTOM SOFTWARE BOX 3 -->
<div class="row mb-4 g-4 align-items-center bg-white shadow-sm rounded">
<div class="col-md-12">
<div class="p-3 text-center">
<h2>TreeStar</h2>
<p class="mx-auto" style="max-width: 850px">
TreeStar is a full suite of tools to manage wholesale Christmas
trees and accessories. It has tools for load and route planning,
carrier and shipping oversight, customer support, sales analysis,
invoicing, and field management. It also has EDI support for
automatic processing of purchase orders, sales, and payments.
</p>
</div>
</div>
</div>
<!-- CUSTOM SOFTWARE BOX 4 -->
<div class="row mb-4 g-4 align-items-center bg-grey shadow-sm rounded">
<div class="col-md-12">
<div class="p-3 text-center">
<h2>HSTManager</h2>
<p class="mx-auto" style="max-width: 850px">
This is a workflow management program for Home Sleep Studies
(HST). It is used by a Sleep Medicine company to manage the HSTs’
flow of information through the process of scheduling, sleep
testing, diagnosing, and generating the medical reports.
HSTManager interfaces to the Electronic Medical Records system and
the Diagnostic Sleep Study Software to automatically exchange the
data needed to allow sleep lab technicians and clinicians to track
the HSTs from start to end. It starts by retrieving the list of
scheduled HSTs and end by uploading the final physician report to
the patient medical record.
</p>
</div>
</div>
</div>
<!-- CUSTOM SOFTWARE BOX 5 -->
<div class="row mb-4 g-4 align-items-center bg-white shadow-sm rounded">
<div class="col-md-12">
<div class="p-3 text-center">
<h2>PawnShopPro</h2>
<p class="mx-auto" style="max-width: 850px">
PawnShopPro simplifies your pawn shop record keeping, billing, and
inventory management. It manages your loans, repairs, sales, and
layaways, and automatically processes interest charges and late
notices.
</p>
</div>
</div>
</div>
<!-- CUSTOM SOFTWARE BOX 6 -->
<div class="row mb-4 g-4 align-items-center bg-grey shadow-sm rounded">
<div class="col-md-12">
<div class="p-3 text-center">
<h2>TransportStar</h2>
<p class="mx-auto" style="max-width: 850px">
TransportStar is everything you need to manage your trucking
company. Track your shipments and calculate costs for your
same-day and next-day LTL and TL shipments, generate invoices and
track payments, and manage your expenses for your fleet of trucks.
</p>
</div>
</div>
</div>
</div>
</div>
<div id="site_footer"></div>
</div>
unit View.CustomSoftware;
interface
uses
System.SysUtils, System.Classes, WEBLib.Graphics, WEBLib.Forms, Vcl.StdCtrls,
WEBLib.StdCtrls, Vcl.Controls, WEBLib.Dialogs, Vcl.Imaging.pngimage,
WEBLib.ExtCtrls, WEBLib.Controls, Web, JS, WEBLib.Menus, WEBLib.WebCtrls;
type
TFCustomSoftware = class(TWebForm)
[async]
procedure WebFormShow(Sender: TObject);
private
{ Private declarations }
public
procedure NavScrollSizing;
end;
var
FCustomSoftware: TFCustomSoftware;
implementation
{$R *.dfm}
uses
View.AboutUs,
View.ContactUs,
View.Home,
View.PublicSafety,
Site.Navbar,
Site.Footer,
ConnectionModule,
View.RecordsManagement;
procedure TFCustomSoftware.WebFormShow(Sender: TObject);
begin
Application.ThemeColor := clTMSWEB;
InjectNavbar;
InjectFooter;
SetFooterVersion('ver - ' + TDMConnection.clientVersion);
NavScrollSizing;
end;
procedure TFCustomSoftware.NavScrollSizing;
begin
asm
window.addEventListener('scroll', function() {
var navbar = document.querySelector('.em-navbar-wrap .navbar');
var logo = document.querySelector('.em-brand img');
var scrollDistance = 50; // Adjust based on your preference
if (window.scrollY > scrollDistance) {
navbar.classList.add('scrolled');
logo.classList.add('scrolled-logo');
} else {
navbar.classList.remove('scrolled');
logo.classList.remove('scrolled-logo');
}
});
end;
end;
initialization
RegisterClass(TFCustomSoftware);
end.
\ No newline at end of file
object FHome: TFHome
Width = 1290
Height = 1090
Caption = 'EM Systems, Inc'
CSSLibrary = cssBootstrap
ElementFont = efCSS
Font.Charset = ANSI_CHARSET
Font.Color = clBlack
Font.Height = -11
Font.Name = 'Arial'
Font.Style = []
ParentFont = False
OnShow = WebFormShow
end
<div class="envoy-page min-vh-100 d-flex flex-column">
<div id="site_nav"></div>
<main class="flex-grow-1">
<section class="envoy-main py-4 py-md-5">
<div class="container envoy-container">
<div class="row justify-content-center">
<div class="col-12">
<div class="envoy-card shadow-sm p-4 p-md-5">
<p class="envoy-subhead mb-4">
The Envoy International website is currently undergoing maintenance.
</p>
<p class="envoy-text mb-4">
We apologize for the inconvenience. If you have any questions or would like a quotation on a currency transaction,
please contact Envoy International using the information below.
</p>
<div class="row g-4">
<div class="col-md-6">
<p class="envoy-section-title mb-2">Contact Envoy International</p>
<p class="envoy-text mb-1">
<strong>Phone</strong> (800) 755-5614
</p>
<p class="envoy-text mb-1">
<strong>Fax</strong> (800) 294-1173
</p>
<p class="envoy-text mb-0">
<strong>Email</strong>
<span>info@envoyinternational.com</span>
</p>
</div>
<div class="col-md-6">
<p class="envoy-section-title mb-2">Office Information</p>
<p class="envoy-text mb-3">
<strong>Envoy International</strong><br>
1972 Military Road<br>
Niagara Falls, NY 14304
</p>
<p class="envoy-text mb-0">
<strong>Envoy International Management Ltd.</strong><br>
427 Garrison Road<br>
Fort Erie, Ontario L2A 6E6
</p>
</div>
</div>
</div>
<div class="envoy-footer mt-3">
<b>Note:</b> Not all services described herein are available in all areas.
Please call us for specific information about services available in your area.
<br>
© Envoy International. © Envoy International Management Ltd. All rights reserved.
</div>
<div class="text-center py-3">
<span class="envoy-managed">Website Managed by EM Systems, Inc.</span>
</div>
</div>
</div>
</div>
</section>
</main>
</div>
unit View.Home;
interface
uses
System.SysUtils, System.Classes, WEBLib.Graphics, WEBLib.Forms,
WEBLib.Controls;
type
TFHome = class(TWebForm)
procedure WebFormShow(Sender: TObject);
end;
var
FHome: TFHome;
implementation
{$R *.dfm}
uses
Site.Navbar;
procedure TFHome.WebFormShow(Sender: TObject);
begin
Application.ThemeColor := clWhite;
InjectNavbar;
end;
initialization
RegisterClass(TFHome);
end.
object FPublicSafety: TFPublicSafety
Width = 640
Height = 480
Caption = 'EM Systems, Inc'
CSSLibrary = cssBootstrap
ElementFont = efCSS
Font.Charset = ANSI_CHARSET
Font.Color = clBlack
Font.Height = -11
Font.Name = 'Arial'
Font.Style = []
ParentFont = False
OnShow = WebFormShow
end
<div class="d-flex flex-column min-vh-100">
<div id="site_nav"></div>
<!-- HERO SECTION -->
<div class="container-fluid px-0">
<div class="page-hero-section bg-dark text-white text-center">
<img
src="images\computer_code.jpg"
alt="Hero Image"
class="img-fluid hero-image"
/>
<div
class="hero-overlay d-flex justify-content-center align-items-center"
>
<div class="text-wrapper">
<h1 class="display-4">Integrated Public Safety Software</h1>
</div>
</div>
</div>
</div>
<!--MAIN CONTAINER-->
<div class="container-main">
<div class="learn-boxes">
<!-- PUBLIC SAFETY BOX 1 -->
<div class="row mb-4 g-4 align-items-center bg-white shadow-sm rounded">
<div class="col-md-12">
<div class="p-3">
<div class="text-center">
<p class="mx-auto" style="max-width: 850px">
EM Systems started developing our integrated public safety
software in the early 1990s, by working closely with local law
enforcement agencies and dispatch centers to create highly
intuitive, dynamic and customizable solutions. Our public safety
software suite has been developed to meet the national and state
requirements and ensure secure data management, access control,
and encryption for public safety and law enforcement operations.
</p>
<p class="mx-auto" style="max-width: 850px">
EM Systems is fully committed to meeting and exceeding CJIS
requirements across every component of the Public Safety
Software programs, providing agencies with secure, compliant,
and reliable solutions that can be trusted to support
mission-critical operations.
</p>
</div>
<div class="container">
<h3 class="text-center">List of Programs</h3>
<div class="row justify-content-center">
<div
class="col-sm-6 col-md-auto mb-2 border-top pt-3"
style="max-width: 350px"
>
<ul class="text-start">
<li>
Computer Aided Dispatch (CAD) - Police, Fire &amp; EMS
</li>
<li>Mapping w/GPS tracking &amp; AVL</li>
<li>Records Management System (RMS)</li>
<li>
Mobile Data System (MDS) w/Police Reports &amp; Arrest
</li>
<li>
Livescan Fingerprinting w/ Booking and Civil submissions
</li>
</ul>
</div>
<div
class="col-sm-6 col-md-auto text-md-start border-top pt-3"
style="max-width: 350px"
>
<ul>
<li>Jail Management System (JMS)</li>
<li>
iPhone &amp; Android Apps - CAD Monitor &amp; Data Access
</li>
<li>FireRMS w/NERIS reporting</li>
<li>
Summons &amp; Accidents MDS modules (Tracs replacement)
</li>
<li>Discovery module w/Interface to DEMS</li>
<li>Interfaces to State &amp; Federal Systems</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- PUBLIC SAFETY BOX 2 -->
<div class="row mb-4 g-4 align-items-center bg-grey shadow-sm rounded">
<div class="col-md-12">
<div class="p-3">
<div class="text-center">
<h2>Computer Aided Dispatch</h2>
<p class="mx-auto" style="max-width: 850px">
EM Systems CAD solution is a powerful, scalable platform
designed to support an unlimited number of police, fire, and
emergency medical services (EMS) agencies in both single-agency
and multi-agency environments. Built to enhance operational
awareness and responder safety, the system delivers advanced
incident mapping, real-time vehicle tracking, seamless field
communications, and proactive alerts for potential hazards at
specific locations.
</p>
</div>
<div class="container">
<h3 class="text-center">System Features</h3>
<div class="row justify-content-center">
<div
class="col-sm-6 col-md-auto mb-2 border-top pt-3"
style="max-width: 250px"
>
<ul class="text-start">
<li>Real-time Call Taking / Dispatching</li>
<li>Complaint and Incident Mapping</li>
<li>911 Interface</li>
<li>Field Communications</li>
</ul>
</div>
<div
class="col-sm-6 col-md-auto text-md-start border-top pt-3"
style="max-width: 250px"
>
<!-- Set max-width and use Bootstrap's sizing -->
<ul>
<li>Messaging and Bulletin Boards</li>
<li>Alerts and Hazards Notification</li>
<li>Supports Silent Dispatch</li>
<li>Integration with LEMS</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- PUBLIC SAFETY BOX 3 -->
<div class="row mb-4 g-4 align-items-center bg-white shadow-sm rounded">
<div class="col-md-12">
<div class="p-3">
<div class="text-center">
<h2>Record Management System</h2>
<p class="mx-auto" style="max-width: 850px">
Our Records Management System (RMS) is a powerful menu-driven
database system than can be used to track everything from arrest
/ booking information to court records (e.g., orders of
protection, summons, etc.), and personnel information (e.g.,
training, promotions, etc.). The system provides for enhanced
patrol, investigative, and administrative processes and provides
a wealth of valuable analysis information. Users can create
reports based on data from any field in the software to help
prevent and solve crimes, allocate resources, and much more.
</p>
</div>
<div class="container">
<h3 class="text-center">System Features</h3>
<div class="row justify-content-center">
<div
class="col-sm-6 col-md-auto mb-2 border-top pt-3"
style="max-width: 250px"
>
<!-- Set max-width and use Bootstrap's sizing -->
<ul class="text-start">
<li>
Master Name including detailed data on persons, addresses,
vehicles, etc.
</li>
<li>Tracking incident activity</li>
<li>Search and audit capabilities</li>
<li>Investigations / case management</li>
</ul>
</div>
<div
class="col-sm-6 col-md-auto text-md-start border-top pt-3"
style="max-width: 250px"
>
<!-- Set max-width and use Bootstrap's sizing -->
<ul>
<li>Crime analysis</li>
<li>Personnel information / management</li>
<li>Narrative with spell check</li>
<li>Reporting capabilities</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- PUBLIC SAFETY BOX 4 -->
<div class="row mb-4 g-4 align-items-center bg-grey shadow-sm rounded">
<div class="col-md-12">
<div class="p-3">
<div class="text-center">
<h2>Mobile Data System</h2>
<p class="mx-auto" style="max-width: 850px">
The Mobile Data System (MDS) we created provides multi-agency
mobile data communications interoperability. The system provides
mobile users the ability to perform onsite data checks,
including plate checks, driver checks, vehicle data checks, and
name checks. The system also provides detailed information on
the complaint, allows the user to view all units and their
status, and enables the user to send and receive messages from
other users.
</p>
</div>
<div class="container">
<h3 class="text-center">System Features</h3>
<div class="row justify-content-center">
<div
class="col-sm-6 col-md-auto mb-2 border-top pt-3"
style="max-width: 250px"
>
<!-- Set max-width and use Bootstrap's sizing -->
<ul class="text-start">
<li>
Wireless multi-agency interoperable data communications of
real-time dispatch and complaint information
</li>
<li>
Onsite data checks (including name, plate, driver,
vehicle, warrants)
</li>
<li>
Police reporting module to enter information into RMS from
the field
</li>
</ul>
</div>
<div
class="col-sm-6 col-md-auto text-md-start border-top pt-3"
style="max-width: 250px"
>
<!-- Set max-width and use Bootstrap's sizing -->
<ul>
<li>View all available units and their status</li>
<li>
Send and receive messages from other units / agencies
</li>
<li>
Supports AirCard and / or Packet Radio Modem RF Technology
</li>
<li>Dispatch link (complaint and status updates)</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- PUBLIC SAFETY BOX 5 -->
<div class="row mb-4 g-4 align-items-center bg-white shadow-sm rounded">
<div class="col-md-12">
<div class="p-3">
<div class="text-center">
<h2>Automated Vehicle Location System</h2>
<p class="mx-auto" style="max-width: 850px">
Our AVL System is a real-time automatic vehicle location system
used to pinpoint the location of equipped vehicles and track
their movement. The system allows you to visually see the
location of units in the field, enhance dispatch operations, and
increase officer safety.
</p>
</div>
<div class="container">
<h3 class="text-center">System Features</h3>
<div class="row justify-content-center">
<div
class="col-sm-6 col-md-auto mb-2 border-top pt-3"
style="max-width: 250px"
>
<!-- Set max-width and use Bootstrap's sizing -->
<ul class="text-start">
<li>Real-time GPS Vehicle Tracking</li>
<li>Mapping Application for Dispatch and Mobile</li>
</ul>
</div>
<div
class="col-sm-6 col-md-auto text-md-start border-top pt-3"
style="max-width: 250px"
>
<!-- Set max-width and use Bootstrap's sizing -->
<ul>
<li>XML-based Communications</li>
<li>Complaint and Crime Mapping</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- PUBLIC SAFETY BOX 6 -->
<div class="row mb-4 g-4 align-items-center bg-grey shadow-sm rounded">
<div class="col-md-12">
<div class="p-3">
<div class="text-center">
<h2>Jail Management System</h2>
<p class="mx-auto" style="max-width: 850px">
EM Systems’ Jail Management System (JMS) is designed to
effectively assist in the management of a detention facility of
any size. The system can operate independently or as a component
of EM Systems’ Law Enforcement Management System (LEMS). It can
also be integrated with other justice information systems from
third-party vendors. As with all &nbsp;&nbsp;EM Systems’
software, the JMS can be customized to meet the unique needs of
your agency.
</p>
</div>
<div class="container">
<h3 class="text-center">System Features</h3>
<div class="row justify-content-center">
<div
class="col-sm-6 col-md-auto mb-2 border-top pt-3"
style="max-width: 250px"
>
<!-- Set max-width and use Bootstrap's sizing -->
<ul class="text-start">
<li>Facilitates booking procedures</li>
<li>Access to historical data</li>
<li>Medical and suicide screening</li>
<li>Release date calculations and processing</li>
</ul>
</div>
<div
class="col-sm-6 col-md-auto text-md-start border-top pt-3"
style="max-width: 250px"
>
<!-- Set max-width and use Bootstrap's sizing -->
<ul>
<li>Property and custody management</li>
<li>Powerful search capabilities</li>
<li>Automated reporting</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div id="site_footer"></div>
</div>
unit View.PublicSafety;
interface
uses
System.SysUtils, System.Classes, WEBLib.Graphics, WEBLib.Forms, Vcl.StdCtrls,
WEBLib.StdCtrls, Vcl.Controls, WEBLib.Dialogs, Vcl.Imaging.pngimage,
WEBLib.ExtCtrls, WEBLib.Controls, Web, JS, WEBLib.Menus, WEBLib.WebCtrls;
type
TFPublicSafety = class(TWebForm)
procedure WebFormShow(Sender: TObject);
[async]
private
{ Private declarations }
public
procedure NavScrollSizing;
end;
var
FPublicSafety: TFPublicSafety;
implementation
{$R *.dfm}
uses
View.AboutUs,
View.ContactUs,
View.CustomSoftware,
View.Home,
Site.Navbar,
Site.Footer,
ConnectionModule,
View.RecordsManagement;
procedure TFPublicSafety.WebFormShow(Sender: TObject);
begin
Application.ThemeColor := clTMSWEB;
InjectNavbar;
InjectFooter;
SetFooterVersion('ver - ' + TDMConnection.clientVersion);
NavScrollSizing;
end;
procedure TFPublicSafety.NavScrollSizing;
begin
asm
window.addEventListener('scroll', function() {
var navbar = document.querySelector('.em-navbar-wrap .navbar');
var logo = document.querySelector('.em-brand img');
var scrollDistance = 50; // Adjust based on your preference
if (window.scrollY > scrollDistance) {
navbar.classList.add('scrolled');
logo.classList.add('scrolled-logo');
} else {
navbar.classList.remove('scrolled');
logo.classList.remove('scrolled-logo');
}
});
end;
end;
initialization
RegisterClass(TFPublicSafety);
end.
\ No newline at end of file
object FRecordsManagement: TFRecordsManagement
Width = 640
Height = 480
Caption = 'EM Systems, Inc'
CSSLibrary = cssBootstrap
Font.Charset = ANSI_CHARSET
Font.Color = clBlack
Font.Height = -11
Font.Name = 'Arial'
Font.Style = []
ParentFont = False
OnShow = WebFormShow
end
<div class="d-flex flex-column min-vh-100">
<div id="site_nav"></div>
<!-- HERO SECTION -->
<div class="container-fluid px-0">
<div class="page-hero-section bg-dark text-white text-center" id="FRecordsManagement" tabindex="-1">
<img src="images\computer_code.jpg" alt="Hero Image" class="img-fluid hero-image">
<div class="hero-overlay d-flex justify-content-center align-items-center">
<div class="text-wrapper">
<h1 class="display-4">Records Management Notification System</h1>
</div>
</div>
</div>
</div>
<!--MAIN CONTAINER-->
<div class="container-main">
<div class="learn-boxes">
<!-- RECORDS MANAGEMENT BOX 1 -->
<div class="row mb-4 g-4 align-items-center bg-white shadow-sm rounded">
<div class="col-md-12">
<div class="p-3 text-center">
<h2>Records Retention Notification</h2>
<p class="mx-auto" style="max-width: 850px;">With multi departmental government organizations constantly in
a state of flux, the Records Management Notification System is designed to provide consistent and informed
alerts to aid governments in following records management best practices.
This system is designed to help Town Clerk’s, Police Departments, and Records Managers fulfill records
retention mandates by providing alerts to complete standard records management practices. This software
will aid in the management of day-to-day records and help local government meet records retention
requirements.
The Records Retention RMNS is fully aligned with the New York State LG-1 schedule, integrating
comprehensive retention and disposition policies that streamline the management of both electronic and
paper records through a task-based notification system.
</p>
</div>
</div>
</div>
<!-- RECORDS MANAGEMENT BOX 2 -->
<div class="row mb-4 g-4 align-items-center bg-gray shadow-sm rounded">
<div class="col-md-12">
<div class="p-3 text-center">
<h2>Legal Hold Notices</h2>
<p class="mx-auto" style="max-width: 850px;">The Legal Holds Notices RMNS module is designed to notify
government officials and records managers of a current obligation to preserve evidence and ensure critical
information remains intact and accessible for review under a legal hold. The notification will remind key
stakeholders that legal holds are current and in place; preventing governments from receiving penalties
for non-compliance.</p>
</div>
</div>
</div>
<!-- RECORDS MANAGEMENT BOX 3 -->
<div class="row mb-4 g-4 align-items-center bg-white shadow-sm rounded">
<div class="col-md-12">
<div class="p-3 text-center">
<h2>Freedom of Information Law (FOIL)</h2>
<p class="mx-auto" style="max-width: 850px;">The FOIL Requests RMNS module provides automated notifications
to government employees when a FOIL request is received and alerts users to the required tasks and steps
necessary to maintain compliance with the Freedom of Information Law. The system issues reminders to
ensure requests are properly filed, delivers automatic status updates, and audits completed tasks to
support ongoing compliance and accountability.</p>
</div>
</div>
</div>
</div>
</div>
<div id="site_footer"></div>
</div>
unit View.RecordsManagement;
interface
uses
System.SysUtils, System.Classes, WEBLib.Graphics, WEBLib.Forms, Vcl.StdCtrls,
WEBLib.StdCtrls, Vcl.Controls, WEBLib.Dialogs, Vcl.Imaging.pngimage,
WEBLib.ExtCtrls, WEBLib.Controls, Web, JS, WEBLib.Menus, WEBLib.WebCtrls;
type
TFRecordsManagement = class(TWebForm)
[async]
procedure WebFormShow(Sender: TObject);
private
{ Private declarations }
public
procedure NavScrollSizing;
end;
var
FRecordsManagement: TFRecordsManagement;
implementation
{$R *.dfm}
uses
View.AboutUs,
View.ContactUs,
View.CustomSoftware,
View.PublicSafety,
Site.Navbar,
Site.Footer,
ConnectionModule,
View.Home;
procedure TFRecordsManagement.WebFormShow(Sender: TObject);
begin
Application.ThemeColor := clTMSWEB;
InjectNavbar;
InjectFooter;
SetFooterVersion('ver - ' + TDMConnection.clientVersion);
NavScrollSizing;
end;
procedure TFRecordsManagement.NavScrollSizing;
begin
asm
window.addEventListener('scroll', function() {
var navbar = document.querySelector('.em-navbar-wrap .navbar');
var logo = document.querySelector('.em-brand img');
var scrollDistance = 50; // Adjust based on your preference
if (window.scrollY > scrollDistance) {
navbar.classList.add('scrolled');
logo.classList.add('scrolled-logo');
} else {
navbar.classList.remove('scrolled');
logo.classList.remove('scrolled-logo');
}
});
end;
end;
initialization
RegisterClass(TFRecordsManagement);
end.
\ No newline at end of file
object FRequestDemo: TFRequestDemo
Width = 640
Height = 480
Caption = 'EM Systems, Inc'
CSSLibrary = cssBootstrap
ElementFont = efCSS
OnCreate = WebFormCreate
object lblReqPrefMethod: TWebLabel
Left = 50
Top = 218
Width = 225
Height = 15
Caption = 'Please choose a preferred contact method.'
ElementID = 'lbl_req_pref_method'
ElementFont = efCSS
HeightStyle = ssAuto
HeightPercent = 100.000000000000000000
WidthPercent = 100.000000000000000000
end
object edtReqName: TWebEdit
Left = 50
Top = 34
Width = 267
Height = 22
TabStop = False
ElementID = 'edt_req_name'
ElementFont = efCSS
HeightStyle = ssAuto
HeightPercent = 100.000000000000000000
ShowFocus = False
WidthPercent = 100.000000000000000000
end
object edtReqEmail: TWebEdit
Left = 50
Top = 62
Width = 121
Height = 22
TabStop = False
ChildOrder = 1
ElementClassName = 'form-control'
ElementID = 'edt_req_email'
ElementFont = efCSS
HeightStyle = ssAuto
HeightPercent = 100.000000000000000000
ShowFocus = False
WidthPercent = 100.000000000000000000
end
object edtReqAgency: TWebEdit
Left = 50
Top = 90
Width = 121
Height = 22
TabStop = False
ChildOrder = 2
ElementID = 'edt_req_agency'
ElementFont = efCSS
HeightStyle = ssAuto
HeightPercent = 100.000000000000000000
ShowFocus = False
WidthPercent = 100.000000000000000000
end
object edtReqPhoneNumber: TWebEdit
Left = 196
Top = 62
Width = 121
Height = 22
TabStop = False
ChildOrder = 3
EditType = weNumeric
ElementClassName = 'form-control'
ElementID = 'edt_req_phone_number'
ElementFont = efCSS
HeightStyle = ssAuto
HeightPercent = 100.000000000000000000
ShowFocus = False
WidthPercent = 100.000000000000000000
end
object radReqPhone: TWebRadioButton
Left = 50
Top = 239
Width = 117
Height = 22
Caption = 'Phone'
Checked = False
ChildOrder = 5
Color = clNone
ElementID = 'rad_req_phone'
ElementFont = efCSS
HeightStyle = ssAuto
HeightPercent = 100.000000000000000000
ShowFocus = False
WidthPercent = 100.000000000000000000
OnClick = radReqPhoneClick
end
object radReqEmail: TWebRadioButton
Left = 196
Top = 239
Width = 121
Height = 22
Caption = 'Email'
Checked = True
ChildOrder = 6
Color = clNone
ElementID = 'rad_req_email'
ElementFont = efCSS
HeightStyle = ssAuto
HeightPercent = 100.000000000000000000
WidthPercent = 100.000000000000000000
OnClick = radReqEmailClick
end
object btnReqSendRequest: TWebButton
Left = 50
Top = 267
Width = 96
Height = 25
Caption = 'Send Request'
ChildOrder = 7
ElementID = 'btn_req_send_request'
ElementFont = efCSS
HeightStyle = ssAuto
HeightPercent = 100.000000000000000000
TabStop = False
WidthPercent = 100.000000000000000000
OnClick = btnReqSendRequestClick
end
object edtReqState: TWebEdit
Left = 196
Top = 90
Width = 121
Height = 22
TabStop = False
ChildOrder = 8
ElementClassName = 'form-control'
ElementID = 'edt_req_state'
ElementFont = efCSS
HeightStyle = ssAuto
HeightPercent = 100.000000000000000000
ShowFocus = False
WidthPercent = 100.000000000000000000
end
object edtReqCounty: TWebEdit
Left = 50
Top = 118
Width = 121
Height = 22
TabStop = False
ChildOrder = 8
ElementClassName = 'form-control'
ElementID = 'edt_req_county'
ElementFont = efCSS
HeightStyle = ssAuto
HeightPercent = 100.000000000000000000
ShowFocus = False
WidthPercent = 100.000000000000000000
end
object memoAdditionalComments: TWebMemo
Left = 50
Top = 147
Width = 267
Height = 65
TabStop = False
ElementID = 'memo_additional_comments'
ElementFont = efCSS
HeightPercent = 100.000000000000000000
Lines.Strings = (
'')
SelLength = 0
SelStart = 2
ShowFocus = False
WidthPercent = 100.000000000000000000
end
object wcbInterest: TWebComboBox
Left = 196
Top = 118
Width = 121
Height = 23
ElementClassName = 'form-select'
ElementID = 'wcb_interest'
ElementFont = efCSS
HeightStyle = ssAuto
HeightPercent = 100.000000000000000000
ShowFocus = False
TabStop = False
WidthPercent = 100.000000000000000000
ItemIndex = -1
Items.Strings = (
''
'Public Safety'
'Records Management'
'Custom Software'
'Other')
end
object xdwcRequestDemo: TXDataWebClient
Connection = DMConnection.ApiConnection
OnError = xdwcRequestDemoError
Left = 264
Top = 362
end
end
<div class="d-flex flex-column min-vh-100">
<div id="site_nav"></div>
<!-- REQUEST DEMO SECTION -->
<div class="container pt-5 mt-5 flex-grow-1">
<div class="row justify-content-center">
<div class="col-12 col-md-10 col-lg-7">
<div class="card shadow-sm border-0">
<div class="card-body p-4 p-md-5">
<h2 class="mb-2 text-center">Request a Demo</h2>
<p class="text-muted text-center mb-4">
Please fill in the information, and we will reach out to schedule a demo.
</p>
<form id="frm_request_demo" novalidate>
<div class="row g-3">
<div class="col-12">
<label for="edt_req_name" class="form-label mb-1">Name*</label>
<input type="text" class="form-control" id="edt_req_name">
<div id="fb_req_name" class="invalid-feedback">Please enter your name.</div>
</div>
<div class="col-12 col-md-7">
<label for="edt_req_email" class="form-label mb-1">Email*</label>
<input type="email" class="form-control" id="edt_req_email">
<div id="fb_req_email" class="invalid-feedback">Please enter a valid email address.</div>
</div>
<div class="col-12 col-md-5">
<label for="edt_req_phone_number" class="form-label mb-1">Phone Number*</label>
<input type="tel" class="form-control" id="edt_req_phone_number">
<div id="fb_req_phone" class="invalid-feedback">Please enter a phone number.</div>
</div>
<div class="col-12 col-md-6">
<label for="edt_req_agency" class="form-label mb-1">Company/Agency*</label>
<input type="text" class="form-control" id="edt_req_agency">
<div id="fb_req_agency" class="invalid-feedback">Please enter your Agency or Company.</div>
</div>
<div class="col-12 col-md-6">
<label for="edt_req_state" class="form-label mb-1">State</label>
<input type="text" class="form-control" id="edt_req_state">
</div>
<div class="col-12 col-md-6">
<label for="edt_req_county" class="form-label mb-1">County</label>
<input type="text" class="form-control" id="edt_req_county">
</div>
<div class="col-12 col-md-6">
<label for="wcb_interest" class="form-label mb-1">Interest</label>
<select class="form-select" id="wcb_interest"></select>
</div>
<div class="col-12">
<label for="memo_additional_comments" class="form-label mb-1">Additional Comments</label>
<textarea class="form-control" id="memo_additional_comments" rows="4"></textarea>
</div>
<div class="col-12">
<div id="lbl_req_pref_method" class="form-label mb-2">Preferred Contact Method</div>
<div class="d-flex flex-column flex-sm-row gap-2 gap-sm-4">
<div class="form-check">
<input class="form-check-input" type="radio" name="req_pref_method" id="rad_req_phone">
<label class="form-check-label" for="rad_req_phone">Phone</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="req_pref_method" id="rad_req_email">
<label class="form-check-label" for="rad_req_email">Email</label>
</div>
</div>
</div>
<div class="col-12 mt-4">
<button type="button" class="btn btn-primary w-100 d-md-inline-block w-md-auto px-4" id="btn_req_send_request">
Send Request
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
<div id="site_footer" class="mt-auto"></div>
</div>
<div id="spinner" class="position-fixed top-50 start-50 translate-middle d-none" style="z-index: 1100;">
<div class="lds-roller">
<div></div><div></div><div></div><div></div>
<div></div><div></div><div></div><div></div>
</div>
</div>
<div class="modal fade" id="contact_notification_modal" tabindex="-1" aria-labelledby="contact_notification_modal_label" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content shadow-lg">
<div class="modal-header">
<h5 class="modal-title" id="contact_notification_modal_label">Demo Requested Successfully</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body fs-6 fw-bold" id="contact_notification_modal_body">
Please contact EMSystems to solve the issue.
</div>
<div class="modal-footer justify-content-center">
<a href="#FHome"
id="btn_modal_close"
class="btn btn-primary"
data-bs-dismiss="modal"
onclick="window.location.hash='#FHome';">
Close
</a>
</div>
</div>
</div>
</div>
unit View.RequestDemo;
interface
uses
System.SysUtils, System.Classes, JS, Web, WEBLib.Graphics, WEBLib.Controls,
WEBLib.Forms, WEBLib.Dialogs, Vcl.StdCtrls, WEBLib.StdCtrls, Vcl.Controls,
XData.Web.Client, ConnectionModule, Utils, WEBLib.RegularExpressions;
type
TFRequestDemo = class(TWebForm)
edtReqName: TWebEdit;
edtReqEmail: TWebEdit;
edtReqAgency: TWebEdit;
edtReqPhoneNumber: TWebEdit;
lblReqPrefMethod: TWebLabel;
radReqPhone: TWebRadioButton;
radReqEmail: TWebRadioButton;
btnReqSendRequest: TWebButton;
xdwcRequestDemo: TXDataWebClient;
edtReqState: TWebEdit;
edtReqCounty: TWebEdit;
memoAdditionalComments: TWebMemo;
wcbInterest: TWebComboBox;
procedure btnReqSendRequestClick(Sender: TObject);
procedure radReqEmailClick(Sender: TObject);
procedure radReqPhoneClick(Sender: TObject);
procedure WebFormCreate(Sender: TObject);
procedure xdwcRequestDemoError(Error: TXDataClientError);
private
function IsEmailValid(const email: string): Boolean;
function PreferredMethod: string;
procedure NavScrollSizing;
procedure ClearFieldErrors;
procedure SetInvalid(const inputId: string);
function ValidateRequest: Boolean;
procedure SendRequest;
end;
var
FRequestDemo: TFRequestDemo;
implementation
{$R *.dfm}
uses
Site.Navbar,
Site.Footer;
procedure TFRequestDemo.WebFormCreate(Sender: TObject);
begin
Application.ThemeColor := clTMSWEB;
InjectNavbar;
InjectFooter;
SetFooterVersion('ver - ' + TDMConnection.clientVersion);
NavScrollSizing;
end;
procedure TFRequestDemo.xdwcRequestDemoError(Error: TXDataClientError);
begin
Utils.HideSpinner('spinner');
ShowNotificationModal('Error when attempting to send: ' + Error.ErrorMessage);
end;
procedure TFRequestDemo.NavScrollSizing;
begin
asm
window.addEventListener('scroll', function() {
var navbar = document.querySelector('.em-navbar-wrap .navbar');
var logo = document.querySelector('.em-brand img');
var scrollDistance = 50;
if (window.scrollY > scrollDistance) {
navbar.classList.add('scrolled');
logo.classList.add('scrolled-logo');
} else {
navbar.classList.remove('scrolled');
logo.classList.remove('scrolled-logo');
}
});
end;
end;
function TFRequestDemo.IsEmailValid(const email: string): Boolean;
const
pattern = '^[^\s@]+@[^\s@]+\.[^\s@]+$';
begin
Result := TRegEx.IsMatch(email.Trim, pattern);
end;
function TFRequestDemo.PreferredMethod: string;
begin
if radReqPhone.Checked then
Exit('phone');
if radReqEmail.Checked then
Exit('email');
Result := '';
end;
procedure TFRequestDemo.SetInvalid(const inputId: string);
var
inputEl: TJSHTMLElement;
begin
inputEl := TJSHTMLElement(document.getElementById(inputId));
if Assigned(inputEl) then
inputEl.classList.add('is-invalid');
end;
procedure TFRequestDemo.ClearFieldErrors;
var
inputEl: TJSHTMLElement;
begin
inputEl := TJSHTMLElement(document.getElementById('edt_req_name'));
if Assigned(inputEl) then inputEl.classList.remove('is-invalid');
inputEl := TJSHTMLElement(document.getElementById('edt_req_email'));
if Assigned(inputEl) then inputEl.classList.remove('is-invalid');
inputEl := TJSHTMLElement(document.getElementById('edt_req_phone_number'));
if Assigned(inputEl) then inputEl.classList.remove('is-invalid');
inputEl := TJSHTMLElement(document.getElementById('edt_req_agency'));
if Assigned(inputEl) then inputEl.classList.remove('is-invalid');
end;
function TFRequestDemo.ValidateRequest: Boolean;
var
isValid: Boolean;
emailText: string;
begin
ClearFieldErrors;
isValid := True;
if edtReqName.Text.Trim = '' then
begin
SetInvalid('edt_req_name');
isValid := False;
end;
emailText := edtReqEmail.Text.Trim;
if emailText = '' then
begin
SetInvalid('edt_req_email');
isValid := False;
end
else if not IsEmailValid(emailText) then
begin
SetInvalid('edt_req_email');
isValid := False;
end;
if edtReqPhoneNumber.Text.Trim = '' then
begin
SetInvalid('edt_req_phone_number');
isValid := False;
end;
if edtReqAgency.Text.Trim = '' then
begin
SetInvalid('edt_req_agency');
isValid := False;
end;
Result := isValid;
end;
procedure TFRequestDemo.btnReqSendRequestClick(Sender: TObject);
begin
if not ValidateRequest then
Exit;
Utils.ShowSpinner('spinner');
if not DMConnection.ApiConnection.Connected then
begin
DMConnection.ApiConnection.Open(
procedure
begin
SendRequest;
end);
Exit;
end;
SendRequest;
end;
procedure TFRequestDemo.radReqEmailClick(Sender: TObject);
begin
if radReqEmail.Checked then
radReqPhone.Checked := False;
end;
procedure TFRequestDemo.radReqPhoneClick(Sender: TObject);
begin
if radReqPhone.Checked then
radReqEmail.Checked := False;
end;
procedure TFRequestDemo.SendRequest;
var
bodyText: string;
pref: string;
begin
pref := PreferredMethod;
bodyText :=
'Demo request details:' + sLineBreak +
'Name: ' + edtReqName.Text + sLineBreak +
'Email: ' + edtReqEmail.Text + sLineBreak +
'Phone: ' + edtReqPhoneNumber.Text + sLineBreak +
'Company/Agency: ' + edtReqAgency.Text + sLineBreak +
'State: ' + edtReqState.Text + sLineBreak +
'County: ' + edtReqCounty.Text + sLineBreak +
'Interest: ' + wcbInterest.Text + sLineBreak +
'Additional comments: ' + memoAdditionalComments.Text;
if pref <> '' then
bodyText := bodyText + sLineBreak + 'Preferred contact: ' + pref;
xdwcRequestDemo.RawInvoke('IApiService.SendEmail',
[edtReqName.Text, edtReqEmail.Text, 'Demo Request', bodyText],
procedure(response: TXDataClientResponse)
begin
Utils.HideSpinner('spinner');
ClearFieldErrors;
edtReqName.Text := '';
edtReqEmail.Text := '';
edtReqPhoneNumber.Text := '';
edtReqAgency.Text := '';
edtReqState.Text := '';
edtReqCounty.Text := '';
memoAdditionalComments.Text := '';
radReqPhone.Checked := False;
radReqEmail.Checked := True;
wcbInterest.ItemIndex := -1;
ShowNotificationModal('Your demo request has been submitted. Please check your email for confirmation. If you did not recieve an email, reach out directly.');
end);
end;
initialization
RegisterClass(TFRequestDemo);
end.
{
"ApiUrl" : "http://localhost:2002/website/",
"AppUrl" : "http://localhost:2002/website/App"
}
html,
body {
min-height: 100%;
}
body {
font-family: Arial, Helvetica, sans-serif;
color: #333333;
background: #ffffff;
margin: 0;
}
.envoy-page {
min-height: 100vh;
background: #ffffff;
}
.envoy-container {
max-width: 900px;
}
.envoy-header {
background-color: #e9eef4;
background-image: url("../images/simple_bg2.png");
background-repeat: repeat-x;
background-position: top center;
}
.envoy-brand img {
width: 158px;
height: 106px;
object-fit: contain;
}
.envoy-nav .nav-link {
color: #999999;
font-size: 13px;
font-weight: 700;
padding: 0.45rem 0.65rem;
cursor: default;
white-space: nowrap;
opacity: 0.55;
}
.envoy-nav .nav-link:hover,
.envoy-nav .nav-link:focus {
color: #315a83;
}
.envoy-main {
background-color: #ffffff;
background-image: url("../images/simple_bg.jpg");
background-repeat: repeat-x;
background-position: top center;
min-height: 370px;
}
.envoy-card {
background: #ffffff;
border: 1px solid #dddddd;
}
.envoy-subhead {
color: #315a83;
font-size: 24px;
line-height: 1.35;
font-weight: 400;
}
.envoy-text {
color: #555555;
font-size: 13px;
line-height: 1.6;
font-weight: 400;
}
.envoy-section-title {
color: #315a83;
font-size: 17px;
line-height: 1.3;
font-weight: 700;
}
.envoy-footer {
color: #666666;
font-size: 11px;
line-height: 1.5;
}
.envoy-managed {
color: #666666;
font-size: 11px;
opacity: 0.55;
}
@media (max-width: 991.98px) {
.envoy-header {
padding-bottom: 0.75rem;
}
}
.lds-roller {
display: inline-block;
position: relative;
width: 80px;
height: 80px;
}
.lds-roller div {
animation: lds-roller 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;
transform-origin: 40px 40px;
}
.lds-roller div:after {
content: " ";
display: block;
position: absolute;
width: 10px;
height: 10px;
border-radius: 50%;
background: var(--bs-primary);
margin: -5px 0 0 -5px;
}
.lds-roller div:nth-child(1) {
animation-delay: -0.036s;
}
.lds-roller div:nth-child(1):after {
top: 63px;
left: 63px;
}
.lds-roller div:nth-child(2) {
animation-delay: -0.072s;
}
.lds-roller div:nth-child(2):after {
top: 68px;
left: 56px;
}
.lds-roller div:nth-child(3) {
animation-delay: -0.108s;
}
.lds-roller div:nth-child(3):after {
top: 71px;
left: 48px;
}
.lds-roller div:nth-child(4) {
animation-delay: -0.144s;
}
.lds-roller div:nth-child(4):after {
top: 72px;
left: 40px;
}
.lds-roller div:nth-child(5) {
animation-delay: -0.18s;
}
.lds-roller div:nth-child(5):after {
top: 71px;
left: 32px;
}
.lds-roller div:nth-child(6) {
animation-delay: -0.216s;
}
.lds-roller div:nth-child(6):after {
top: 68px;
left: 24px;
}
.lds-roller div:nth-child(7) {
animation-delay: -0.252s;
}
.lds-roller div:nth-child(7):after {
top: 63px;
left: 17px;
}
.lds-roller div:nth-child(8) {
animation-delay: -0.288s;
}
.lds-roller div:nth-child(8):after {
top: 56px;
left: 12px;
}
@keyframes lds-roller {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
program envoyInternationalWeb;
{$R *.dres}
uses
Vcl.Forms,
WEBLib.Forms,
View.Home in 'View.Home.pas' {FHome: TWebForm} {*.html},
View.PublicSafety in 'View.PublicSafety.pas' {FPublicSafety: TWebForm} {*.html},
View.RecordsManagement in 'View.RecordsManagement.pas' {FRecordsManagement: TWebForm} {*.html},
View.CustomSoftware in 'View.CustomSoftware.pas' {FCustomSoftware: TWebForm} {*.html},
View.AboutUs in 'View.AboutUs.pas' {FAboutUs: TWebForm} {*.html},
View.ContactUs in 'View.ContactUs.pas' {FContactUs: TWebForm} {*.html},
Utils in 'Utils.pas',
ConnectionModule in 'ConnectionModule.pas' {DMConnection: TWebDataModule},
View.RequestDemo in 'View.RequestDemo.pas' {FRequestDemo: TWebForm} {*.html},
Site.Footer in 'Site.Footer.pas',
Site.Navbar in 'Site.Navbar.pas';
{$R *.res}
const
MaintenanceMode = True;
procedure StartMaintenancePage;
begin
asm
window.location.hash = '#FHome';
end;
Application.CreateForm(TFHome, FHome);
end;
procedure ShowVersionModal(const errorMessage, clientVer: string);
begin
asm
var dlg = document.createElement("dialog");
dlg.classList.add("shadow", "rounded", "border", "p-4");
dlg.style.maxWidth = "520px";
dlg.style.width = "92%";
dlg.style.fontFamily = "system-ui, sans-serif";
dlg.innerHTML =
"<h5 class='fw-bold mb-3 text-danger'>EM Systems web site</h5>" +
"<p class='mb-3' style='white-space: pre-wrap;'>" + errorMessage + "</p>" +
"<div class='text-end'>" +
"<button id='refreshBtn' class='btn btn-danger'>Reload</button></div>";
document.body.appendChild(dlg);
dlg.showModal();
document.getElementById("refreshBtn").addEventListener("click", function () {
var base = location.origin + location.pathname;
location.replace(base + "?ver=" + clientVer + "&r=" + Date.now() + location.hash);
});
end;
end;
procedure StartRouting;
begin
asm
window.addEventListener('hashchange', function() {
window.scrollTo(0, 0);
}, false);
if (window.location.hash === '') {
window.location.hash = '#FHome';
}
end;
if not Application.Route then
Application.CreateForm(TFHome, FHome);
end;
procedure StartApplication;
var
clientVer: string;
begin
clientVer := TDMConnection.clientVersion;
DMConnection.InitApp(
procedure
begin
DMConnection.SetClientConfig(
procedure(success: Boolean; errorMessage: string)
begin
if success then
StartRouting
else
ShowVersionModal(errorMessage, clientVer);
end
);
end
);
end;
begin
Application.Initialize;
Application.MainFormOnTaskbar := True;
if MaintenanceMode then
StartMaintenancePage
else
begin
Application.CreateForm(TDMConnection, DMConnection);
StartApplication;
end;
Application.Run;
end.
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{01921D57-5440-4C01-A48E-45F8F0B7DBB4}</ProjectGuid>
<ProjectVersion>20.4</ProjectVersion>
<FrameworkType>VCL</FrameworkType>
<MainSource>envoyInternationalWeb.dpr</MainSource>
<Base>True</Base>
<Config Condition="'$(Config)'==''">Debug</Config>
<Platform Condition="'$(Platform)'==''">Win32</Platform>
<TargetedPlatforms>1</TargetedPlatforms>
<AppType>Application</AppType>
<ProjectName Condition="'$(ProjectName)'==''">envoyInternationalWeb</ProjectName>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
<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="'$(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="('$(Platform)'=='Win32' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win32)'!=''">
<Cfg_2_Win32>true</Cfg_2_Win32>
<CfgParent>Cfg_2</CfgParent>
<Cfg_2>true</Cfg_2>
<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;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace)</DCC_Namespace>
<TMSWebProject>2</TMSWebProject>
<Icon_MainIcon>$(BDS)\bin\delphi_PROJECTICON.ico</Icon_MainIcon>
<Icns_MainIcns>$(BDS)\bin\delphi_PROJECTICNS.icns</Icns_MainIcns>
<TMSWebHTMLFile>EMSystemsWebsite.html</TMSWebHTMLFile>
<SanitizedProjectName>envoyInternationalWeb</SanitizedProjectName>
</PropertyGroup>
<PropertyGroup Condition="'$(Base_Win32)'!=''">
<DCC_UsePackage>DBXSqliteDriver;IndyIPCommon;RESTComponents;bindcompdbx;DBXInterBaseDriver;vcl;IndyIPServer;vclactnband;vclFireDAC;IndySystem;tethering;svnui;dsnapcon;FireDACADSDriver;FireDACMSAccDriver;fmxFireDAC;vclimg;FireDAC;vcltouch;vcldb;bindcompfmx;svn;TMSWEBCorePkgLibDXE12;FireDACSqliteDriver;FireDACPgDriver;inetdb;soaprtl;DbxCommonDriver;fmx;FireDACIBDriver;fmxdae;xmlrtl;soapmidas;fmxobj;vclwinx;rtl;DbxClientDriver;CustomIPTransport;vcldsnap;dbexpress;IndyCore;vclx;bindcomp;appanalytics;dsnap;FireDACCommon;IndyIPClient;TMSWEBCorePkgDXE12;bindcompvcl;RESTBackendComponents;VCLRESTComponents;soapserver;dbxcds;VclSmp;adortl;vclie;bindengine;DBXMySQLDriver;CloudService;dsnapxml;FireDACMySQLDriver;dbrtl;IndyProtocols;inetdbxpress;FireDACCommonODBC;FireDACCommonDriver;inet;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_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
<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>
<Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
</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>
<TMSWebDebugInfo>2</TMSWebDebugInfo>
<TMSWebDefines>DEBUG</TMSWebDefines>
<TMSWebHTMLFile>index.html</TMSWebHTMLFile>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_1_Win32)'!=''">
<DCC_RemoteDebug>false</DCC_RemoteDebug>
<AppDPIAwarenessMode>PerMonitorV2</AppDPIAwarenessMode>
<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
<VerInfo_Locale>1033</VerInfo_Locale>
<TMSWebServerWait>2</TMSWebServerWait>
</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>
<TMSWebObfuscation>2</TMSWebObfuscation>
<TMSWebOptimization>2</TMSWebOptimization>
<TMSWebDefines>RELEASE</TMSWebDefines>
<TMSWebHTMLFile>index.html</TMSWebHTMLFile>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_2_Win32)'!=''">
<AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
<AppDPIAwarenessMode>PerMonitorV2</AppDPIAwarenessMode>
</PropertyGroup>
<ItemGroup>
<DelphiCompile Include="$(MainSource)">
<MainSource>MainSource</MainSource>
</DelphiCompile>
<DCCReference Include="View.Home.pas">
<Form>FHome</Form>
<FormType>dfm</FormType>
<DesignClass>TWebForm</DesignClass>
</DCCReference>
<DCCReference Include="View.PublicSafety.pas">
<Form>FPublicSafety</Form>
<FormType>dfm</FormType>
<DesignClass>TWebForm</DesignClass>
</DCCReference>
<DCCReference Include="View.RecordsManagement.pas">
<Form>FRecordsManagement</Form>
<FormType>dfm</FormType>
<DesignClass>TWebForm</DesignClass>
</DCCReference>
<DCCReference Include="View.CustomSoftware.pas">
<Form>FCustomSoftware</Form>
<FormType>dfm</FormType>
<DesignClass>TWebForm</DesignClass>
</DCCReference>
<DCCReference Include="View.AboutUs.pas">
<Form>FAboutUs</Form>
<FormType>dfm</FormType>
<DesignClass>TWebForm</DesignClass>
</DCCReference>
<DCCReference Include="View.ContactUs.pas">
<Form>FContactUs</Form>
<FormType>dfm</FormType>
<DesignClass>TWebForm</DesignClass>
</DCCReference>
<DCCReference Include="Utils.pas"/>
<DCCReference Include="ConnectionModule.pas">
<Form>DMConnection</Form>
<FormType>dfm</FormType>
<DesignClass>TWebDataModule</DesignClass>
</DCCReference>
<DCCReference Include="View.RequestDemo.pas">
<Form>FRequestDemo</Form>
<FormType>dfm</FormType>
<DesignClass>TWebForm</DesignClass>
</DCCReference>
<DCCReference Include="Site.Footer.pas"/>
<DCCReference Include="Site.Navbar.pas"/>
<None Include="css\App.css"/>
<None Include="index.html"/>
<None Include="css\spinner.css"/>
<RcItem Include="images\bookshelves.jpg">
<ResourceType>RCDATA</ResourceType>
<ResourceId>JpgImage_1</ResourceId>
</RcItem>
<RcItem Include="images\computer_code.jpg">
<ResourceType>RCDATA</ResourceType>
<ResourceId>JpgImage_2</ResourceId>
</RcItem>
<RcItem Include="images\EM_Logo2_Copy5-1024x173.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_1</ResourceId>
</RcItem>
<RcItem Include="images\EM_Logo_2c66a0.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_2</ResourceId>
</RcItem>
<RcItem Include="images\EM_Logo_Black_Purple.jpg">
<ResourceType>RCDATA</ResourceType>
<ResourceId>JpgImage_3</ResourceId>
</RcItem>
<RcItem Include="images\EM_Logo_White.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_3</ResourceId>
</RcItem>
<RcItem Include="images\honeycomb-new.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_4</ResourceId>
</RcItem>
<RcItem Include="images\honeycomb.jpg">
<ResourceType>RCDATA</ResourceType>
<ResourceId>JpgImage_4</ResourceId>
</RcItem>
<RcItem Include="images\laptop.jpg">
<ResourceType>RCDATA</ResourceType>
<ResourceId>JpgImage_5</ResourceId>
</RcItem>
<RcItem Include="images\LogoAddress2.jpg">
<ResourceType>RCDATA</ResourceType>
<ResourceId>JpgImage_6</ResourceId>
</RcItem>
<RcItem Include="images\niagara.jpg">
<ResourceType>RCDATA</ResourceType>
<ResourceId>JpgImage_7</ResourceId>
</RcItem>
<RcItem Include="images\table_with_computers.jpg">
<ResourceType>RCDATA</ResourceType>
<ResourceId>JpgImage_8</ResourceId>
</RcItem>
<BuildConfiguration Include="Base">
<Key>Base</Key>
</BuildConfiguration>
<BuildConfiguration Include="Debug">
<Key>Cfg_1</Key>
<CfgParent>Base</CfgParent>
</BuildConfiguration>
<BuildConfiguration Include="Release">
<Key>Cfg_2</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">envoyInternationalWeb.dpr</Source>
</Source>
<Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\bcboffice2k290.bpl">Embarcadero C++Builder Office 2000 Servers Package</Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\bcbofficexp290.bpl">Embarcadero C++Builder Office XP Servers Package</Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\dcloffice2k290.bpl">Microsoft Office 2000 Sample Automation Server Wrapper Components</Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\dclofficexp290.bpl">Microsoft Office XP Sample Automation Server Wrapper Components</Excluded_Packages>
</Excluded_Packages>
</Delphi.Personality>
<Deployment Version="5">
<DeployFile LocalName="EMSystemsWebsite.html" Configuration="Debug" Class="ProjectFile"/>
<DeployFile LocalName="Win32\Debug\EMSystemsWebsite.exe" Configuration="Debug" Class="ProjectOutput"/>
<DeployFile LocalName="Win32\Debug\envoyInternationalWeb.exe" Configuration="Debug" Class="ProjectOutput">
<Platform Name="Win32">
<RemoteName>envoyInternationalWeb.exe</RemoteName>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="Win32\Release\envoyInternationalWeb.exe" Configuration="Release" Class="ProjectOutput">
<Platform Name="Win32">
<RemoteName>envoyInternationalWeb.exe</RemoteName>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="css\App.css" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="css\App.css" Configuration="Release" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="css\spinner.css" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="css\spinner.css" Configuration="Release" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="images\EM_Logo2_Copy5-1024x173.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="images\EM_Logo2_Copy5-1024x173.png" Configuration="Release" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="images\EM_Logo_2c66a0.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="images\EM_Logo_2c66a0.png" Configuration="Release" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="images\EM_Logo_Black_Purple.jpg" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="images\EM_Logo_Black_Purple.jpg" Configuration="Release" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="images\EM_Logo_White.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="images\EM_Logo_White.png" Configuration="Release" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="images\LogoAddress2.jpg" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="images\LogoAddress2.jpg" Configuration="Release" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="images\bookshelves.jpg" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="images\bookshelves.jpg" Configuration="Release" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="images\computer_code.jpg" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="images\computer_code.jpg" Configuration="Release" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="images\honeycomb-new.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="images\honeycomb-new.png" Configuration="Release" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="images\honeycomb.jpg" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="images\honeycomb.jpg" Configuration="Release" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="images\laptop.jpg" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="images\laptop.jpg" Configuration="Release" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="images\niagara.jpg" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="images\niagara.jpg" Configuration="Release" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="images\table_with_computers.jpg" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="images\table_with_computers.jpg" Configuration="Release" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="index.html" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="index.html" Configuration="Release" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<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="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="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="AndroidSplashImageDefV21">
<Platform Name="Android">
<RemoteDir>res\drawable-anydpi-v21</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-anydpi-v21</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="AndroidSplashStylesV31">
<Platform Name="Android">
<RemoteDir>res\values-v31</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\values-v31</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidSplashStylesV35">
<Platform Name="Android">
<RemoteDir>res\values-v35</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\values-v35</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_AdaptiveIcon">
<Platform Name="Android">
<RemoteDir>res\drawable-anydpi-v26</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-anydpi-v26</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_AdaptiveIconBackground">
<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_AdaptiveIconForeground">
<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_AdaptiveIconMonochrome">
<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_AdaptiveIconV33">
<Platform Name="Android">
<RemoteDir>res\drawable-anydpi-v33</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-anydpi-v33</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_ColorsDark">
<Platform Name="Android">
<RemoteDir>res\values-night-v21</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\values-night-v21</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_DefaultAppIcon">
<Platform Name="Android">
<RemoteDir>res\drawable</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_LauncherIcon144">
<Platform Name="Android">
<RemoteDir>res\drawable-xxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-xxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_LauncherIcon192">
<Platform Name="Android">
<RemoteDir>res\drawable-xxxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-xxxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_LauncherIcon36">
<Platform Name="Android">
<RemoteDir>res\drawable-ldpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-ldpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_LauncherIcon48">
<Platform Name="Android">
<RemoteDir>res\drawable-mdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-mdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_LauncherIcon72">
<Platform Name="Android">
<RemoteDir>res\drawable-hdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-hdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_LauncherIcon96">
<Platform Name="Android">
<RemoteDir>res\drawable-xhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-xhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_NotificationIcon24">
<Platform Name="Android">
<RemoteDir>res\drawable-mdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-mdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_NotificationIcon36">
<Platform Name="Android">
<RemoteDir>res\drawable-hdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-hdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_NotificationIcon48">
<Platform Name="Android">
<RemoteDir>res\drawable-xhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-xhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_NotificationIcon72">
<Platform Name="Android">
<RemoteDir>res\drawable-xxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-xxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_NotificationIcon96">
<Platform Name="Android">
<RemoteDir>res\drawable-xxxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-xxxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_SplashImage426">
<Platform Name="Android">
<RemoteDir>res\drawable-small</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-small</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_SplashImage470">
<Platform Name="Android">
<RemoteDir>res\drawable-normal</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-normal</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_SplashImage640">
<Platform Name="Android">
<RemoteDir>res\drawable-large</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-large</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_SplashImage960">
<Platform Name="Android">
<RemoteDir>res\drawable-xlarge</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-xlarge</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_Strings">
<Platform Name="Android">
<RemoteDir>res\values</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\values</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_VectorizedNotificationIcon">
<Platform Name="Android">
<RemoteDir>res\drawable-anydpi-v24</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-anydpi-v24</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_VectorizedSplash">
<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_VectorizedSplashDark">
<Platform Name="Android">
<RemoteDir>res\drawable-night-anydpi-v21</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-night-anydpi-v21</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_VectorizedSplashV31">
<Platform Name="Android">
<RemoteDir>res\drawable-anydpi-v31</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-anydpi-v31</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_VectorizedSplashV31Dark">
<Platform Name="Android">
<RemoteDir>res\drawable-night-anydpi-v31</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-night-anydpi-v31</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="OSXARM64">
<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="iOSSimARM64">
<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="OSXARM64">
<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="iOSSimARM64">
<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="OSXARM64">
<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="iOSSimARM64">
<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="OSXARM64">
<RemoteDir>Contents\Resources\StartUp\</RemoteDir>
<Operation>0</Operation>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectAndroidManifest">
<Platform Name="Android">
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectOSXDebug">
<Platform Name="OSX64">
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="OSXARM64">
<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>
<Platform Name="OSXARM64">
<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>
<Platform Name="OSXARM64">
<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>
<Platform Name="OSXARM64">
<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="iOSSimARM64">
<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="OSXARM64">
<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>
<Platform Name="Win64x">
<Operation>1</Operation>
</Platform>
<Platform Name="WinARM64EC">
<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>
<Platform Name="iOSSimARM64">
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSEntitlements">
<Platform Name="iOSDevice32">
<RemoteDir>..\</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<RemoteDir>..\</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<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="iOSSimARM64">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSLaunchScreen">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen</RemoteDir>
<Operation>64</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<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="iOSSimARM64">
<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>
<Platform Name="WinARM64EC">
<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>
<Platform Name="WinARM64EC">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iOS_AppStore1024">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_AppIcon152">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_AppIcon167">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch2x">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_LaunchDark2x">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Notification40">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Setting58">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_SpotLight80">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_AppIcon120">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_AppIcon180">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch2x">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch3x">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_LaunchDark2x">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<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="iOSSimARM64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Notification40">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Notification60">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Setting58">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Setting87">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Spotlight120">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Spotlight80">
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimARM64">
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<ProjectRoot Platform="Android" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="Android64" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="iOSDevice32" Name="$(PROJECTNAME).app"/>
<ProjectRoot Platform="iOSDevice64" Name="$(PROJECTNAME).app"/>
<ProjectRoot Platform="iOSSimARM64" Name="$(PROJECTNAME).app"/>
<ProjectRoot Platform="iOSSimulator" Name="$(PROJECTNAME).app"/>
<ProjectRoot Platform="Linux64" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="OSX32" Name="$(PROJECTNAME).app"/>
<ProjectRoot Platform="OSX64" Name="$(PROJECTNAME).app"/>
<ProjectRoot Platform="OSXARM64" Name="$(PROJECTNAME).app"/>
<ProjectRoot Platform="Win32" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="Win64" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="Win64x" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="WinARM64EC" Name="$(PROJECTNAME)"/>
</Deployment>
<Platforms>
<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>
 <!--NAVBAR CONTAINER-->
<nav class="navbar navbar-expand-lg navbar-dark bg-dark fixed-top shadow">
<div class="container-fluid">
<a class="navbar-brand" href="#FHome">
<img src="images\EM_Logo_2c66a0.png" alt="EM_Logo" style="max-height: 50px;">
</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav"
aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav ms-auto">
<li class="nav-item">
<a class="nav-link" id="homenav" href="#FHome">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" id="aboutusnav" href="#FAboutUs">About Us</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown"
aria-expanded="false">
What We Do
</a>
<ul class="dropdown-menu" aria-labelledby="navbarDropdown">
<li><a class="dropdown-item" id="customsoftwarenav" href="#FCustomSoftware">Custom Software</a></li>
<li><a class="dropdown-item" id="publicsafetynav" href="#FPublicSafety">Public Safety</a></li>
<li><a class="dropdown-item" id="recordsmanagementnav" href="#FRecordsManagement">Records Management</a>
</ul>
</li>
<li class="nav-item">
<a class="nav-link" id="contactusnav" href="#FContactUs">Contact Us</a>
</li>
</ul>
</div>
</div>
</nav>
<!-- HERO SECTION -->
<div class="hero-section bg-dark text-white text-center" style="margin-top: 56px;">
<img class="img-fluid" src="images\table_with_computers.jpg" alt="Hero Image">
<div class="d-flex justify-content-center align-items-center" style="position: absolute; top: 0; right: 0; bottom: 0; left: 0;">
<div class="text-center">
<h1 class="display-4">Custom Software, Comprehensive Support</h1>
<p class="lead">Real connections. Reliable support. Software made for you.</p>
</div>
</div>
</div>
<!-- MAIN CONTENT-->
<div class="container my-5 flex-grow-1">
<div class="row g-4">
<!-- First Box: Records and Information Management Solutions -->
<div class="col-md-6">
<img src="http://gator3304.temp.domains/~emsys065/wp-content/uploads/2021/12/archive-gc84e8bebd_1920-1024x683.jpg" class="img-fluid rounded" alt="Storage Image">
</div>
<div class="col-md-6 d-flex align-items-center">
<div class="text-center">
<h2>Records Management Notification System</h2>
<p>EM Systems has several new records and information management systems which incorporate modern paradigms in the field. Thinking of integrating electronic medical records with public safety systems? We can help. Feel free to contact us any time.</p>
<a href="#FRecordsManagement" class="btn btn-primary" id="recordsmanagementlearn">Learn More</a>
</div>
</div>
<!-- Second Box: Integrated Public Safety Software -->
<div class="col-md-6 order-md-2">
<img src="http://gator3304.temp.domains/~emsys065/wp-content/uploads/2021/12/digitization-g72e897cbb_1920-1024x680.jpg" class="img-fluid rounded" alt="Logistics Image">
</div>
<div class="col-md-6 d-flex align-items-center order-md-1">
<div class="text-center">
<h2>Integrated Public Safety Software</h2>
<p>EM Systems maintains a full suite of proven integrated systems that can be tailored to fit the specific needs of your organization. Seeking to move from an older outdated, or more expensive solution? Facilitate a smooth transition and don’t lose a thing. Ask us about data conversion and training programs.</p>
<a href="#FPublicSafety" class="btn btn-primary" id="publicsafetylearn">Learn More</a>
</div>
</div>
<!-- Third Box: Custom Software Development -->
<div class="col-md-6">
<img src="http://gator3304.temp.domains/~emsys065/wp-content/uploads/2021/10/computer-ga073c6b91_1920-1024x682.jpg" class="img-fluid rounded" alt="Computer Image">
</div>
<div class="col-md-6 d-flex align-items-center">
<div class="text-center">
<h2>Custom Software Development</h2>
<p>EM Systems has great talent when it comes to working with customers to develop software solutions designed and tailored to their specific needs. Over the years we have created hundreds of custom solutions that have worked wonders for our customers.</p>
<a href="#FCustomSoftware" class="btn btn-primary" id="customsoftwarelearn">Learn More</a>
</div>
</div>
</div>
</div>
<!-- FOOTER -->
<footer class="bg-dark text-light py-3">
<div class="container">
<div class="row text-center">
<!-- Logo Column -->
<div class="col-md-4 mb-3">
<a href="#FHome" class="navbar-brand">
<img src="images/EM_Logo_2c66a0.png" alt="EM_Logo" style="max-height: 30px">
</a>
</div>
<div class="col-md-4 mb-3">
<div>
<h5>Explore</h5>
<ul class="list-unstyled">
<li><a href="#FHome" id="homefooter">Home</a></li>
<li><a href="#FAboutUs" id="aboutusfooter">About Us</a></li>
<li><a href="#FContactUs" id="contactusfooter">Contact Us</a></li>
</ul>
</div>
</div>
<div class="col-md-4 mb-3">
<div>
<address>
4043 Maple Rd, Suite 211<br>
Amherst, NY 14226<br>
(716) 836-4910
</address>
</div>
</div>
</div>
</div>
<div class="footer-copyright">
© 2011-2024 EM Systems Inc
</div>
</footer>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment