├── Delphi ├── TasksExample │ ├── Simple Client │ │ ├── FormSimple.vlb │ │ ├── SimpleTaskClient.res │ │ ├── SimpleTaskClient.dpr │ │ ├── FormSimple.pas │ │ └── FormSimple.fmx │ ├── SIMPLETESTDB.IB │ ├── Simple Server │ │ ├── SimpleRADServerTasks.res │ │ ├── SimpleRADServerTasks.dpk │ │ ├── Unit2.pas │ │ ├── Unit2.dfm │ │ └── SimpleRADServerTasks.dproj │ └── pgTaskExample.groupproj ├── ChangeViews │ ├── SUB.IB │ ├── Client │ │ ├── ChangeViewsEMSThingPoint.dpr │ │ ├── formMain.pas │ │ ├── formMain.dfm │ │ └── ChangeViewsEMSThingPoint.dproj │ ├── Server │ │ └── RADServerDemo.dpk │ ├── ModuleCode │ │ ├── HighScores.Params.pas │ │ ├── HighScores.API.dfm │ │ ├── HighScore.dpk │ │ ├── ChangeView.DataConnection.dfm │ │ ├── ChangeView.DataConnection.pas │ │ ├── HighScores.API.pas │ │ └── ChangeView.Cache.pas │ └── ChangeViewsInEMS.groupproj └── REST.DataUpdater.pas ├── SenchaMail ├── data │ └── SENCHAMAILSERVER.IB ├── SenchaMail.dpk ├── unitLabels.dfm ├── unitLabels.pas ├── unitData.dfm └── unitData.pas ├── README.md └── .gitignore /Delphi/TasksExample/Simple Client/FormSimple.vlb: -------------------------------------------------------------------------------- 1 | [FDMemTable1] 2 | Visible=False 3 | 4 | -------------------------------------------------------------------------------- /Delphi/ChangeViews/SUB.IB: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DelphiABall/RADServer/HEAD/Delphi/ChangeViews/SUB.IB -------------------------------------------------------------------------------- /Delphi/TasksExample/SIMPLETESTDB.IB: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DelphiABall/RADServer/HEAD/Delphi/TasksExample/SIMPLETESTDB.IB -------------------------------------------------------------------------------- /SenchaMail/data/SENCHAMAILSERVER.IB: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DelphiABall/RADServer/HEAD/SenchaMail/data/SENCHAMAILSERVER.IB -------------------------------------------------------------------------------- /Delphi/TasksExample/Simple Client/SimpleTaskClient.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DelphiABall/RADServer/HEAD/Delphi/TasksExample/Simple Client/SimpleTaskClient.res -------------------------------------------------------------------------------- /Delphi/TasksExample/Simple Server/SimpleRADServerTasks.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DelphiABall/RADServer/HEAD/Delphi/TasksExample/Simple Server/SimpleRADServerTasks.res -------------------------------------------------------------------------------- /Delphi/TasksExample/Simple Client/SimpleTaskClient.dpr: -------------------------------------------------------------------------------- 1 | program SimpleTaskClient; 2 | 3 | uses 4 | System.StartUpCopy, 5 | FMX.Forms, 6 | FormSimple in 'FormSimple.pas' {Form1}, 7 | REST.DataUpdater in '..\..\REST.DataUpdater.pas'; 8 | 9 | {$R *.res} 10 | 11 | begin 12 | Application.Initialize; 13 | Application.CreateForm(TForm1, Form1); 14 | Application.Run; 15 | end. 16 | -------------------------------------------------------------------------------- /Delphi/ChangeViews/Client/ChangeViewsEMSThingPoint.dpr: -------------------------------------------------------------------------------- 1 | program ChangeViewsEMSThingPoint; 2 | 3 | uses 4 | Vcl.Forms, 5 | formMain in 'formMain.pas' {Form1}, 6 | HighScores.Params in '..\ModuleCode\HighScores.Params.pas', 7 | HighScores.API in '..\ModuleCode\HighScores.API.pas' {dataHighscoresResource: TDataModule}, 8 | ChangeView.DataConnection in '..\ModuleCode\ChangeView.DataConnection.pas' {ChangeViewConnection: TDataModule}, 9 | ChangeView.Cache in '..\ModuleCode\ChangeView.Cache.pas'; 10 | 11 | {$R *.res} 12 | 13 | begin 14 | Application.Initialize; 15 | Application.MainFormOnTaskbar := True; 16 | Application.CreateForm(TForm1, Form1); 17 | Application.Run; 18 | end. 19 | -------------------------------------------------------------------------------- /Delphi/ChangeViews/Server/RADServerDemo.dpk: -------------------------------------------------------------------------------- 1 | package RADServerDemo; 2 | 3 | {$R *.res} 4 | {$IFDEF IMPLICITBUILDING This IFDEF should not be used by users} 5 | {$ALIGN 8} 6 | {$ASSERTIONS ON} 7 | {$BOOLEVAL OFF} 8 | {$DEBUGINFO OFF} 9 | {$EXTENDEDSYNTAX ON} 10 | {$IMPORTEDDATA ON} 11 | {$IOCHECKS ON} 12 | {$LOCALSYMBOLS ON} 13 | {$LONGSTRINGS ON} 14 | {$OPENSTRINGS ON} 15 | {$OPTIMIZATION OFF} 16 | {$OVERFLOWCHECKS ON} 17 | {$RANGECHECKS ON} 18 | {$REFERENCEINFO ON} 19 | {$SAFEDIVIDE OFF} 20 | {$STACKFRAMES ON} 21 | {$TYPEDADDRESS OFF} 22 | {$VARSTRINGCHECKS ON} 23 | {$WRITEABLECONST OFF} 24 | {$MINENUMSIZE 1} 25 | {$IMAGEBASE $400000} 26 | {$DEFINE DEBUG} 27 | {$ENDIF IMPLICITBUILDING} 28 | {$RUNONLY} 29 | {$IMPLICITBUILD ON} 30 | 31 | requires 32 | rtl, 33 | emsserverapi; 34 | 35 | end. 36 | -------------------------------------------------------------------------------- /Delphi/ChangeViews/ModuleCode/HighScores.Params.pas: -------------------------------------------------------------------------------- 1 | unit HighScores.Params; 2 | 3 | interface 4 | 5 | uses 6 | EMS.ResourceAPI, EMS.ResourceTypes, System.SysUtils; 7 | 8 | type 9 | TChangeViewParams = Record 10 | public 11 | DeviceID : string; 12 | ChangeViewName : string; 13 | Constructor Create(const AContext: TEndpointContext; const ARequest: TEndpointRequest; const AResponse: TEndpointResponse); 14 | end; 15 | 16 | implementation 17 | 18 | { TChangeViewParams } 19 | 20 | constructor TChangeViewParams.Create(const AContext: TEndpointContext; 21 | const ARequest: TEndpointRequest; const AResponse: TEndpointResponse); 22 | begin 23 | DeviceID := ARequest.Params.Values['deviceid']; 24 | ChangeViewName := 'sub_highscore'; 25 | 26 | if Self.DeviceID.IsEmpty then 27 | EEMSHTTPError.RaiseBadRequest('DeviceID Missing'); 28 | end; 29 | 30 | end. 31 | -------------------------------------------------------------------------------- /Delphi/ChangeViews/ModuleCode/HighScores.API.dfm: -------------------------------------------------------------------------------- 1 | object dataHighscoresResource: TdataHighscoresResource 2 | Height = 600 3 | Width = 1200 4 | PixelsPerInch = 192 5 | object FDConnection1: TFDConnection 6 | Params.Strings = ( 7 | 'Database=c:\data\sub.ib' 8 | 'User_Name=sysdba' 9 | 'Password=masterkey' 10 | 'DriverID=IB') 11 | LoginPrompt = False 12 | Left = 92 13 | Top = 40 14 | end 15 | object qryHIGHSCORES: TFDQuery 16 | Connection = FDConnection1 17 | SQL.Strings = ( 18 | 'select * from HIGHSCORES' 19 | '{if !SORT}order by !SORT{fi}') 20 | Left = 260 21 | Top = 112 22 | MacroData = < 23 | item 24 | Value = Null 25 | Name = 'SORT' 26 | end> 27 | end 28 | object dsrHIGHSCORES: TEMSDataSetResource 29 | AllowedActions = [List, Get, Post, Put, Delete] 30 | DataSet = qryHIGHSCORES 31 | Left = 372 32 | Top = 248 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /Delphi/TasksExample/Simple Server/SimpleRADServerTasks.dpk: -------------------------------------------------------------------------------- 1 | package SimpleRADServerTasks; 2 | 3 | {$R *.res} 4 | {$IFDEF IMPLICITBUILDING This IFDEF should not be used by users} 5 | {$ALIGN 8} 6 | {$ASSERTIONS ON} 7 | {$BOOLEVAL OFF} 8 | {$DEBUGINFO OFF} 9 | {$EXTENDEDSYNTAX ON} 10 | {$IMPORTEDDATA ON} 11 | {$IOCHECKS ON} 12 | {$LOCALSYMBOLS ON} 13 | {$LONGSTRINGS ON} 14 | {$OPENSTRINGS ON} 15 | {$OPTIMIZATION OFF} 16 | {$OVERFLOWCHECKS ON} 17 | {$RANGECHECKS ON} 18 | {$REFERENCEINFO ON} 19 | {$SAFEDIVIDE OFF} 20 | {$STACKFRAMES ON} 21 | {$TYPEDADDRESS OFF} 22 | {$VARSTRINGCHECKS ON} 23 | {$WRITEABLECONST OFF} 24 | {$MINENUMSIZE 1} 25 | {$IMAGEBASE $400000} 26 | {$DEFINE DEBUG} 27 | {$ENDIF IMPLICITBUILDING} 28 | {$RUNONLY} 29 | {$IMPLICITBUILD ON} 30 | 31 | requires 32 | rtl, 33 | emsserverapi, 34 | dbrtl, 35 | emsserverresource, 36 | FireDACCommonDriver, 37 | FireDACCommon, 38 | FireDAC, 39 | FireDACIBDriver; 40 | 41 | contains 42 | Unit2 in 'Unit2.pas' {DataResource1: TDataModule}; 43 | 44 | end. 45 | 46 | 47 | -------------------------------------------------------------------------------- /SenchaMail/SenchaMail.dpk: -------------------------------------------------------------------------------- 1 | package SenchaMail; 2 | 3 | {$R *.res} 4 | {$IFDEF IMPLICITBUILDING This IFDEF should not be used by users} 5 | {$ALIGN 8} 6 | {$ASSERTIONS ON} 7 | {$BOOLEVAL OFF} 8 | {$DEBUGINFO OFF} 9 | {$EXTENDEDSYNTAX ON} 10 | {$IMPORTEDDATA ON} 11 | {$IOCHECKS ON} 12 | {$LOCALSYMBOLS OFF} 13 | {$LONGSTRINGS ON} 14 | {$OPENSTRINGS ON} 15 | {$OPTIMIZATION ON} 16 | {$OVERFLOWCHECKS OFF} 17 | {$RANGECHECKS OFF} 18 | {$REFERENCEINFO OFF} 19 | {$SAFEDIVIDE OFF} 20 | {$STACKFRAMES OFF} 21 | {$TYPEDADDRESS OFF} 22 | {$VARSTRINGCHECKS ON} 23 | {$WRITEABLECONST OFF} 24 | {$MINENUMSIZE 1} 25 | {$IMAGEBASE $400000} 26 | {$DEFINE RELEASE} 27 | {$ENDIF IMPLICITBUILDING} 28 | {$RUNONLY} 29 | {$IMPLICITBUILD ON} 30 | 31 | requires 32 | rtl, 33 | emsserverapi, 34 | dbrtl, 35 | emsserverresource, 36 | FireDACCommonDriver, 37 | FireDACCommon, 38 | FireDAC, 39 | FireDACIBDriver; 40 | 41 | contains 42 | unitData in 'unitData.pas' {MailResource1: TDataModule}, 43 | unitLabels in 'unitLabels.pas' {LabelsResource1: TDataModule}; 44 | 45 | end. 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /Delphi/ChangeViews/ModuleCode/HighScore.dpk: -------------------------------------------------------------------------------- 1 | package HighScore; 2 | 3 | {$R *.res} 4 | {$IFDEF IMPLICITBUILDING This IFDEF should not be used by users} 5 | {$ALIGN 8} 6 | {$ASSERTIONS ON} 7 | {$BOOLEVAL OFF} 8 | {$DEBUGINFO OFF} 9 | {$EXTENDEDSYNTAX ON} 10 | {$IMPORTEDDATA ON} 11 | {$IOCHECKS ON} 12 | {$LOCALSYMBOLS ON} 13 | {$LONGSTRINGS ON} 14 | {$OPENSTRINGS ON} 15 | {$OPTIMIZATION OFF} 16 | {$OVERFLOWCHECKS ON} 17 | {$RANGECHECKS ON} 18 | {$REFERENCEINFO ON} 19 | {$SAFEDIVIDE OFF} 20 | {$STACKFRAMES ON} 21 | {$TYPEDADDRESS OFF} 22 | {$VARSTRINGCHECKS ON} 23 | {$WRITEABLECONST OFF} 24 | {$MINENUMSIZE 1} 25 | {$IMAGEBASE $400000} 26 | {$DEFINE DEBUG} 27 | {$ENDIF IMPLICITBUILDING} 28 | {$RUNONLY} 29 | {$IMPLICITBUILD ON} 30 | 31 | requires 32 | rtl, 33 | emsserverapi, 34 | dbrtl, 35 | emsserverresource, 36 | FireDACCommonDriver, 37 | FireDACCommon, 38 | FireDAC, 39 | FireDACIBDriver; 40 | 41 | contains 42 | HighScores.API in 'HighScores.API.pas' {dataHighscoresResource: TDataModule}, 43 | ChangeView.DataConnection in 'ChangeView.DataConnection.pas' {ChangeViewConnection: TDataModule}, 44 | ChangeView.Cache in 'ChangeView.Cache.pas' {ChangeViewCachce: TDataModule}, 45 | HighScores.Params in 'HighScores.Params.pas'; 46 | 47 | end. 48 | -------------------------------------------------------------------------------- /Delphi/TasksExample/Simple Server/Unit2.pas: -------------------------------------------------------------------------------- 1 | unit Unit2; 2 | 3 | // EMS Resource Module 4 | 5 | interface 6 | 7 | uses 8 | System.SysUtils, System.Classes, System.JSON, 9 | EMS.Services, EMS.ResourceAPI, EMS.ResourceTypes, FireDAC.Stan.Intf, 10 | FireDAC.Stan.Option, FireDAC.Stan.Error, FireDAC.UI.Intf, FireDAC.Phys.Intf, 11 | FireDAC.Stan.Def, FireDAC.Stan.Pool, FireDAC.Stan.Async, FireDAC.Phys, 12 | FireDAC.Phys.IB, FireDAC.Phys.IBDef, FireDAC.ConsoleUI.Wait, 13 | FireDAC.Stan.Param, FireDAC.DatS, FireDAC.DApt.Intf, FireDAC.DApt, Data.DB, 14 | EMS.DataSetResource, FireDAC.Comp.DataSet, FireDAC.Comp.Client; 15 | 16 | type 17 | [ResourceName('data')] 18 | TDataResource1 = class(TDataModule) 19 | FDConnection1: TFDConnection; 20 | qryTASKS: TFDQuery; 21 | [ResourceSuffix('TASKS')] 22 | // If using Delphi 11.0, use this workaround to enable POST to work. 23 | // [ResourceSuffix('post', './{dummy_id}')] // added "fake" parameter as work around 24 | dsrTASKS: TEMSDataSetResource; 25 | qryTASKSTASK_ID: TIntegerField; 26 | qryTASKSTASK_NAME: TStringField; 27 | qryTASKSCOMPLETED: TBooleanField; 28 | 29 | published 30 | end; 31 | 32 | implementation 33 | 34 | {%CLASSGROUP 'System.Classes.TPersistent'} 35 | 36 | {$R *.dfm} 37 | 38 | uses System.IOUtils; 39 | 40 | procedure Register; 41 | begin 42 | RegisterResource(TypeInfo(TDataResource1)); 43 | end; 44 | 45 | initialization 46 | Register; 47 | end. 48 | 49 | 50 | -------------------------------------------------------------------------------- /SenchaMail/unitLabels.dfm: -------------------------------------------------------------------------------- 1 | object LabelsResource1: TLabelsResource1 2 | Height = 600 3 | Width = 1200 4 | PixelsPerInch = 192 5 | object FDConnection1: TFDConnection 6 | Params.Strings = ( 7 | 'Database=C:\data\SENCHAMAILSERVER.IB' 8 | 'User_Name=SYSDBA' 9 | 'Password=masterkey' 10 | 'Port=3050' 11 | 'InstanceName=instance2' 12 | 'DriverID=IB') 13 | UpdateOptions.AssignedValues = [uvGeneratorName] 14 | UpdateOptions.GeneratorName = 'G_ID' 15 | LoginPrompt = False 16 | Left = 60 17 | Top = 32 18 | end 19 | object qryInsert: TFDQuery 20 | Connection = FDConnection1 21 | SQL.Strings = ( 22 | 'INSERT INTO MESSAGE_LABELS' 23 | '(MESSAGE_ID, LABEL_ID)' 24 | 'VALUES' 25 | '(:MESSAGE_ID, :LABEL_ID);') 26 | Left = 224 27 | Top = 192 28 | ParamData = < 29 | item 30 | Name = 'MESSAGE_ID' 31 | ParamType = ptInput 32 | end 33 | item 34 | Name = 'LABEL_ID' 35 | ParamType = ptInput 36 | end> 37 | end 38 | object qryDelete: TFDQuery 39 | Connection = FDConnection1 40 | SQL.Strings = ( 41 | 42 | 'DELETE FROM MESSAGE_LABELS WHERE MESSAGE_ID =:MESSAGE_ID AND LAB' + 43 | 'EL_ID = :LABEL_ID') 44 | Left = 384 45 | Top = 192 46 | ParamData = < 47 | item 48 | Name = 'MESSAGE_ID' 49 | ParamType = ptInput 50 | end 51 | item 52 | Name = 'LABEL_ID' 53 | ParamType = ptInput 54 | end> 55 | end 56 | end 57 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RADServer Samples 2 | 3 | I plan to add a number of RAD Server Examples here. 4 | Many of the previous RAD Server code snippets are linked to blogs on https://delphiaball.co.uk/tag/rad-server/ 5 | 6 | ## TRESTRequestDataSetAdapter Example 7 | The TRESTResponseDataSetAdapter can be used converts a JSON array response into a TDataSet. 8 | The TRESTRequestDataSetAdapter works in the opposite direction, by coverting a TDataSet into a Post, Put, or Delete request to update the remote data. 9 | The TaskExample sample includes a RAD Server Package and a Client application (just setup the DB path in the package to run it). You can copy and drop the REST.DataUpdater unit into your own application. REST.DataUpdater extend the FireDAC framework to rapidly post updates back to the server. While its recommended to run each request as it comes in, it also allows changes to cache into memory to bulk update. 10 | 11 | Discover the example on YouTube 12 | https://youtu.be/7O1B9LsYUPE 13 | 14 | ## SenchaMail 15 | The SenchaMail sample example uses the SENCHAMAILSERVER.IB database. (found in the data folder) 16 | This is an InterBase database that stores emails, contacts, and labels that are applied to the email. 17 | To use the sample, either place the database at C:\data\SENCHAMAILSERVER.IB or update the connection path in the FDConnection1 components found in unitLabels and unitData. 18 | 19 | The sample acts as a backend for persisting data from the JavaScript client sample created by Stuart98 20 | https://github.com/Stuart98/ext-mail/ 21 | 22 | -------------------------------------------------------------------------------- /Delphi/TasksExample/Simple Server/Unit2.dfm: -------------------------------------------------------------------------------- 1 | object DataResource1: TDataResource1 2 | Height = 558 3 | Width = 778 4 | PixelsPerInch = 192 5 | object FDConnection1: TFDConnection 6 | Params.Strings = ( 7 | 8 | 'Database=C:\Source\git\DelphiABall\RADServer\Delphi\TasksExample' + 9 | '\SIMPLETESTDB.IB' 10 | 'User_Name=sysdba' 11 | 'Password=masterkey' 12 | 'DriverID=IB') 13 | Connected = True 14 | LoginPrompt = False 15 | Left = 94 16 | Top = 24 17 | end 18 | object qryTASKS: TFDQuery 19 | Connection = FDConnection1 20 | UpdateOptions.AssignedValues = [uvGeneratorName] 21 | UpdateOptions.GeneratorName = 'NEWID' 22 | UpdateOptions.AutoIncFields = 'TASK_ID' 23 | SQL.Strings = ( 24 | 'select * from TASKS') 25 | Left = 274 26 | Top = 32 27 | object qryTASKSTASK_ID: TIntegerField 28 | FieldName = 'TASK_ID' 29 | Origin = 'TASK_ID' 30 | Required = True 31 | end 32 | object qryTASKSTASK_NAME: TStringField 33 | FieldName = 'TASK_NAME' 34 | Origin = 'TASK_NAME' 35 | Size = 255 36 | end 37 | object qryTASKSCOMPLETED: TBooleanField 38 | FieldName = 'COMPLETED' 39 | Origin = 'COMPLETED' 40 | Required = True 41 | end 42 | end 43 | object dsrTASKS: TEMSDataSetResource 44 | AllowedActions = [List, Get, Post, Put, Delete] 45 | DataSet = qryTASKS 46 | KeyFields = 'TASK_ID' 47 | Options = [roEnableParams, roEnablePaging, roEnableSorting, roReturnNewEntityKey, roReturnNewEntityValue] 48 | Left = 282 49 | Top = 184 50 | end 51 | end 52 | -------------------------------------------------------------------------------- /Delphi/ChangeViews/ModuleCode/ChangeView.DataConnection.dfm: -------------------------------------------------------------------------------- 1 | object ChangeViewConnection: TChangeViewConnection 2 | Height = 1920 3 | Width = 2560 4 | PixelsPerInch = 192 5 | object FDConnection: TFDConnection 6 | Params.Strings = ( 7 | 'Database=c:\data\sub.ib' 8 | 'User_Name=sysdba' 9 | 'Password=masterkey' 10 | 'DriverID=IB') 11 | TxOptions.Isolation = xiSnapshot 12 | TxOptions.AutoStop = False 13 | TxOptions.DisconnectAction = xdRollback 14 | LoginPrompt = False 15 | Transaction = FDTransaction1 16 | Left = 108 17 | Top = 56 18 | end 19 | object qryData: TFDQuery 20 | Connection = FDConnection 21 | Transaction = FDTransaction1 22 | SQL.Strings = ( 23 | 'select * from HIGHSCORES' 24 | '{if !SORT}order by !SORT{fi}') 25 | Left = 716 26 | Top = 168 27 | MacroData = < 28 | item 29 | Value = Null 30 | Name = 'SORT' 31 | end> 32 | end 33 | object qryActivateChangeView: TFDQuery 34 | Connection = FDConnection 35 | Transaction = FDTransaction1 36 | SecurityOptions.AllowedCommandKinds = [skExecute, skStartTransaction, skCommit, skRollback, skSet] 37 | SecurityOptions.AllowMultiCommands = False 38 | SQL.Strings = ( 39 | 'set subscription !SubscriptionName at !DeviceID active;') 40 | Left = 484 41 | Top = 168 42 | MacroData = < 43 | item 44 | Value = 'sub_highscore' 45 | Name = 'SUBSCRIPTIONNAME' 46 | end 47 | item 48 | Value = 'MyDeviceID' 49 | Name = 'DEVICEID' 50 | DataType = mdString 51 | end> 52 | end 53 | object FDTransaction1: TFDTransaction 54 | Options.Isolation = xiSnapshot 55 | Options.AutoStop = False 56 | Options.DisconnectAction = xdRollback 57 | Connection = FDConnection 58 | Left = 192 59 | Top = 192 60 | end 61 | end 62 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Uncomment these types if you want even more clean repository. But be careful. 2 | # It can make harm to an existing project source. Read explanations below. 3 | # 4 | # Resource files are binaries containing manifest, project icon and version info. 5 | # They can not be viewed as text or compared by diff-tools. Consider replacing them with .rc files. 6 | #*.res 7 | # 8 | # Type library file (binary). In old Delphi versions it should be stored. 9 | # Since Delphi 2009 it is produced from .ridl file and can safely be ignored. 10 | #*.tlb 11 | # 12 | # Diagram Portfolio file. Used by the diagram editor up to Delphi 7. 13 | # Uncomment this if you are not using diagrams or use newer Delphi version. 14 | #*.ddp 15 | # 16 | # Visual LiveBindings file. Added in Delphi XE2. 17 | # Uncomment this if you are not using LiveBindings Designer. 18 | #*.vlb 19 | # 20 | # Deployment Manager configuration file for your project. Added in Delphi XE2. 21 | # Uncomment this if it is not mobile development and you do not use remote debug feature. 22 | #*.deployproj 23 | # 24 | # C++ object files produced when C/C++ Output file generation is configured. 25 | # Uncomment this if you are not using external objects (zlib library for example). 26 | #*.obj 27 | # 28 | 29 | # Delphi compiler-generated binaries (safe to delete) 30 | *.exe 31 | *.dll 32 | *.bpl 33 | *.bpi 34 | *.dcp 35 | *.so 36 | *.apk 37 | *.drc 38 | *.map 39 | *.dres 40 | *.rsm 41 | *.tds 42 | *.dcu 43 | *.lib 44 | *.a 45 | *.o 46 | *.ocx 47 | 48 | # Delphi autogenerated files (duplicated info) 49 | *.cfg 50 | *.hpp 51 | *Resource.rc 52 | 53 | # Delphi local files (user-specific info) 54 | *.local 55 | *.identcache 56 | *.projdata 57 | *.tvsconfig 58 | *.dsk 59 | 60 | # Delphi history and backups 61 | __history/ 62 | __recovery/ 63 | *.~* 64 | 65 | # Castalia statistics file (since XE7 Castalia is distributed with Delphi) 66 | *.stat 67 | 68 | # Boss dependency manager vendor folder https://github.com/HashLoad/boss 69 | modules/ 70 | Delphi/ChangeViews/Client/ChangeViewsEMSThingPoint.res 71 | *.res 72 | -------------------------------------------------------------------------------- /Delphi/TasksExample/pgTaskExample.groupproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | {0E821AB1-738E-4C39-9153-B88AAF8875A4} 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | Default.Personality.12 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /Delphi/ChangeViews/ChangeViewsInEMS.groupproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | {FE7D3E9E-E4DA-4092-9D6E-4CC5FA4418C0} 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | Default.Personality.12 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /Delphi/ChangeViews/Client/formMain.pas: -------------------------------------------------------------------------------- 1 | unit formMain; 2 | 3 | interface 4 | 5 | uses 6 | Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, 7 | Vcl.Controls, Vcl.Forms, Vcl.Dialogs, System.JSON, REST.Backend.EMSServices, 8 | EMSHosting.ExtensionsServices, EMSHosting.EdgeHTTPListener, 9 | REST.Backend.EMSProvider, REST.Backend.Providers, EMSHosting.EdgeService, 10 | Vcl.StdCtrls, ChangeView.Cache, FireDAC.UI.Intf, FireDAC.VCLUI.Wait, 11 | FireDAC.Stan.Intf, FireDAC.Comp.UI, Vcl.ExtCtrls, Vcl.Samples.Spin; 12 | 13 | type 14 | TForm1 = class(TForm) 15 | Button1: TButton; 16 | EMSEdgeService1: TEMSEdgeService; 17 | EMSProvider1: TEMSProvider; 18 | FDGUIxWaitCursor1: TFDGUIxWaitCursor; 19 | MemoStatus: TMemo; 20 | Panel1: TPanel; 21 | Label1: TLabel; 22 | TimerStatsUpdate: TTimer; 23 | TimerSweep: TTimer; 24 | btnSweep: TButton; 25 | seLifeSpanSeconds: TSpinEdit; 26 | Label2: TLabel; 27 | procedure Button1Click(Sender: TObject); 28 | procedure FormCreate(Sender: TObject); 29 | procedure FormClose(Sender: TObject; var Action: TCloseAction); 30 | procedure btnSweepClick(Sender: TObject); 31 | procedure TimerSweepTimer(Sender: TObject); 32 | procedure TimerStatsUpdateTimer(Sender: TObject); 33 | private 34 | { Private declarations } 35 | public 36 | { Public declarations } 37 | end; 38 | 39 | var 40 | Form1: TForm1; 41 | 42 | implementation 43 | 44 | {$R *.dfm} 45 | 46 | procedure TForm1.btnSweepClick(Sender: TObject); 47 | begin 48 | TimerSweep.Enabled := not TimerSweep.Enabled; 49 | btnSweep.Caption := 'Sweep Active = '+ BoolToStr(TimerSweep.Enabled, True); 50 | end; 51 | 52 | procedure TForm1.Button1Click(Sender: TObject); 53 | begin 54 | EMSEdgeService1.Active := not EMSEdgeService1.Active; 55 | Button1.Caption := 'Active = '+ BoolToStr(EMSEdgeService1.Active, True); 56 | end; 57 | 58 | procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); 59 | begin 60 | if EMSEdgeService1.Active then 61 | EMSEdgeService1.Active := False; 62 | end; 63 | 64 | procedure TForm1.FormCreate(Sender: TObject); 65 | begin 66 | Button1.Caption := 'Active = '+ BoolToStr(EMSEdgeService1.Active, True); 67 | end; 68 | 69 | procedure TForm1.TimerStatsUpdateTimer(Sender: TObject); 70 | begin 71 | ChangeViewSessions.GetStats(MemoStatus.Lines); 72 | end; 73 | 74 | procedure TForm1.TimerSweepTimer(Sender: TObject); 75 | begin 76 | TimerSweep.Enabled := False; 77 | try 78 | // Removes Sessions that have passed their allowed inactive time. 79 | ChangeViewSessions.Sweep(seLifeSpanSeconds.Value); 80 | finally 81 | TimerSweep.Enabled := True; 82 | end; 83 | end; 84 | 85 | end. 86 | -------------------------------------------------------------------------------- /Delphi/TasksExample/Simple Client/FormSimple.pas: -------------------------------------------------------------------------------- 1 | unit FormSimple; 2 | 3 | interface 4 | 5 | uses 6 | System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, 7 | FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, REST.Types, 8 | FireDAC.Stan.Intf, FireDAC.Stan.Option, FireDAC.Stan.Param, 9 | FireDAC.Stan.Error, FireDAC.DatS, FireDAC.Phys.Intf, FireDAC.DApt.Intf, 10 | System.Rtti, FMX.Grid.Style, Data.Bind.EngExt, Fmx.Bind.DBEngExt, 11 | Fmx.Bind.Grid, System.Bindings.Outputs, Fmx.Bind.Editors, Data.Bind.Controls, 12 | FMX.Layouts, Fmx.Bind.Navigator, Data.Bind.Components, Data.Bind.Grid, 13 | Data.Bind.DBScope, FMX.Controls.Presentation, FMX.ScrollBox, FMX.Grid, 14 | Data.DB, FireDAC.Comp.DataSet, FireDAC.Comp.Client, REST.Response.Adapter, 15 | REST.Client, Data.Bind.ObjectScope, FMX.StdCtrls, FMX.Memo.Types, FMX.Memo, 16 | FMX.TabControl, FMX.Edit; 17 | 18 | type 19 | TForm1 = class(TForm) 20 | BindNavigator1: TBindNavigator; 21 | Layout1: TLayout; 22 | Button1: TButton; 23 | Button2: TButton; 24 | StringGrid1: TStringGrid; 25 | BindingsList1: TBindingsList; 26 | RESTClient1: TRESTClient; 27 | RESTRequestGet: TRESTRequest; 28 | RESTResponseGet: TRESTResponse; 29 | RESTResponseDataSetAdapterGet: TRESTResponseDataSetAdapter; 30 | FDMemTable1: TFDMemTable; 31 | BindSourceDB2: TBindSourceDB; 32 | LinkGridToDataSourceBindSourceDB2: TLinkGridToDataSource; 33 | Memo1: TMemo; 34 | TabControl1: TTabControl; 35 | TabItem1: TTabItem; 36 | TabItem2: TTabItem; 37 | Label1: TLabel; 38 | Label2: TLabel; 39 | MemoPostBody: TMemo; 40 | Button3: TButton; 41 | procedure Button1Click(Sender: TObject); 42 | procedure Button2Click(Sender: TObject); 43 | procedure Button3Click(Sender: TObject); 44 | private 45 | { Private declarations } 46 | public 47 | { Public declarations } 48 | end; 49 | 50 | var 51 | Form1: TForm1; 52 | 53 | implementation 54 | 55 | {$R *.fmx} 56 | uses REST.DataUpdater; 57 | 58 | procedure TForm1.Button1Click(Sender: TObject); 59 | begin 60 | RESTRequestGet.Execute; 61 | FDMemTable1.CachedUpdates := True; 62 | end; 63 | 64 | procedure TForm1.Button2Click(Sender: TObject); 65 | begin 66 | var Updater := TRestDataSetUpdater.Create(Self,RESTClient1, 'data/tasks/', 'TASK_ID', FDMemTable1); 67 | try 68 | // Uncomment For RAD Studio / Delphi 11.0 as you need to have a dummy param to make the post work. (known issue fixed in 11.1) 69 | // Updater.ResourcePost := Updater.ResourcePost+'/-1'; // Dummy ID for tempory workaround 70 | Updater.ApplyRemoteUpdates(True); 71 | Memo1.Lines.Text := Updater.ErrorLog.Text; 72 | finally 73 | Updater.Free; 74 | end; 75 | 76 | end; 77 | 78 | procedure TForm1.Button3Click(Sender: TObject); 79 | begin 80 | ShowMessage(FDMemTable1.ChangeCount.ToString); 81 | end; 82 | 83 | end. 84 | -------------------------------------------------------------------------------- /Delphi/ChangeViews/ModuleCode/ChangeView.DataConnection.pas: -------------------------------------------------------------------------------- 1 | unit ChangeView.DataConnection; 2 | 3 | interface 4 | 5 | uses 6 | System.SysUtils, System.Classes, FireDAC.Stan.Intf, FireDAC.Stan.Option, 7 | FireDAC.Stan.Error, FireDAC.UI.Intf, FireDAC.Phys.Intf, FireDAC.Stan.Def, 8 | FireDAC.Stan.Pool, FireDAC.Stan.Async, FireDAC.Phys, FireDAC.Phys.IB, 9 | FireDAC.Phys.IBDef, FireDAC.ConsoleUI.Wait, FireDAC.Stan.Param, FireDAC.DatS, 10 | FireDAC.DApt.Intf, FireDAC.DApt, Data.DB, FireDAC.Comp.DataSet, 11 | FireDAC.Comp.Client; 12 | 13 | type 14 | TChangeViewConnection = class(TDataModule) 15 | FDConnection: TFDConnection; 16 | qryData: TFDQuery; 17 | qryActivateChangeView: TFDQuery; 18 | FDTransaction1: TFDTransaction; 19 | private 20 | FLastCalled : TDateTime; 21 | function GetDeviceID: string; 22 | function GetSubscriptionName: string; 23 | 24 | { Private declarations } 25 | public 26 | { Public declarations } 27 | constructor Create(AOwner : TComponent; Const ADeviceID, ASubscription : String); 28 | destructor Destroy; override; 29 | 30 | procedure Activate; 31 | 32 | procedure CommitChangeView; 33 | procedure RollBackChangeView; 34 | // Updates the date time for a last made change 35 | procedure MarkAsActive; 36 | 37 | property DeviceID : string read GetDeviceID; 38 | property SubscriptionName : string read GetSubscriptionName; 39 | property LatestActivity : TDateTime read FLastCalled; 40 | end; 41 | 42 | implementation 43 | 44 | {%CLASSGROUP 'System.Classes.TPersistent'} 45 | 46 | {$R *.dfm} 47 | 48 | 49 | procedure TChangeViewConnection.Activate; 50 | begin 51 | if not FDConnection.Connected then 52 | FDConnection.Connected := True; 53 | 54 | if not FDConnection.Transaction.Active then 55 | FDConnection.StartTransaction; 56 | 57 | qryActivateChangeView.ExecSQL; 58 | 59 | MarkAsActive; 60 | end; 61 | 62 | procedure TChangeViewConnection.CommitChangeView; 63 | begin 64 | if FDConnection.Transaction.Active then 65 | FDConnection.Commit; 66 | 67 | MarkAsActive; 68 | end; 69 | 70 | { TdataHighScoreConnection } 71 | 72 | constructor TChangeViewConnection.Create(AOwner: TComponent; const ADeviceID, ASubscription: String); 73 | begin 74 | Assert(ADeviceID > '','Invalid DeviceID'); 75 | Assert(ASubscription > '','Invalid Subscription'); 76 | 77 | inherited Create(AOwner); 78 | 79 | qryActivateChangeView.MacroByName('SubscriptionName').AsString := ASubscription; //'sub_highscore'; 80 | qryActivateChangeView.MacroByName('DeviceID').AsString := ADeviceID; 81 | 82 | MarkAsActive; 83 | end; 84 | 85 | destructor TChangeViewConnection.Destroy; 86 | begin 87 | if FDConnection.Transaction.Active then 88 | RollBackChangeView; 89 | inherited; 90 | end; 91 | 92 | function TChangeViewConnection.GetDeviceID: string; 93 | begin 94 | Result := qryActivateChangeView.MacroByName('DeviceID').AsString; 95 | end; 96 | 97 | procedure TChangeViewConnection.MarkAsActive; 98 | begin 99 | FLastCalled := Now; 100 | end; 101 | 102 | procedure TChangeViewConnection.RollBackChangeView; 103 | begin 104 | if FDConnection.Transaction.Active then 105 | FDConnection.Rollback; 106 | 107 | MarkAsActive; 108 | end; 109 | 110 | function TChangeViewConnection.GetSubscriptionName : string; 111 | begin 112 | Result := qryActivateChangeView.MacroByName('SubscriptionName').AsString; 113 | end; 114 | 115 | end. 116 | -------------------------------------------------------------------------------- /Delphi/ChangeViews/Client/formMain.dfm: -------------------------------------------------------------------------------- 1 | object Form1: TForm1 2 | Left = 0 3 | Top = 0 4 | Margins.Left = 6 5 | Margins.Top = 6 6 | Margins.Right = 6 7 | Margins.Bottom = 6 8 | Caption = 'Form1' 9 | ClientHeight = 943 10 | ClientWidth = 1274 11 | Color = clBtnFace 12 | Font.Charset = DEFAULT_CHARSET 13 | Font.Color = clWindowText 14 | Font.Height = -24 15 | Font.Name = 'Segoe UI' 16 | Font.Style = [] 17 | OnClose = FormClose 18 | OnCreate = FormCreate 19 | PixelsPerInch = 192 20 | DesignSize = ( 21 | 1274 22 | 943) 23 | TextHeight = 32 24 | object Label1: TLabel 25 | Left = 0 26 | Top = 145 27 | Width = 1274 28 | Height = 32 29 | Margins.Left = 6 30 | Margins.Top = 6 31 | Margins.Right = 6 32 | Margins.Bottom = 6 33 | Align = alTop 34 | Caption = 'Stats' 35 | ExplicitWidth = 50 36 | end 37 | object Label2: TLabel 38 | Left = 24 39 | Top = 628 40 | Width = 295 41 | Height = 32 42 | Margins.Left = 6 43 | Margins.Top = 6 44 | Margins.Right = 6 45 | Margins.Bottom = 6 46 | Caption = 'Sessions Lifespan (Seconds)' 47 | end 48 | object MemoStatus: TMemo 49 | Left = 0 50 | Top = 177 51 | Width = 1274 52 | Height = 376 53 | Margins.Left = 6 54 | Margins.Top = 6 55 | Margins.Right = 6 56 | Margins.Bottom = 6 57 | Align = alTop 58 | Lines.Strings = ( 59 | 'MemoStatus') 60 | TabOrder = 0 61 | end 62 | object Panel1: TPanel 63 | Left = 0 64 | Top = 0 65 | Width = 1274 66 | Height = 145 67 | Margins.Left = 6 68 | Margins.Top = 6 69 | Margins.Right = 6 70 | Margins.Bottom = 6 71 | Align = alTop 72 | BevelOuter = bvNone 73 | TabOrder = 1 74 | object Button1: TButton 75 | Left = 24 76 | Top = 33 77 | Width = 233 78 | Height = 81 79 | Caption = 'Button1' 80 | TabOrder = 0 81 | OnClick = Button1Click 82 | end 83 | end 84 | object seLifeSpanSeconds: TSpinEdit 85 | Left = 416 86 | Top = 625 87 | Width = 185 88 | Height = 43 89 | Margins.Left = 6 90 | Margins.Top = 6 91 | Margins.Right = 6 92 | Margins.Bottom = 6 93 | MaxValue = 3600 94 | MinValue = 5 95 | TabOrder = 2 96 | Value = 60 97 | end 98 | object btnSweep: TButton 99 | Left = 24 100 | Top = 688 101 | Width = 577 102 | Height = 95 103 | Margins.Left = 6 104 | Margins.Top = 6 105 | Margins.Right = 6 106 | Margins.Bottom = 6 107 | Anchors = [akTop, akRight] 108 | Caption = 'Sweep' 109 | TabOrder = 3 110 | OnClick = btnSweepClick 111 | end 112 | object EMSEdgeService1: TEMSEdgeService 113 | ModuleName = 'ChangeViewsDemo' 114 | ModuleVersion = '1' 115 | Provider = EMSProvider1 116 | ListenerProtocol = 'http' 117 | ListenerService.Port = 8888 118 | ListenerService.Host = 'localhost' 119 | Left = 1000 120 | Top = 304 121 | end 122 | object EMSProvider1: TEMSProvider 123 | ApiVersion = '2' 124 | URLHost = 'localhost' 125 | URLPort = 8080 126 | Left = 832 127 | Top = 280 128 | end 129 | object FDGUIxWaitCursor1: TFDGUIxWaitCursor 130 | Provider = 'Forms' 131 | ScreenCursor = gcrHourGlass 132 | Left = 688 133 | Top = 552 134 | end 135 | object TimerStatsUpdate: TTimer 136 | OnTimer = TimerStatsUpdateTimer 137 | Left = 848 138 | Top = 56 139 | end 140 | object TimerSweep: TTimer 141 | OnTimer = TimerSweepTimer 142 | Left = 1136 143 | Top = 72 144 | end 145 | end 146 | -------------------------------------------------------------------------------- /SenchaMail/unitLabels.pas: -------------------------------------------------------------------------------- 1 | unit unitLabels; 2 | 3 | // EMS Resource Module 4 | 5 | interface 6 | 7 | uses 8 | System.SysUtils, System.Classes, System.JSON, 9 | EMS.Services, EMS.ResourceAPI, EMS.ResourceTypes, FireDAC.Stan.Intf, 10 | FireDAC.Stan.Option, FireDAC.Stan.Error, FireDAC.UI.Intf, FireDAC.Phys.Intf, 11 | FireDAC.Stan.Def, FireDAC.Stan.Pool, FireDAC.Stan.Async, FireDAC.Phys, 12 | FireDAC.Phys.IB, FireDAC.Phys.IBDef, FireDAC.ConsoleUI.Wait, Data.DB, 13 | FireDAC.Comp.Client, FireDAC.Stan.Param, FireDAC.DatS, FireDAC.DApt.Intf, 14 | FireDAC.DApt, FireDAC.Comp.DataSet; 15 | 16 | type 17 | [ResourceName('labels')] 18 | TLabelsResource1 = class(TDataModule) 19 | FDConnection1: TFDConnection; 20 | qryInsert: TFDQuery; 21 | qryDelete: TFDQuery; 22 | published 23 | 24 | [EndPointRequestSummary('Tests', 'PostItem', 'Creates new item', '', 'application/json')] 25 | [EndPointRequestParameter(TAPIDocParameter.TParameterIn.Body, 'body', 'A new item content', true, TAPIDoc.TPrimitiveType.spObject, 26 | TAPIDoc.TPrimitiveFormat.None, TAPIDoc.TPrimitiveType.spObject, '', '')] 27 | [EndPointResponseDetails(200, 'Ok', TAPIDoc.TPrimitiveType.spNull, TAPIDoc.TPrimitiveFormat.None, '', '')] 28 | [EndPointResponseDetails(409, 'Item Exist', TAPIDoc.TPrimitiveType.spNull, TAPIDoc.TPrimitiveFormat.None, '', '')] 29 | [ResourceSuffix('{messageid}/{labelid}')] 30 | procedure Post(const AContext: TEndpointContext; const ARequest: TEndpointRequest; const AResponse: TEndpointResponse); 31 | 32 | [EndPointRequestSummary('Tests', 'DeleteItem', 'Deletes item with specified ID', '', '')] 33 | [EndPointRequestParameter(TAPIDocParameter.TParameterIn.Path, 'item', 'A item ID', true, TAPIDoc.TPrimitiveType.spString, 34 | TAPIDoc.TPrimitiveFormat.None, TAPIDoc.TPrimitiveType.spString, '', '')] 35 | [EndPointResponseDetails(200, 'Ok', TAPIDoc.TPrimitiveType.spNull, TAPIDoc.TPrimitiveFormat.None, '', '')] 36 | [EndPointResponseDetails(404, 'Not Found', TAPIDoc.TPrimitiveType.spNull, TAPIDoc.TPrimitiveFormat.None, '', '')] 37 | [ResourceSuffix('{messageid}/{labelid}')] 38 | procedure DeleteItem(const AContext: TEndpointContext; const ARequest: TEndpointRequest; const AResponse: TEndpointResponse); 39 | end; 40 | 41 | implementation 42 | 43 | {%CLASSGROUP 'System.Classes.TPersistent'} 44 | 45 | {$R *.dfm} 46 | 47 | procedure TLabelsResource1.Post(const AContext: TEndpointContext; const ARequest: TEndpointRequest; const AResponse: TEndpointResponse); 48 | var 49 | FMessageID, FLabelID: string; 50 | begin 51 | FLabelID := ARequest.Params.Values['labelid']; 52 | FMessageID := ARequest.Params.Values['messageid']; 53 | 54 | if StrToIntDef(FMessageID,-1) < 0 then 55 | AResponse.RaiseNotFound('Invalid Message ID'); 56 | if StrToIntDef(FLabelID,-1) < 0 then 57 | AResponse.RaiseNotFound('Invalid Label ID'); 58 | 59 | qryInsert.ParamByName('MESSAGE_ID').AsString := FMessageID; 60 | qryInsert.ParamByName('LABEL_ID').AsString := FLabelID; 61 | try 62 | qryInsert.ExecSQL; 63 | except 64 | on e:Exception do 65 | AResponse.RaiseDuplicate('Duplicate message label'); 66 | end; 67 | 68 | end; 69 | 70 | procedure TLabelsResource1.DeleteItem(const AContext: TEndpointContext; const ARequest: TEndpointRequest; const AResponse: TEndpointResponse); 71 | var 72 | FMessageID, FLabelID: string; 73 | begin 74 | FMessageID := ARequest.Params.Values['messageid']; 75 | FLabelID := ARequest.Params.Values['labelid']; 76 | 77 | if StrToIntDef(FMessageID,-1) < 0 then 78 | AResponse.RaiseNotFound('Invalid Message ID'); 79 | if StrToIntDef(FLabelID,-1) < 0 then 80 | AResponse.RaiseNotFound('Invalid Label ID'); 81 | 82 | qryDelete.ParamByName('MESSAGE_ID').AsString := FMessageID; 83 | qryDelete.ParamByName('LABEL_ID').AsString := FLabelID; 84 | 85 | try 86 | qryDelete.ExecSQL; 87 | except 88 | on e:Exception do 89 | AResponse.RaiseBadRequest('Invalid Request',e.message); 90 | end; 91 | 92 | end; 93 | 94 | procedure Register; 95 | begin 96 | RegisterResource(TypeInfo(TLabelsResource1)); 97 | end; 98 | 99 | initialization 100 | Register; 101 | end. 102 | 103 | 104 | -------------------------------------------------------------------------------- /SenchaMail/unitData.dfm: -------------------------------------------------------------------------------- 1 | object MailResource1: TMailResource1 2 | Height = 514 3 | Width = 1176 4 | PixelsPerInch = 192 5 | object FDConnection1: TFDConnection 6 | Params.Strings = ( 7 | 'Database=C:\data\SENCHAMAILSERVER.IB' 8 | 'User_Name=SYSDBA' 9 | 'Password=masterkey' 10 | 'Port=3050' 11 | 'InstanceName=instance2' 12 | 'DriverID=IB') 13 | UpdateOptions.AssignedValues = [uvGeneratorName] 14 | UpdateOptions.GeneratorName = 'G_ID' 15 | LoginPrompt = False 16 | Left = 60 17 | Top = 32 18 | end 19 | object qryCONTACTS: TFDQuery 20 | Connection = FDConnection1 21 | UpdateOptions.KeyFields = 'ID' 22 | UpdateOptions.AutoIncFields = 'ID' 23 | SQL.Strings = ( 24 | 'select * from CONTACTS') 25 | Left = 260 26 | Top = 32 27 | object qryCONTACTSID: TFDAutoIncField 28 | FieldName = 'ID' 29 | Origin = 'ID' 30 | ProviderFlags = [pfInUpdate, pfInWhere, pfInKey] 31 | IdentityInsert = True 32 | end 33 | object qryCONTACTSFIRST_NAME: TStringField 34 | FieldName = 'FIRST_NAME' 35 | Origin = 'FIRST_NAME' 36 | Size = 50 37 | end 38 | object qryCONTACTSLAST_NAME: TStringField 39 | FieldName = 'LAST_NAME' 40 | Origin = 'LAST_NAME' 41 | Size = 50 42 | end 43 | object qryCONTACTSEMAIL: TStringField 44 | FieldName = 'EMAIL' 45 | Origin = 'EMAIL' 46 | Size = 320 47 | end 48 | end 49 | object dsrCONTACTS: TEMSDataSetResource 50 | AllowedActions = [List, Get, Post, Put, Delete] 51 | DataSet = qryCONTACTS 52 | KeyFields = 'ID' 53 | PageSize = 20 54 | Left = 260 55 | Top = 144 56 | end 57 | object qryLABELS: TFDQuery 58 | Connection = FDConnection1 59 | UpdateOptions.KeyFields = 'ID' 60 | UpdateOptions.AutoIncFields = 'ID' 61 | SQL.Strings = ( 62 | 'select * from LABELS') 63 | Left = 460 64 | Top = 32 65 | object qryLABELSID: TIntegerField 66 | AutoGenerateValue = arAutoInc 67 | FieldName = 'ID' 68 | Origin = 'ID' 69 | ProviderFlags = [pfInUpdate, pfInWhere, pfInKey] 70 | Required = True 71 | end 72 | object qryLABELSPARENT_ID: TIntegerField 73 | FieldName = 'PARENT_ID' 74 | Origin = 'PARENT_ID' 75 | end 76 | object qryLABELSNAME: TStringField 77 | FieldName = 'NAME' 78 | Origin = 'NAME' 79 | Required = True 80 | Size = 50 81 | end 82 | object qryLABELSLEAF: TBooleanField 83 | FieldName = 'LEAF' 84 | Origin = 'LEAF' 85 | Required = True 86 | end 87 | object qryLABELSEXPANDED: TBooleanField 88 | FieldName = 'EXPANDED' 89 | Origin = 'EXPANDED' 90 | Required = True 91 | end 92 | end 93 | object dsrLABELS: TEMSDataSetResource 94 | AllowedActions = [List, Get, Post, Put, Delete] 95 | DataSet = qryLABELS 96 | KeyFields = 'ID' 97 | Left = 460 98 | Top = 144 99 | end 100 | object qryMESSAGES: TFDQuery 101 | Connection = FDConnection1 102 | UpdateOptions.AssignedValues = [uvGeneratorName] 103 | UpdateOptions.GeneratorName = 'G_ID' 104 | UpdateOptions.KeyFields = 'ID' 105 | UpdateOptions.AutoIncFields = 'ID' 106 | SQL.Strings = ( 107 | 'select * from MESSAGES') 108 | Left = 660 109 | Top = 32 110 | object qryMESSAGESID: TIntegerField 111 | FieldName = 'ID' 112 | Origin = 'ID' 113 | ProviderFlags = [pfInUpdate, pfInWhere, pfInKey] 114 | Required = True 115 | end 116 | object qryMESSAGESFIRST_NAME: TStringField 117 | FieldName = 'FIRST_NAME' 118 | Origin = 'FIRST_NAME' 119 | Size = 50 120 | end 121 | object qryMESSAGESLAST_NAME: TStringField 122 | FieldName = 'LAST_NAME' 123 | Origin = 'LAST_NAME' 124 | Size = 50 125 | end 126 | object qryMESSAGESEMAIL: TStringField 127 | FieldName = 'EMAIL' 128 | Origin = 'EMAIL' 129 | Size = 320 130 | end 131 | object qryMESSAGESDATE: TSQLTimeStampField 132 | FieldName = 'DATE' 133 | Origin = '"DATE"' 134 | Required = True 135 | end 136 | object qryMESSAGESSUBJECT: TStringField 137 | FieldName = 'SUBJECT' 138 | Origin = 'SUBJECT' 139 | Size = 998 140 | end 141 | object qryMESSAGESMESSAGE: TMemoField 142 | FieldName = 'MESSAGE' 143 | Origin = '"MESSAGE"' 144 | BlobType = ftMemo 145 | end 146 | object qryMESSAGESUNREAD: TBooleanField 147 | FieldName = 'UNREAD' 148 | Origin = 'UNREAD' 149 | Required = True 150 | end 151 | object qryMESSAGESDRAFT: TBooleanField 152 | FieldName = 'DRAFT' 153 | Origin = 'DRAFT' 154 | Required = True 155 | end 156 | object qryMESSAGESSENT: TBooleanField 157 | FieldName = 'SENT' 158 | Origin = 'SENT' 159 | Required = True 160 | end 161 | object qryMESSAGESSTARRED: TBooleanField 162 | FieldName = 'STARRED' 163 | Origin = 'STARRED' 164 | Required = True 165 | end 166 | object qryMESSAGESOUTGOING: TBooleanField 167 | FieldName = 'OUTGOING' 168 | Origin = 'OUTGOING' 169 | Required = True 170 | end 171 | end 172 | object dsrMESSAGES: TEMSDataSetResource 173 | AllowedActions = [List, Get, Post, Put, Delete] 174 | DataSet = qryMESSAGES 175 | KeyFields = 'ID' 176 | PageSize = 100 177 | Left = 660 178 | Top = 144 179 | end 180 | object qryMESSAGE_LABELS: TFDQuery 181 | MasterSource = dsMessages 182 | MasterFields = 'ID' 183 | DetailFields = 'MESSAGE_ID' 184 | Connection = FDConnection1 185 | SQL.Strings = ( 186 | 'select * from MESSAGE_LABELS') 187 | Left = 916 188 | Top = 32 189 | end 190 | object dsrMESSAGE_LABELS: TEMSDataSetResource 191 | AllowedActions = [List] 192 | DataSet = qryMESSAGE_LABELS 193 | KeyFields = 'MESSAGE_ID;LABEL_ID' 194 | PageSize = 100 195 | Left = 916 196 | Top = 144 197 | end 198 | object dsMessages: TDataSource 199 | DataSet = qryMESSAGES 200 | Left = 912 201 | Top = 336 202 | end 203 | object qryLabelChildren: TFDQuery 204 | Connection = FDConnection1 205 | SQL.Strings = ( 206 | 'select * from LABELS') 207 | Left = 452 208 | Top = 320 209 | end 210 | end 211 | -------------------------------------------------------------------------------- /Delphi/ChangeViews/ModuleCode/HighScores.API.pas: -------------------------------------------------------------------------------- 1 | unit HighScores.API; 2 | 3 | // EMS Resource Module 4 | 5 | interface 6 | 7 | uses 8 | System.SysUtils, System.Classes, System.JSON, 9 | EMS.Services, EMS.ResourceAPI, EMS.ResourceTypes, FireDAC.Stan.Intf, 10 | FireDAC.Stan.Option, FireDAC.Stan.Error, FireDAC.UI.Intf, FireDAC.Phys.Intf, 11 | FireDAC.Stan.Def, FireDAC.Stan.Pool, FireDAC.Stan.Async, FireDAC.Phys, 12 | FireDAC.Phys.IB, FireDAC.Phys.IBDef, FireDAC.ConsoleUI.Wait, 13 | FireDAC.Stan.Param, FireDAC.DatS, FireDAC.DApt.Intf, FireDAC.DApt, 14 | EMS.DataSetResource, Data.DB, FireDAC.Comp.DataSet, FireDAC.Comp.Client, 15 | ChangeView.Cache, HighScores.Params; 16 | 17 | type 18 | [ResourceName('highscores')] 19 | TdataHighscoresResource = class(TDataModule) 20 | FDConnection1: TFDConnection; 21 | qryHIGHSCORES: TFDQuery; 22 | 23 | [ResourceSuffix('./')] 24 | dsrHIGHSCORES: TEMSDataSetResource; 25 | published 26 | 27 | // [EndPointRequestSummary('Tests', 'ListItems', 'Retrieves list of items', 'application/json', '')] 28 | // [EndPointResponseDetails(200, 'Ok', TAPIDoc.TPrimitiveType.spObject, TAPIDoc.TPrimitiveFormat.None, '', '')] 29 | // procedure Get(const AContext: TEndpointContext; const ARequest: TEndpointRequest; const AResponse: TEndpointResponse); 30 | // 31 | // [EndPointRequestSummary('Tests', 'GetItem', 'Retrieves item with specified ID', 'application/json', '')] 32 | // [EndPointRequestParameter(TAPIDocParameter.TParameterIn.Path, 'item', 'A item ID', true, TAPIDoc.TPrimitiveType.spString, 33 | // TAPIDoc.TPrimitiveFormat.None, TAPIDoc.TPrimitiveType.spString, '', '')] 34 | // [EndPointResponseDetails(200, 'Ok', TAPIDoc.TPrimitiveType.spObject, TAPIDoc.TPrimitiveFormat.None, '', '')] 35 | // [EndPointResponseDetails(404, 'Not Found', TAPIDoc.TPrimitiveType.spNull, TAPIDoc.TPrimitiveFormat.None, '', '')] 36 | 37 | [ResourceSuffix('./CHANGEVIEW/ACTIVATE')] 38 | procedure GetActivateChangeView(const AContext: TEndpointContext; const ARequest: TEndpointRequest; const AResponse: TEndpointResponse); 39 | 40 | [ResourceSuffix('./CHANGEVIEW/QUERY')] 41 | procedure GetQueryChangeView(const AContext: TEndpointContext; const ARequest: TEndpointRequest; const AResponse: TEndpointResponse); 42 | 43 | [ResourceSuffix('./CHANGEVIEW/COMMIT')] 44 | procedure GetCommitChangeView(const AContext: TEndpointContext; const ARequest: TEndpointRequest; const AResponse: TEndpointResponse); 45 | 46 | [ResourceSuffix('./CHANGEVIEW/ROLLBACK')] 47 | procedure GetRollBackChangeView(const AContext: TEndpointContext; const ARequest: TEndpointRequest; const AResponse: TEndpointResponse); 48 | 49 | end; 50 | 51 | implementation 52 | 53 | {%CLASSGROUP 'System.Classes.TPersistent'} 54 | 55 | uses Data.DBJson; 56 | 57 | {$R *.dfm} 58 | 59 | procedure TdataHighscoresResource.GetActivateChangeView(const AContext: TEndpointContext; const ARequest: TEndpointRequest; const AResponse: TEndpointResponse); 60 | begin 61 | // Get the ChangeView Name and the Device ID 62 | // Return the Internal Session ID where the DataModule with the active transaction is stored. 63 | var Params := TChangeViewParams.Create(AContext, ARequest, AResponse); 64 | 65 | var CVS := ChangeViewSessions.FindDeviceSession(Params.ChangeViewName, Params.DeviceID, True); 66 | CVS.Activate; 67 | 68 | if CVS <> nil then 69 | AResponse.Body.SetValue(TJSONString.Create(CVS.SubscriptionName+' Active for '+CVS.DeviceID), True) 70 | else 71 | AResponse.Body.SetValue(TJSONString.Create('Active failed'), True); 72 | 73 | end; 74 | 75 | procedure TdataHighscoresResource.GetQueryChangeView(const AContext: TEndpointContext; const ARequest: TEndpointRequest; const AResponse: TEndpointResponse); 76 | begin 77 | // AResponse.Body.SetValue(TJSONString.Create('Query ChangeView'), True); 78 | var Params := TChangeViewParams.Create(AContext, ARequest, AResponse); 79 | 80 | var CVS := ChangeViewSessions.FindDeviceSession(Params.ChangeViewName, Params.DeviceID, True); 81 | 82 | if CVS.FDConnection.Transaction.Active = False then 83 | CVS.Activate; 84 | 85 | var QueryOption : string := ARequest.Params.Values['query']; 86 | 87 | if LowerCase(QueryOption) = 'count' then 88 | begin 89 | CVS.qryData.Open('SELECT COUNT(*) as "COUNT" FROM HIGHSCORES') 90 | end else 91 | begin 92 | CVS.qryData.Open('SELECT * FROM HIGHSCORES'); 93 | end; 94 | 95 | var lBridge := TDataSetToJSONBridge.Create; 96 | // takes the current record of the master query and converts it to a JSON object 97 | lBridge.Dataset := CVS.qryData; 98 | lBridge.IncludeNulls := True; 99 | // specifies that the we only require to process the current record 100 | lBridge.Area := TJSONDataSetArea.All; 101 | // adds the master record as an object in the JSON result 102 | lBridge.Produce(AResponse.Body.JSONWriter); 103 | 104 | end; 105 | 106 | procedure TdataHighscoresResource.GetCommitChangeView(const AContext: TEndpointContext; const ARequest: TEndpointRequest; const AResponse: TEndpointResponse); 107 | begin 108 | var Params := TChangeViewParams.Create(AContext, ARequest, AResponse); 109 | var CVC := ChangeViewSessions.FindDeviceSession(Params.ChangeViewName, Params.DeviceID, True); 110 | CVC.CommitChangeView; 111 | 112 | // Remove from Cache... all done!! 113 | var CVS := ChangeViewSessions.FindChangeViewSessions(Params.ChangeViewName); 114 | if Assigned(CVS) then 115 | CVS.CloseSession(Params.DeviceID); 116 | AResponse.Body.SetValue(TJSONString.Create(Format('ChangeView %s for %s Commited', [Params.ChangeViewName, Params.DeviceID])), True); 117 | end; 118 | 119 | procedure TdataHighscoresResource.GetRollBackChangeView(const AContext: TEndpointContext; const ARequest: TEndpointRequest; const AResponse: TEndpointResponse); 120 | begin 121 | var Params := TChangeViewParams.Create(AContext, ARequest, AResponse); 122 | var CVC := ChangeViewSessions.FindDeviceSession(Params.ChangeViewName, Params.DeviceID, True); 123 | CVC.RollBackChangeView; 124 | 125 | // Remove from Cache... all done!! 126 | var CVS := ChangeViewSessions.FindChangeViewSessions(Params.ChangeViewName); 127 | if Assigned(CVS) then 128 | CVS.CloseSession(Params.DeviceID); 129 | AResponse.Body.SetValue(TJSONString.Create(Format('ChangeView %s for %s Rolledback', [Params.ChangeViewName, Params.DeviceID])), True); 130 | 131 | end; 132 | 133 | 134 | procedure Register; 135 | begin 136 | RegisterResource(TypeInfo(TdataHighscoresResource)); 137 | end; 138 | 139 | initialization 140 | Register; 141 | end. 142 | 143 | 144 | -------------------------------------------------------------------------------- /SenchaMail/unitData.pas: -------------------------------------------------------------------------------- 1 | unit unitData; 2 | 3 | // EMS Resource Module 4 | 5 | interface 6 | 7 | uses 8 | System.SysUtils, System.Classes, System.JSON, 9 | EMS.Services, EMS.ResourceAPI, EMS.ResourceTypes, FireDAC.Stan.Intf, 10 | FireDAC.Stan.Option, FireDAC.Stan.Error, FireDAC.UI.Intf, FireDAC.Phys.Intf, 11 | FireDAC.Stan.Def, FireDAC.Stan.Pool, FireDAC.Stan.Async, FireDAC.Phys, 12 | FireDAC.Phys.IB, FireDAC.Phys.IBDef, FireDAC.ConsoleUI.Wait, 13 | FireDAC.Stan.Param, FireDAC.DatS, FireDAC.DApt.Intf, FireDAC.DApt, 14 | EMS.DataSetResource, Data.DB, FireDAC.Comp.DataSet, FireDAC.Comp.Client; 15 | 16 | type 17 | [ResourceName('data')] 18 | TMailResource1 = class(TDataModule) 19 | FDConnection1: TFDConnection; 20 | qryCONTACTS: TFDQuery; 21 | [ResourceSuffix('contacts')] 22 | dsrCONTACTS: TEMSDataSetResource; 23 | qryLABELS: TFDQuery; 24 | [ResourceSuffix('labels')] 25 | dsrLABELS: TEMSDataSetResource; 26 | qryMESSAGES: TFDQuery; 27 | [ResourceSuffix('messages')] 28 | dsrMESSAGES: TEMSDataSetResource; 29 | qryMESSAGE_LABELS: TFDQuery; 30 | [ResourceSuffix('message_labels')] 31 | dsrMESSAGE_LABELS: TEMSDataSetResource; 32 | dsMessages: TDataSource; 33 | qryLabelChildren: TFDQuery; 34 | qryLABELSID: TIntegerField; 35 | qryLABELSPARENT_ID: TIntegerField; 36 | qryLABELSNAME: TStringField; 37 | qryLABELSLEAF: TBooleanField; 38 | qryLABELSEXPANDED: TBooleanField; 39 | qryCONTACTSID: TFDAutoIncField; 40 | qryCONTACTSFIRST_NAME: TStringField; 41 | qryCONTACTSLAST_NAME: TStringField; 42 | qryCONTACTSEMAIL: TStringField; 43 | qryMESSAGESFIRST_NAME: TStringField; 44 | qryMESSAGESLAST_NAME: TStringField; 45 | qryMESSAGESEMAIL: TStringField; 46 | qryMESSAGESDATE: TSQLTimeStampField; 47 | qryMESSAGESSUBJECT: TStringField; 48 | qryMESSAGESMESSAGE: TMemoField; 49 | qryMESSAGESUNREAD: TBooleanField; 50 | qryMESSAGESDRAFT: TBooleanField; 51 | qryMESSAGESSENT: TBooleanField; 52 | qryMESSAGESSTARRED: TBooleanField; 53 | qryMESSAGESOUTGOING: TBooleanField; 54 | qryMESSAGESID: TIntegerField; 55 | 56 | published 57 | [ResourceSuffix('messagesfull')] 58 | [EndPointRequestSummary('messages', 'Get messages (with labels)', 'Retrieves list of messages with their labels', 'application/json', '')] 59 | [EndPointResponseDetails(200, 'Ok', TAPIDoc.TPrimitiveType.spObject, TAPIDoc.TPrimitiveFormat.None, '', '')] 60 | procedure Get(const AContext: TEndpointContext; const ARequest: TEndpointRequest; const AResponse: TEndpointResponse); 61 | 62 | [ResourceSuffix('labelsnested')] 63 | [EndPointRequestSummary('labels', 'Get list of labels in their nested structure', 'Retrieves list of labels', 'application/json', '')] 64 | [EndPointResponseDetails(200, 'Ok', TAPIDoc.TPrimitiveType.spObject, TAPIDoc.TPrimitiveFormat.None, '', '')] 65 | procedure GetLabels(const AContext: TEndpointContext; const ARequest: TEndpointRequest; const AResponse: TEndpointResponse); 66 | end; 67 | 68 | implementation 69 | 70 | {%CLASSGROUP 'System.Classes.TPersistent'} 71 | 72 | {$R *.dfm} 73 | 74 | procedure ConvertRecordToJSONObject( 75 | const AResponse: TEndpointResponse; 76 | DataSet : TDataSet; 77 | MasterField : string = ''; 78 | IncFieldName : Boolean = True); 79 | var 80 | FieldIdx : Integer; 81 | begin 82 | for FieldIdx := 0 to DataSet.FieldCount -1 do 83 | begin 84 | // Skip master field 85 | if (MasterField > '') and 86 | (Uppercase(MasterField) = 87 | Uppercase(DataSet.Fields[FieldIdx]. 88 | FieldName)) then 89 | Continue; 90 | 91 | // Add name value pairs (except if labels array, just write the values) 92 | if IncFieldName then 93 | if DataSet.Fields[FieldIdx].DisplayName > '' then 94 | AResponse.Body.JSONWriter.WritePropertyName(DataSet.Fields[FieldIdx].DisplayName) 95 | else 96 | AResponse.Body.JSONWriter.WritePropertyName(DataSet.Fields[FieldIdx].FieldName); 97 | 98 | case DataSet.Fields[FieldIdx].DataType of 99 | ftSmallint, 100 | ftInteger, 101 | ftWord, 102 | ftLargeint, 103 | ftLongWord, 104 | ftShortint : AResponse.Body.JSONWriter.WriteValue(DataSet.Fields[FieldIdx].AsInteger); 105 | 106 | ftFloat, 107 | ftCurrency, 108 | ftExtended, 109 | ftSingle : AResponse.Body.JSONWriter.WriteValue(DataSet.Fields[FieldIdx].AsFloat); 110 | 111 | ftBoolean : AResponse.Body.JSONWriter.WriteValue(DataSet.Fields[FieldIdx].AsBoolean); 112 | 113 | ftDate, 114 | ftDateTime, 115 | ftTimeStamp, 116 | ftOraTimeStamp : AResponse.Body.JSONWriter.WriteValue(DataSet.Fields[FieldIdx].AsDateTime); 117 | 118 | else 119 | AResponse.Body.JSONWriter.WriteValue(DataSet.Fields[FieldIdx].AsString); 120 | end; 121 | end; 122 | end; 123 | 124 | procedure TMailResource1.Get(const AContext: TEndpointContext; const ARequest: TEndpointRequest; const AResponse: TEndpointResponse); 125 | begin 126 | qryMESSAGES.Open; 127 | qryMESSAGE_LABELS.Open('SELECT * FROM MESSAGE_LABELS WHERE MESSAGE_ID = :ID'); 128 | 129 | AResponse.Body.JSONWriter.WriteStartArray; 130 | 131 | qryMessages.First; 132 | while not qryMessages.Eof do begin 133 | // Build Message 134 | AResponse.Body.JSONWriter.WriteStartObject; 135 | ConvertRecordToJSONObject(AResponse,qryMessages); 136 | 137 | // Add the Labels 138 | AResponse.Body.JSONWriter.WritePropertyName('labels'); 139 | AResponse.Body.JSONWriter.WriteStartArray; 140 | qryMessage_Labels.First; 141 | 142 | while not qryMessage_Labels.Eof do begin 143 | ConvertRecordToJSONObject(AResponse, qryMessage_Labels,'MESSAGE_ID',False); 144 | qryMessage_Labels.Next; 145 | end; 146 | 147 | AResponse.Body.JSONWriter.WriteEndArray; 148 | AResponse.Body.JSONWriter.WriteEndObject; 149 | qryMessages.Next; 150 | end; 151 | AResponse.Body.JSONWriter.WriteEndArray; 152 | 153 | end; 154 | 155 | procedure TMailResource1.GetLabels(const AContext: TEndpointContext; 156 | const ARequest: TEndpointRequest; const AResponse: TEndpointResponse); 157 | 158 | procedure loadChlildren(ParentQry:TFDDataSet); 159 | var 160 | Qry : TFDMemTable; 161 | begin 162 | AResponse.Body.JSONWriter.WritePropertyName('children'); 163 | AResponse.Body.JSONWriter.WriteStartArray; 164 | 165 | if qryLabelChildren.Locate('PARENT_ID', ParentQry.FieldByName('ID').AsInteger) then begin 166 | 167 | Qry := TFDMemTable.Create(Self); 168 | try 169 | Qry.CloneCursor(qryLabelChildren,True); 170 | Qry.Filter := 'PARENT_ID = '+ParentQry.FieldByName('ID').AsString; 171 | Qry.Filtered := True; 172 | 173 | 174 | while not Qry.Eof do begin 175 | AResponse.Body.JSONWriter.WriteStartObject; 176 | ConvertRecordToJSONObject(AResponse, Qry,'PARENT_ID'); 177 | loadChlildren(Qry); 178 | AResponse.Body.JSONWriter.WriteEndObject; 179 | Qry.Next; 180 | end; 181 | 182 | finally 183 | Qry.Free; 184 | end; 185 | end; 186 | 187 | AResponse.Body.JSONWriter.WriteEndArray; 188 | end; 189 | 190 | begin 191 | // Get the top level list 192 | qryLABELS.Open('SELECT * FROM LABELS WHERE PARENT_ID IS NULL ORDER BY ID'); 193 | // List of all linked nodes to work with 194 | qryLabelChildren.Open('SELECT * FROM LABELS WHERE PARENT_ID IS NOT NULL ORDER BY PARENT_ID, ID'); 195 | 196 | AResponse.Body.JSONWriter.WriteStartArray; 197 | 198 | qryLABELS.First; 199 | while not qryLABELS.Eof do begin 200 | // Build Message 201 | AResponse.Body.JSONWriter.WriteStartObject; 202 | ConvertRecordToJSONObject(AResponse,qryLabels,'PARENT_ID'); 203 | // Add child labels Labels 204 | loadChlildren(qryLABELS); 205 | 206 | AResponse.Body.JSONWriter.WriteEndObject; 207 | qryLABELS.Next; 208 | end; 209 | AResponse.Body.JSONWriter.WriteEndArray; 210 | end; 211 | 212 | procedure Register; 213 | begin 214 | RegisterResource(TypeInfo(TMailResource1)); 215 | end; 216 | 217 | 218 | initialization 219 | Register; 220 | end. 221 | 222 | 223 | -------------------------------------------------------------------------------- /Delphi/TasksExample/Simple Client/FormSimple.fmx: -------------------------------------------------------------------------------- 1 | object Form1: TForm1 2 | Left = 0 3 | Top = 0 4 | Caption = 'Form1' 5 | ClientHeight = 480 6 | ClientWidth = 764 7 | FormFactor.Width = 320 8 | FormFactor.Height = 480 9 | FormFactor.Devices = [Desktop] 10 | DesignerMasterStyle = 0 11 | object BindNavigator1: TBindNavigator 12 | Align = Bottom 13 | Position.Y = 455.000000000000000000 14 | Size.Width = 764.000000000000000000 15 | Size.Height = 25.000000000000000000 16 | Size.PlatformDefault = False 17 | TabOrder = 7 18 | DataSource = BindSourceDB2 19 | xRadius = 4.000000000000000000 20 | yRadius = 4.000000000000000000 21 | end 22 | object Layout1: TLayout 23 | Align = Top 24 | Size.Width = 764.000000000000000000 25 | Size.Height = 50.000000000000000000 26 | Size.PlatformDefault = False 27 | TabOrder = 8 28 | object Button1: TButton 29 | Position.X = 8.000000000000000000 30 | Position.Y = 8.000000000000000000 31 | TabOrder = 1 32 | Text = 'Fetch' 33 | OnClick = Button1Click 34 | end 35 | object Button2: TButton 36 | Position.X = 96.000000000000000000 37 | Position.Y = 8.000000000000000000 38 | TabOrder = 0 39 | Text = 'Save' 40 | OnClick = Button2Click 41 | end 42 | object Button3: TButton 43 | Position.X = 192.000000000000000000 44 | Position.Y = 8.000000000000000000 45 | Size.Width = 121.000000000000000000 46 | Size.Height = 22.000000000000000000 47 | Size.PlatformDefault = False 48 | TabOrder = 2 49 | Text = 'Change Count' 50 | OnClick = Button3Click 51 | end 52 | end 53 | object TabControl1: TTabControl 54 | Align = Client 55 | Size.Width = 764.000000000000000000 56 | Size.Height = 405.000000000000000000 57 | Size.PlatformDefault = False 58 | TabIndex = 1 59 | TabOrder = 19 60 | TabPosition = PlatformDefault 61 | Sizes = ( 62 | 764s 63 | 379s 64 | 764s 65 | 379s) 66 | object TabItem1: TTabItem 67 | CustomIcon = < 68 | item 69 | end> 70 | IsSelected = False 71 | Size.Width = 69.000000000000000000 72 | Size.Height = 26.000000000000000000 73 | Size.PlatformDefault = False 74 | StyleLookup = '' 75 | TabOrder = 0 76 | Text = 'TabItem1' 77 | ExplicitSize.cx = 69.000000000000000000 78 | ExplicitSize.cy = 26.000000000000000000 79 | object StringGrid1: TStringGrid 80 | Align = Client 81 | CanFocus = True 82 | ClipChildren = True 83 | Size.Width = 764.000000000000000000 84 | Size.Height = 379.000000000000000000 85 | Size.PlatformDefault = False 86 | TabOrder = 0 87 | RowCount = 0 88 | Viewport.Width = 760.000000000000000000 89 | Viewport.Height = 354.000000000000000000 90 | end 91 | end 92 | object TabItem2: TTabItem 93 | CustomIcon = < 94 | item 95 | end> 96 | IsSelected = True 97 | Size.Width = 69.000000000000000000 98 | Size.Height = 26.000000000000000000 99 | Size.PlatformDefault = False 100 | StyleLookup = '' 101 | TabOrder = 0 102 | Text = 'TabItem2' 103 | ExplicitSize.cx = 69.000000000000000000 104 | ExplicitSize.cy = 26.000000000000000000 105 | object Memo1: TMemo 106 | Touch.InteractiveGestures = [Pan, LongTap, DoubleTap] 107 | DataDetectorTypes = [] 108 | Align = Top 109 | Position.Y = 17.000000000000000000 110 | Size.Width = 764.000000000000000000 111 | Size.Height = 72.000000000000000000 112 | Size.PlatformDefault = False 113 | TabOrder = 1 114 | Viewport.Width = 760.000000000000000000 115 | Viewport.Height = 68.000000000000000000 116 | end 117 | object Label1: TLabel 118 | Align = Top 119 | Size.Width = 764.000000000000000000 120 | Size.Height = 17.000000000000000000 121 | Size.PlatformDefault = False 122 | Text = 'Post Response' 123 | TabOrder = 3 124 | end 125 | object Label2: TLabel 126 | Align = Top 127 | Position.Y = 89.000000000000000000 128 | Size.Width = 764.000000000000000000 129 | Size.Height = 17.000000000000000000 130 | Size.PlatformDefault = False 131 | Text = 'Post Update Body' 132 | TabOrder = 2 133 | end 134 | object MemoPostBody: TMemo 135 | Touch.InteractiveGestures = [Pan, LongTap, DoubleTap] 136 | DataDetectorTypes = [] 137 | Align = Top 138 | Position.Y = 106.000000000000000000 139 | Size.Width = 764.000000000000000000 140 | Size.Height = 72.000000000000000000 141 | Size.PlatformDefault = False 142 | TabOrder = 0 143 | Viewport.Width = 760.000000000000000000 144 | Viewport.Height = 68.000000000000000000 145 | end 146 | end 147 | end 148 | object BindingsList1: TBindingsList 149 | Methods = <> 150 | OutputConverters = <> 151 | Left = 28 152 | Top = 357 153 | object LinkGridToDataSourceBindSourceDB2: TLinkGridToDataSource 154 | Category = 'Quick Bindings' 155 | DataSource = BindSourceDB2 156 | GridControl = StringGrid1 157 | Columns = <> 158 | end 159 | end 160 | object RESTClient1: TRESTClient 161 | Accept = 'application/json, text/plain; q=0.9, text/html;q=0.8,' 162 | AcceptCharset = 'utf-8, *;q=0.8' 163 | BaseURL = 'http://localhost:8080' 164 | Params = <> 165 | Left = 136 166 | Top = 88 167 | end 168 | object RESTRequestGet: TRESTRequest 169 | AssignedValues = [rvConnectTimeout, rvReadTimeout] 170 | Client = RESTClient1 171 | Params = <> 172 | Resource = 'data/tasks/' 173 | Response = RESTResponseGet 174 | Left = 136 175 | Top = 136 176 | end 177 | object RESTResponseGet: TRESTResponse 178 | ContentType = 'application/json' 179 | Left = 136 180 | Top = 192 181 | end 182 | object RESTResponseDataSetAdapterGet: TRESTResponseDataSetAdapter 183 | Active = True 184 | Dataset = FDMemTable1 185 | FieldDefs = <> 186 | Response = RESTResponseGet 187 | StringFieldSize = 50 188 | Left = 136 189 | Top = 248 190 | end 191 | object FDMemTable1: TFDMemTable 192 | Active = True 193 | FieldDefs = < 194 | item 195 | Name = 'ID' 196 | DataType = ftWideString 197 | Size = 50 198 | end 199 | item 200 | Name = 'FIRST_NAME' 201 | DataType = ftWideString 202 | Size = 50 203 | end 204 | item 205 | Name = 'LAST_NAME' 206 | DataType = ftWideString 207 | Size = 50 208 | end 209 | item 210 | Name = 'EMAIL' 211 | DataType = ftWideString 212 | Size = 50 213 | end 214 | item 215 | Name = 'DATE' 216 | DataType = ftWideString 217 | Size = 50 218 | end 219 | item 220 | Name = 'SUBJECT' 221 | DataType = ftWideString 222 | Size = 50 223 | end 224 | item 225 | Name = 'UNREAD' 226 | DataType = ftWideString 227 | Size = 50 228 | end 229 | item 230 | Name = 'DRAFT' 231 | DataType = ftWideString 232 | Size = 50 233 | end 234 | item 235 | Name = 'SENT' 236 | DataType = ftWideString 237 | Size = 50 238 | end 239 | item 240 | Name = 'STARRED' 241 | DataType = ftWideString 242 | Size = 50 243 | end 244 | item 245 | Name = 'OUTGOING' 246 | DataType = ftWideString 247 | Size = 50 248 | end 249 | item 250 | Name = 'MESSAGE' 251 | DataType = ftWideString 252 | Size = 50 253 | end> 254 | IndexDefs = <> 255 | FetchOptions.AssignedValues = [evMode] 256 | FetchOptions.Mode = fmAll 257 | ResourceOptions.AssignedValues = [rvSilentMode] 258 | ResourceOptions.SilentMode = True 259 | UpdateOptions.AssignedValues = [uvUpdateChngFields, uvUpdateMode, uvLockMode, uvLockPoint, uvLockWait, uvRefreshMode, uvFetchGeneratorsPoint, uvCheckRequired, uvCheckReadOnly, uvCheckUpdatable] 260 | UpdateOptions.LockWait = True 261 | UpdateOptions.FetchGeneratorsPoint = gpNone 262 | UpdateOptions.CheckRequired = False 263 | StoreDefs = True 264 | Left = 272 265 | Top = 312 266 | end 267 | object BindSourceDB2: TBindSourceDB 268 | DataSet = FDMemTable1 269 | ScopeMappings = <> 270 | Left = 272 271 | Top = 368 272 | end 273 | end 274 | -------------------------------------------------------------------------------- /Delphi/REST.DataUpdater.pas: -------------------------------------------------------------------------------- 1 | unit REST.DataUpdater; 2 | 3 | interface 4 | 5 | uses System.Classes, REST.Client, REST.Response.Adapter, 6 | Data.DB, FireDAC.Comp.DataSet, FireDAC.Comp.Client, REST.Types; 7 | 8 | type 9 | TRestDataSetUpdater = class(TComponent) 10 | type 11 | TRDSUTransport = class(TComponent) 12 | private 13 | FDataSet : TFDDataSet; 14 | FRequest : TRESTRequest; 15 | FResponse : TRESTResponse; 16 | FDataSetAdapter: TRESTRequestDataSetAdapter; 17 | function RDSU : TRestDataSetUpdater; 18 | public 19 | // Need to create constructor, set these options then put into the thread model. 20 | constructor Create(AOwner : TRestDataSetUpdater; UpdateKind : TRESTRequestMethod); reintroduce; 21 | function Execute(AutoUpdateDataSetSavePoint : Boolean = True) : Boolean; 22 | end; 23 | 24 | private 25 | FRESTClient : TRESTClient; 26 | FDataSet : TFDDataSet; 27 | FKeyFieldName: string; 28 | FslError : TStringList; 29 | FResourcePut: string; 30 | FResourceDelete: string; 31 | FResourcePost: string; 32 | 33 | procedure SetDataSet(const Value: TFDDataSet); 34 | procedure SetClient(const Value: TRESTClient); 35 | procedure SetKeyFieldName(const Value: string); 36 | procedure LogError(aErrorMessage: string); 37 | procedure SetResourceDelete(const Value: string); 38 | procedure SetResourcePost(const Value: string); 39 | procedure SetResourcePut(const Value: string); 40 | public 41 | constructor Create(AOwner : TComponent); reintroduce; overload; 42 | constructor Create(AOwner : TComponent; ARESTClient : TRESTClient; AResource, AKeyFieldName : string; ADataSet : TFDDataSet); reintroduce; overload; 43 | destructor Destroy; override; 44 | 45 | function ApplyRemoteUpdates(AutoUpdateDataSetSavePoint : Boolean = True) : Boolean; 46 | 47 | property DataSet : TFDDataSet read FDataSet write SetDataSet; 48 | 49 | // Insert 50 | property ResourcePost : string read FResourcePost write SetResourcePost; 51 | // Update 52 | property ResourcePut : string read FResourcePut write SetResourcePut; 53 | // Delete 54 | property ResourceDelete : string read FResourceDelete write SetResourceDelete; 55 | 56 | property Client : TRESTClient read FRESTClient write SetClient; 57 | 58 | // Name the paramater for the ID to be the same as the field in the dataset, this way it will get set. 59 | property KeyFieldName : string read FKeyFieldName write SetKeyFieldName; 60 | 61 | property ErrorLog : TStringList read FslError; 62 | end; 63 | 64 | implementation 65 | 66 | uses Data.DBJson, System.SysUtils; 67 | 68 | { TRestDataSetUpdater } 69 | 70 | function TRestDataSetUpdater.ApplyRemoteUpdates(AutoUpdateDataSetSavePoint : Boolean = True): Boolean; 71 | var 72 | ResultI, ResultU, ResultD : Boolean; 73 | begin 74 | // Check Client is set. 75 | Assert(Assigned(DataSet),'DataSet Missing'); 76 | Assert(Assigned(Client),'RESTClient Connection missing'); 77 | Assert(KeyFieldName > '','Key FieldName Missing'); 78 | 79 | if not DataSet.UpdatesPending then 80 | Exit(True); 81 | 82 | FslError.Clear; 83 | 84 | // 85 | ResultI := False; 86 | ResultU := False; 87 | ResultD := False; 88 | 89 | var InsertTransport := TRDSUTransport.Create(Self,TRESTRequestMethod.rmPOST); 90 | try 91 | try 92 | ResultI := InsertTransport.Execute(AutoUpdateDataSetSavePoint); 93 | except 94 | on e:Exception do 95 | LogError('rmPOST Error: '+e.Message); 96 | end; 97 | finally 98 | InsertTransport.Free; 99 | end; 100 | 101 | // Updates 102 | var UpdateTransport := TRDSUTransport.Create(Self,TRESTRequestMethod.rmPUT); 103 | try 104 | try 105 | ResultU := UpdateTransport.Execute(AutoUpdateDataSetSavePoint); 106 | except 107 | on e:Exception do 108 | LogError('rmPUT Error: '+e.Message); 109 | end; 110 | finally 111 | UpdateTransport.Free; 112 | end; 113 | 114 | // Delete 115 | var DeleteTransport := TRDSUTransport.Create(Self,TRESTRequestMethod.rmDELETE); 116 | try 117 | try 118 | ResultD := DeleteTransport.Execute(AutoUpdateDataSetSavePoint); 119 | except 120 | on e:Exception do 121 | LogError('rmDELETE Error: '+e.Message); 122 | end; 123 | finally 124 | DeleteTransport.Free; 125 | end; 126 | 127 | Result := ResultI and ResultU and ResultD; 128 | 129 | if AutoUpdateDataSetSavePoint and Result then 130 | FDataSet.CommitUpdates; // Clear the cache. 131 | end; 132 | 133 | constructor TRestDataSetUpdater.Create(AOwner: TComponent); 134 | begin 135 | inherited Create(AOwner); 136 | FslError := TStringList.Create; 137 | FRESTClient := nil; 138 | end; 139 | 140 | constructor TRestDataSetUpdater.Create(AOwner: TComponent; 141 | ARESTClient: TRESTClient; AResource, AKeyFieldName: string; ADataSet : TFDDataSet); 142 | begin 143 | Create(AOwner); 144 | Client := ARESTClient; 145 | 146 | if not AResource.EndsWith('/') then 147 | AResource := AResource+'/'; 148 | 149 | // Insert (Put} doesn't take a param... 150 | ResourcePost := AResource; 151 | // Update and delete, use the Param. These can be overriden after creation. 152 | ResourcePut := AResource+'{'+AKeyFieldName+'}'; 153 | ResourceDelete := AResource+'{'+AKeyFieldName+'}'; 154 | 155 | DataSet := ADataSet; 156 | KeyFieldName := AKeyFieldName; 157 | end; 158 | 159 | destructor TRestDataSetUpdater.Destroy; 160 | begin 161 | FslError.Free; 162 | inherited; 163 | end; 164 | 165 | procedure TRestDataSetUpdater.LogError(aErrorMessage: string); 166 | begin 167 | FslError.Add(aErrorMessage); 168 | end; 169 | 170 | procedure TRestDataSetUpdater.SetClient(const Value: TRESTClient); 171 | begin 172 | FRESTClient := Value; 173 | end; 174 | 175 | procedure TRestDataSetUpdater.SetDataSet(const Value: TFDDataSet); 176 | begin 177 | FDataset := Value; 178 | end; 179 | 180 | procedure TRestDataSetUpdater.SetKeyFieldName(const Value: string); 181 | begin 182 | FKeyFieldName := Value; 183 | end; 184 | 185 | procedure TRestDataSetUpdater.SetResourceDelete(const Value: string); 186 | begin 187 | FResourceDelete := Value; 188 | end; 189 | 190 | procedure TRestDataSetUpdater.SetResourcePost(const Value: string); 191 | begin 192 | FResourcePost := Value; 193 | end; 194 | 195 | procedure TRestDataSetUpdater.SetResourcePut(const Value: string); 196 | begin 197 | FResourcePut := Value; 198 | end; 199 | 200 | { TRestDataSetUpdater.TRDSUTransport } 201 | 202 | constructor TRestDataSetUpdater.TRDSUTransport.Create(AOwner : TRestDataSetUpdater; UpdateKind : TRESTRequestMethod); 203 | begin 204 | Assert(AOwner <> nil,'Owner not Assigned'); 205 | 206 | inherited Create(AOwner); 207 | 208 | FDataSet := TFDMemTable.Create(Self); 209 | FDataSet.Data := AOwner.DataSet.Delta; 210 | 211 | FRequest := TRESTRequest.Create(Self); 212 | FRequest.Client := AOwner.Client; 213 | 214 | FResponse := TRESTResponse.Create(Self); 215 | FRequest.Response := FResponse; 216 | 217 | case UpdateKind of 218 | rmPOST : FRequest.Resource := AOwner.ResourcePost; 219 | rmPUT : FRequest.Resource := AOwner.ResourcePut; 220 | rmDELETE : FRequest.Resource := AOwner.ResourceDelete; 221 | //rmGET : ; 222 | //rmPATCH: ; 223 | else 224 | FRequest.Resource := AOwner.ResourcePut; 225 | end; 226 | 227 | FRequest.Method := UpdateKind; 228 | 229 | FDataSetAdapter := TRESTRequestDataSetAdapter.Create(Self); 230 | FDataSetAdapter.Area := TJSONDataSetArea.Current; 231 | FDataSetAdapter.Request := FRequest; 232 | FDataSetAdapter.Dataset := FDataSet; 233 | 234 | // Ignore Nulls on Insert. 235 | if UpdateKind = rmPost then 236 | FDataSetAdapter.IncludeNulls := False; 237 | 238 | FDataSetAdapter.AutoUpdate := True; 239 | end; 240 | 241 | function TRestDataSetUpdater.TRDSUTransport.Execute(AutoUpdateDataSetSavePoint : Boolean = True) : Boolean; 242 | begin 243 | 244 | case FRequest.Method of 245 | // Insert 246 | rmPOST : FDataSet.FilterChanges := [rtInserted]; 247 | // Update 248 | rmPUT, 249 | rmPATCH : FDataSet.FilterChanges := [rtModified]; 250 | // Delete 251 | rmDELETE : FDataSet.FilterChanges := [rtDeleted]; 252 | else 253 | //Should never be used - e.g. rmGET - Force a failure if it is. 254 | Exit(False); 255 | end; 256 | 257 | // If nothing to update, all is good, return true; 258 | if FDataSet.RecordCount = 0 then 259 | Exit(True); 260 | 261 | // Currently, it has to be done record by record. 262 | // Future update, check each field to build the data to push back when its a Patch. 263 | try 264 | Result := True; 265 | 266 | var KeyStr := RDSU.KeyFieldName; 267 | var FParam := FRequest.Params.ParameterByName(KeyStr); 268 | 269 | while not FDataSet.Eof do begin 270 | // AutoUpdate will update the REST Request body data 271 | // Update URL Param for current ITEM 272 | if Assigned(FParam) then 273 | FParam.Value := FDataSet.FieldByName(KeyStr).AsString; 274 | 275 | try 276 | FRequest.Execute; 277 | finally 278 | Result := (FResponse.StatusCode >= 200) and (FResponse.StatusCode <= 205); 279 | end; 280 | 281 | FDataSet.Next; 282 | end; 283 | 284 | 285 | // This isn't applying to the master dataset.... Is there away to do this record by record? 286 | if AutoUpdateDataSetSavePoint and Result then 287 | FDataSet.CommitUpdates; // Clear the cache. 288 | 289 | 290 | except 291 | on E:Exception do begin 292 | // Log the error 293 | RDSU.LogError('Execute error: '+e.Message); 294 | RDSU.LogError('DataPacket: '+FRequest.GetFullRequestBody); 295 | Result := False; 296 | end; 297 | end; 298 | 299 | end; 300 | 301 | function TRestDataSetUpdater.TRDSUTransport.RDSU: TRestDataSetUpdater; 302 | begin 303 | Result := TRestDataSetUpdater(Owner); 304 | end; 305 | 306 | end. 307 | -------------------------------------------------------------------------------- /Delphi/ChangeViews/ModuleCode/ChangeView.Cache.pas: -------------------------------------------------------------------------------- 1 | unit ChangeView.Cache; 2 | 3 | interface 4 | 5 | uses 6 | System.SysUtils, System.Classes, System.Generics.Collections, 7 | ChangeView.DataConnection, System.SyncObjs, System.Threading; 8 | 9 | type 10 | 11 | // A list of Sessions for a ChangeView based on the DeviceID as the key 12 | TChangeViewSessions = class(TComponent) 13 | type 14 | TChangeViewSessionItems = TDictionary; 15 | strict private 16 | FChangeViewName: string; 17 | FCriticalSection : TCriticalSection; 18 | FSessions : TChangeViewSessionItems; 19 | procedure EnterCriticalSection; 20 | procedure LeaveCriticalSection; 21 | function GetCount: Integer; 22 | public 23 | constructor Create(AOwner : TComponent; AChangeViewName : String); reintroduce; 24 | destructor Destroy; override; 25 | 26 | function FindSession(ADeviceID : string):TChangeViewConnection; 27 | function NewSession(ADeviceID : string):TChangeViewConnection; 28 | procedure CloseSession(ADeviceID : string); 29 | procedure CloseInactiveSession(InactiveTimeInSeconds : Integer); 30 | procedure GetStats(AOutput: TStrings); 31 | 32 | property Count : Integer read GetCount; 33 | property ChangeViewName : string read FChangeViewName; 34 | end; 35 | 36 | 37 | // ChangeView Name and a List of Sessions for that ChangeView 38 | TChangeViewSessionList = TDictionary; 39 | 40 | TChangeViewSessionManager = class(TComponent) 41 | strict private 42 | FChangeViewSessionList : TChangeViewSessionList; 43 | FCriticalSectionManager : TCriticalSection; 44 | 45 | procedure EnterCriticalSection; 46 | procedure LeaveCriticalSection; 47 | public 48 | constructor Create(AOwner : TComponent); Reintroduce; 49 | destructor Destroy; override; 50 | 51 | function FindDeviceSession(const ChangeViewName : string; const DeviceID : string; AutoCreate : Boolean = False): TChangeViewConnection; 52 | function FindChangeViewSessions(const ChangeViewName : string; AutoCreate : Boolean = False): TChangeViewSessions; 53 | 54 | procedure Sweep(SecondsInactive : Integer); 55 | 56 | procedure GetStats(AOutput: TStrings; const QuickStats : Boolean = False); 57 | end; 58 | 59 | var 60 | FChangeViewSessionManager : TChangeViewSessionManager; 61 | 62 | function ChangeViewSessions : TChangeViewSessionManager; 63 | 64 | 65 | implementation 66 | 67 | uses System.DateUtils; 68 | 69 | 70 | function ChangeViewSessions : TChangeViewSessionManager; 71 | begin 72 | Result := FChangeViewSessionManager; 73 | end; 74 | 75 | 76 | constructor TChangeViewSessionManager.Create(AOwner: TComponent); 77 | begin 78 | inherited Create(AOwner); 79 | FCriticalSectionManager := TCriticalSection.Create; 80 | FChangeViewSessionList := TChangeViewSessionList.Create; 81 | end; 82 | 83 | destructor TChangeViewSessionManager.Destroy; 84 | begin 85 | FChangeViewSessionList.Free; 86 | FCriticalSectionManager.Free; 87 | inherited Destroy; 88 | end; 89 | 90 | procedure TChangeViewSessionManager.EnterCriticalSection; 91 | begin 92 | FCriticalSectionManager.Enter; 93 | end; 94 | 95 | function TChangeViewSessionManager.FindChangeViewSessions( 96 | const ChangeViewName: string; AutoCreate : Boolean = False): TChangeViewSessions; 97 | var 98 | FChangeViewSessions : TChangeViewSessions; 99 | begin 100 | FChangeViewSessionList.TryGetValue(ChangeViewName, FChangeViewSessions); 101 | 102 | if (FChangeViewSessions = nil) and AutoCreate then 103 | begin 104 | FCriticalSectionManager.Enter; 105 | try 106 | FChangeViewSessions := TChangeViewSessions.Create(Self, ChangeViewName); 107 | if not FChangeViewSessionList.TryAdd(ChangeViewName,FChangeViewSessions) then 108 | begin 109 | FChangeViewSessions.Free; 110 | Exit(nil); 111 | end; 112 | finally 113 | FCriticalSectionManager.Leave; 114 | end; 115 | end; 116 | 117 | Result := FChangeViewSessions; 118 | 119 | end; 120 | 121 | function TChangeViewSessionManager.FindDeviceSession(const ChangeViewName : string; const DeviceID : string; AutoCreate : Boolean = False): TChangeViewConnection; 122 | var 123 | FChangeViewSessions : TChangeViewSessions; 124 | 125 | begin 126 | FChangeViewSessions := FindChangeViewSessions(ChangeViewName, AutoCreate); 127 | 128 | if FChangeViewSessions <> nil then begin 129 | 130 | var FCurrSession := FChangeViewSessions.FindSession(DeviceID); 131 | 132 | if (FCurrSession = nil) and AutoCreate then 133 | begin 134 | FCurrSession := FChangeViewSessions.NewSession(DeviceID); 135 | end; 136 | 137 | Result := FCurrSession; 138 | Result.MarkAsActive; 139 | 140 | end else 141 | Result := nil; 142 | 143 | end; 144 | 145 | procedure TChangeViewSessionManager.GetStats(AOutput: TStrings; const QuickStats : Boolean); 146 | 147 | procedure Log(s : string); 148 | begin 149 | AOutput.Add(s); 150 | end; 151 | 152 | begin 153 | AOutput.BeginUpdate; 154 | try 155 | AOutput.Clear; 156 | 157 | Log( Format('Total ChangeViews : %d',[FChangeViewSessionList.Count] )); 158 | Log( '' ); 159 | for var CVS in FChangeViewSessionList do begin 160 | 161 | if QuickStats then 162 | Log( Format('-- ChangeView : %s [%d Sessions] --',[CVS.Value.ChangeViewName, CVS.Value.Count] )) 163 | else 164 | CVS.Value.GetStats(AOutput); 165 | 166 | Log( '' ); 167 | 168 | end; 169 | 170 | 171 | finally 172 | AOutput.EndUpdate; 173 | end; 174 | end; 175 | 176 | 177 | procedure TChangeViewSessionManager.LeaveCriticalSection; 178 | begin 179 | FCriticalSectionManager.Leave; 180 | end; 181 | 182 | procedure TChangeViewSessionManager.Sweep(SecondsInactive: Integer); 183 | begin 184 | var FCloseList := TStringList.Create; 185 | try 186 | EnterCriticalSection; 187 | try 188 | for var FChangeViewList in FChangeViewSessionList do 189 | begin 190 | FChangeViewList.Value.CloseInactiveSession(SecondsInactive); 191 | if FChangeViewList.Value.Count = 0 then 192 | begin 193 | FCloseList.Add(FChangeViewList.Key); 194 | end; 195 | end; 196 | 197 | for var S in FCloseList do 198 | FChangeViewSessionList.Remove(S); 199 | 200 | finally 201 | LeaveCriticalSection; 202 | end; 203 | 204 | finally 205 | FCloseList.Free; 206 | end; 207 | 208 | end; 209 | 210 | { TChangeViewSessions } 211 | 212 | procedure TChangeViewSessions.CloseInactiveSession( 213 | InactiveTimeInSeconds: Integer); 214 | begin 215 | var CloseList := TStringList.Create; 216 | try 217 | EnterCriticalSection; 218 | try 219 | for var FCurrSession in FSessions do 220 | begin 221 | if FCurrSession.Value.LatestActivity.IncSecond(InactiveTimeInSeconds) < Now then 222 | begin 223 | CloseList.Add(FCurrSession.Key); 224 | end; 225 | end; 226 | finally 227 | LeaveCriticalSection; 228 | end; 229 | 230 | for var FDeviceID in CloseList do 231 | CloseSession(FDeviceID); 232 | 233 | finally 234 | CloseList.Free; 235 | end; 236 | end; 237 | 238 | procedure TChangeViewSessions.CloseSession(ADeviceID: string); 239 | begin 240 | EnterCriticalSection; 241 | try 242 | var FCurrSession := FindSession(ADeviceID); 243 | if FCurrSession <> nil then 244 | begin 245 | FSessions.Remove(ADeviceID); 246 | FCurrSession.Free; 247 | end; 248 | finally 249 | LeaveCriticalSection; 250 | end; 251 | end; 252 | 253 | constructor TChangeViewSessions.Create(AOwner: TComponent; 254 | AChangeViewName: String); 255 | begin 256 | inherited Create(AOwner); 257 | FCriticalSection := TCriticalSection.Create; 258 | FChangeViewName := AChangeViewName; 259 | FSessions := TChangeViewSessionItems.Create; 260 | end; 261 | 262 | destructor TChangeViewSessions.Destroy; 263 | begin 264 | FSessions.Free; 265 | FCriticalSection.Free; 266 | inherited; 267 | end; 268 | 269 | procedure TChangeViewSessions.EnterCriticalSection; 270 | begin 271 | FCriticalSection.Enter; 272 | end; 273 | 274 | function TChangeViewSessions.FindSession( 275 | ADeviceID: string): TChangeViewConnection; 276 | var 277 | FFoundSession : TChangeViewConnection; 278 | begin 279 | FSessions.TryGetValue(ADeviceID, FFoundSession); 280 | Result := FFoundSession; 281 | end; 282 | 283 | function TChangeViewSessions.GetCount: Integer; 284 | begin 285 | Result := FSessions.Count; 286 | end; 287 | 288 | procedure TChangeViewSessions.GetStats(AOutput: TStrings); 289 | 290 | procedure Log(s : string); 291 | begin 292 | AOutput.Add(s); 293 | end; 294 | 295 | begin 296 | AOutput.BeginUpdate; 297 | try 298 | Log( Format('-- ChangeView : %s [%d Sessions] --',[ChangeViewName, FSessions.Count] )); 299 | for var CurrSession in FSessions do begin 300 | Log( Format('Device : %s [Active %s]',[CurrSession.Value.DeviceID, DateTimeToStr(CurrSession.Value.LatestActivity)]) ); 301 | Log(''); 302 | end; 303 | finally 304 | AOutput.EndUpdate; 305 | end; 306 | end; 307 | 308 | procedure TChangeViewSessions.LeaveCriticalSection; 309 | begin 310 | FCriticalSection.Leave; 311 | end; 312 | 313 | function TChangeViewSessions.NewSession( 314 | ADeviceID: string): TChangeViewConnection; 315 | begin 316 | if FindSession(ADeviceID) <> nil then 317 | CloseSession(ADeviceID); 318 | 319 | var FNewSession := TChangeViewConnection.Create(Self,aDeviceID,ChangeViewName); 320 | 321 | EnterCriticalSection; 322 | try 323 | if not FSessions.TryAdd(ADeviceID, FNewSession) then 324 | FNewSession.Free; 325 | finally 326 | LeaveCriticalSection; 327 | end; 328 | 329 | // Get from list incase of issue adding 330 | Result := FindSession(ADeviceID); 331 | 332 | end; 333 | 334 | initialization 335 | FChangeViewSessionManager := TChangeViewSessionManager.Create(nil); 336 | 337 | finalization 338 | try 339 | FreeAndNil(FChangeViewSessionManager); 340 | except 341 | end; 342 | 343 | 344 | 345 | end. 346 | -------------------------------------------------------------------------------- /Delphi/TasksExample/Simple Server/SimpleRADServerTasks.dproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | {5736511B-90F4-46CA-A073-E543F230B706} 4 | SimpleRADServerTasks.dpk 5 | 19.4 6 | None 7 | True 8 | Release 9 | Win32 10 | 131 11 | Package 12 | 13 | 14 | true 15 | 16 | 17 | true 18 | Base 19 | true 20 | 21 | 22 | true 23 | Base 24 | true 25 | 26 | 27 | true 28 | Base 29 | true 30 | 31 | 32 | true 33 | Base 34 | true 35 | 36 | 37 | true 38 | Base 39 | true 40 | 41 | 42 | true 43 | Base 44 | true 45 | 46 | 47 | true 48 | Base 49 | true 50 | 51 | 52 | true 53 | Base 54 | true 55 | 56 | 57 | true 58 | Base 59 | true 60 | 61 | 62 | true 63 | Cfg_1 64 | true 65 | true 66 | 67 | 68 | true 69 | Base 70 | true 71 | 72 | 73 | .\$(Platform)\$(Config) 74 | .\$(Platform)\$(Config) 75 | false 76 | false 77 | false 78 | false 79 | false 80 | true 81 | true 82 | System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace) 83 | True 84 | -l"$(TargetName)" 85 | $(BDS)\bin\delphi_PROJECTICON.ico 86 | $(BDS)\bin\delphi_PROJECTICNS.icns 87 | SimpleRADServerTasks 88 | 89 | 90 | package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey= 91 | Debug 92 | annotation-1.2.0.dex.jar;asynclayoutinflater-1.0.0.dex.jar;billing-4.0.0.dex.jar;browser-1.0.0.dex.jar;cloud-messaging.dex.jar;collection-1.0.0.dex.jar;coordinatorlayout-1.0.0.dex.jar;core-1.5.0-rc02.dex.jar;core-common-2.0.1.dex.jar;core-runtime-2.0.1.dex.jar;cursoradapter-1.0.0.dex.jar;customview-1.0.0.dex.jar;documentfile-1.0.0.dex.jar;drawerlayout-1.0.0.dex.jar;firebase-annotations-16.0.0.dex.jar;firebase-common-20.0.0.dex.jar;firebase-components-17.0.0.dex.jar;firebase-datatransport-18.0.0.dex.jar;firebase-encoders-17.0.0.dex.jar;firebase-encoders-json-18.0.0.dex.jar;firebase-iid-interop-17.1.0.dex.jar;firebase-installations-17.0.0.dex.jar;firebase-installations-interop-17.0.0.dex.jar;firebase-measurement-connector-19.0.0.dex.jar;firebase-messaging-22.0.0.dex.jar;fmx.dex.jar;fragment-1.0.0.dex.jar;google-play-licensing.dex.jar;interpolator-1.0.0.dex.jar;javax.inject-1.dex.jar;legacy-support-core-ui-1.0.0.dex.jar;legacy-support-core-utils-1.0.0.dex.jar;lifecycle-common-2.0.0.dex.jar;lifecycle-livedata-2.0.0.dex.jar;lifecycle-livedata-core-2.0.0.dex.jar;lifecycle-runtime-2.0.0.dex.jar;lifecycle-service-2.0.0.dex.jar;lifecycle-viewmodel-2.0.0.dex.jar;listenablefuture-1.0.dex.jar;loader-1.0.0.dex.jar;localbroadcastmanager-1.0.0.dex.jar;play-services-ads-20.1.0.dex.jar;play-services-ads-base-20.1.0.dex.jar;play-services-ads-identifier-17.0.0.dex.jar;play-services-ads-lite-20.1.0.dex.jar;play-services-base-17.5.0.dex.jar;play-services-basement-17.6.0.dex.jar;play-services-cloud-messaging-16.0.0.dex.jar;play-services-drive-17.0.0.dex.jar;play-services-games-21.0.0.dex.jar;play-services-location-18.0.0.dex.jar;play-services-maps-17.0.1.dex.jar;play-services-measurement-base-18.0.0.dex.jar;play-services-measurement-sdk-api-18.0.0.dex.jar;play-services-places-placereport-17.0.0.dex.jar;play-services-stats-17.0.0.dex.jar;play-services-tasks-17.2.0.dex.jar;print-1.0.0.dex.jar;room-common-2.1.0.dex.jar;room-runtime-2.1.0.dex.jar;slidingpanelayout-1.0.0.dex.jar;sqlite-2.0.1.dex.jar;sqlite-framework-2.0.1.dex.jar;swiperefreshlayout-1.0.0.dex.jar;transport-api-3.0.0.dex.jar;transport-backend-cct-3.0.0.dex.jar;transport-runtime-3.0.0.dex.jar;user-messaging-platform-1.0.0.dex.jar;versionedparcelable-1.1.1.dex.jar;viewpager-1.0.0.dex.jar;work-runtime-2.1.0.dex.jar 93 | 94 | 95 | package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey= 96 | Debug 97 | annotation-1.2.0.dex.jar;asynclayoutinflater-1.0.0.dex.jar;billing-4.0.0.dex.jar;browser-1.0.0.dex.jar;cloud-messaging.dex.jar;collection-1.0.0.dex.jar;coordinatorlayout-1.0.0.dex.jar;core-1.5.0-rc02.dex.jar;core-common-2.0.1.dex.jar;core-runtime-2.0.1.dex.jar;cursoradapter-1.0.0.dex.jar;customview-1.0.0.dex.jar;documentfile-1.0.0.dex.jar;drawerlayout-1.0.0.dex.jar;firebase-annotations-16.0.0.dex.jar;firebase-common-20.0.0.dex.jar;firebase-components-17.0.0.dex.jar;firebase-datatransport-18.0.0.dex.jar;firebase-encoders-17.0.0.dex.jar;firebase-encoders-json-18.0.0.dex.jar;firebase-iid-interop-17.1.0.dex.jar;firebase-installations-17.0.0.dex.jar;firebase-installations-interop-17.0.0.dex.jar;firebase-measurement-connector-19.0.0.dex.jar;firebase-messaging-22.0.0.dex.jar;fmx.dex.jar;fragment-1.0.0.dex.jar;google-play-licensing.dex.jar;interpolator-1.0.0.dex.jar;javax.inject-1.dex.jar;legacy-support-core-ui-1.0.0.dex.jar;legacy-support-core-utils-1.0.0.dex.jar;lifecycle-common-2.0.0.dex.jar;lifecycle-livedata-2.0.0.dex.jar;lifecycle-livedata-core-2.0.0.dex.jar;lifecycle-runtime-2.0.0.dex.jar;lifecycle-service-2.0.0.dex.jar;lifecycle-viewmodel-2.0.0.dex.jar;listenablefuture-1.0.dex.jar;loader-1.0.0.dex.jar;localbroadcastmanager-1.0.0.dex.jar;play-services-ads-20.1.0.dex.jar;play-services-ads-base-20.1.0.dex.jar;play-services-ads-identifier-17.0.0.dex.jar;play-services-ads-lite-20.1.0.dex.jar;play-services-base-17.5.0.dex.jar;play-services-basement-17.6.0.dex.jar;play-services-cloud-messaging-16.0.0.dex.jar;play-services-drive-17.0.0.dex.jar;play-services-games-21.0.0.dex.jar;play-services-location-18.0.0.dex.jar;play-services-maps-17.0.1.dex.jar;play-services-measurement-base-18.0.0.dex.jar;play-services-measurement-sdk-api-18.0.0.dex.jar;play-services-places-placereport-17.0.0.dex.jar;play-services-stats-17.0.0.dex.jar;play-services-tasks-17.2.0.dex.jar;print-1.0.0.dex.jar;room-common-2.1.0.dex.jar;room-runtime-2.1.0.dex.jar;slidingpanelayout-1.0.0.dex.jar;sqlite-2.0.1.dex.jar;sqlite-framework-2.0.1.dex.jar;swiperefreshlayout-1.0.0.dex.jar;transport-api-3.0.0.dex.jar;transport-backend-cct-3.0.0.dex.jar;transport-runtime-3.0.0.dex.jar;user-messaging-platform-1.0.0.dex.jar;versionedparcelable-1.1.1.dex.jar;viewpager-1.0.0.dex.jar;work-runtime-2.1.0.dex.jar 98 | 99 | 100 | CFBundleName=$(MSBuildProjectName);CFBundleDevelopmentRegion=en;CFBundleDisplayName=$(MSBuildProjectName);CFBundleIdentifier=$(MSBuildProjectName);CFBundleInfoDictionaryVersion=7.1;CFBundleVersion=1.0.0;CFBundleShortVersionString=1.0.0;CFBundlePackageType=APPL;CFBundleSignature=????;LSRequiresIPhoneOS=true;CFBundleAllowMixedLocalizations=YES;CFBundleExecutable=$(MSBuildProjectName);UIDeviceFamily=iPhone & iPad;NSLocationAlwaysUsageDescription=The reason for accessing the location information of the user;NSLocationWhenInUseUsageDescription=The reason for accessing the location information of the user;NSLocationAlwaysAndWhenInUseUsageDescription=The reason for accessing the location information of the user;UIBackgroundModes=;NSContactsUsageDescription=The reason for accessing the contacts;NSPhotoLibraryUsageDescription=The reason for accessing the photo library;NSPhotoLibraryAddUsageDescription=The reason for adding to the photo library;NSCameraUsageDescription=The reason for accessing the camera;NSFaceIDUsageDescription=The reason for accessing the face id;NSMicrophoneUsageDescription=The reason for accessing the microphone;NSSiriUsageDescription=The reason for accessing Siri;ITSAppUsesNonExemptEncryption=false;NSBluetoothAlwaysUsageDescription=The reason for accessing bluetooth;NSBluetoothPeripheralUsageDescription=The reason for accessing bluetooth peripherals;NSCalendarsUsageDescription=The reason for accessing the calendar data;NSRemindersUsageDescription=The reason for accessing the reminders;NSMotionUsageDescription=The reason for accessing the accelerometer;NSSpeechRecognitionUsageDescription=The reason for requesting to send user data to Apple's speech recognition servers 101 | iPhoneAndiPad 102 | true 103 | Debug 104 | $(MSBuildProjectName) 105 | 106 | 107 | /usr/lib/ems/EMSDevServerCommand 108 | 109 | 110 | CFBundleName=$(MSBuildProjectName);CFBundleDisplayName=$(MSBuildProjectName);CFBundleIdentifier=$(MSBuildProjectName);CFBundleVersion=1.0.0;CFBundleShortVersionString=1.0.0;CFBundlePackageType=APPL;CFBundleSignature=????;CFBundleAllowMixedLocalizations=YES;CFBundleExecutable=$(MSBuildProjectName);NSHighResolutionCapable=true;LSApplicationCategoryType=public.app-category.utilities;NSLocationUsageDescription=The reason for accessing the location information of the user;NSContactsUsageDescription=The reason for accessing the contacts;NSCalendarsUsageDescription=The reason for accessing the calendar data;NSRemindersUsageDescription=The reason for accessing the reminders;NSCameraUsageDescription=The reason for accessing the camera;NSMicrophoneUsageDescription=The reason for accessing the microphone;NSMotionUsageDescription=The reason for accessing the accelerometer;NSDesktopFolderUsageDescription=The reason for accessing the Desktop folder;NSDocumentsFolderUsageDescription=The reason for accessing the Documents folder;NSDownloadsFolderUsageDescription=The reason for accessing the Downloads folder;NSNetworkVolumesUsageDescription=The reason for accessing files on a network volume;NSRemovableVolumesUsageDescription=The reason for accessing files on a removable volume;NSSpeechRecognitionUsageDescription=The reason for requesting to send user data to Apple's speech recognition servers 111 | Debug 112 | 113 | 114 | CFBundleName=$(MSBuildProjectName);CFBundleDisplayName=$(MSBuildProjectName);CFBundleIdentifier=$(MSBuildProjectName);CFBundleVersion=1.0.0;CFBundleShortVersionString=1.0.0;CFBundlePackageType=APPL;CFBundleSignature=????;CFBundleAllowMixedLocalizations=YES;CFBundleExecutable=$(MSBuildProjectName);NSHighResolutionCapable=true;LSApplicationCategoryType=public.app-category.utilities;NSLocationUsageDescription=The reason for accessing the location information of the user;NSContactsUsageDescription=The reason for accessing the contacts;NSCalendarsUsageDescription=The reason for accessing the calendar data;NSRemindersUsageDescription=The reason for accessing the reminders;NSCameraUsageDescription=The reason for accessing the camera;NSMicrophoneUsageDescription=The reason for accessing the microphone;NSMotionUsageDescription=The reason for accessing the accelerometer;NSDesktopFolderUsageDescription=The reason for accessing the Desktop folder;NSDocumentsFolderUsageDescription=The reason for accessing the Documents folder;NSDownloadsFolderUsageDescription=The reason for accessing the Downloads folder;NSNetworkVolumesUsageDescription=The reason for accessing files on a network volume;NSRemovableVolumesUsageDescription=The reason for accessing files on a removable volume;NSSpeechRecognitionUsageDescription=The reason for requesting to send user data to Apple's speech recognition servers 115 | Debug 116 | 117 | 118 | Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) 119 | Debug 120 | true 121 | CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= 122 | 1033 123 | $(BDS)\bin\EMSDevServer.exe 124 | 125 | 126 | Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace) 127 | Debug 128 | true 129 | CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= 130 | 1033 131 | $(BDS)\bin64\EMSDevServer.exe 132 | 133 | 134 | DEBUG;$(DCC_Define) 135 | true 136 | false 137 | true 138 | true 139 | true 140 | true 141 | true 142 | 143 | 144 | false 145 | 146 | 147 | false 148 | RELEASE;$(DCC_Define) 149 | 0 150 | 0 151 | 152 | 153 | 154 | MainSource 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 |
DataResource1
166 | dfm 167 | TDataModule 168 |
169 | 170 | Base 171 | 172 | 173 | Cfg_1 174 | Base 175 | 176 | 177 | Cfg_2 178 | Base 179 | 180 |
181 | 182 | Delphi.Personality.12 183 | Package 184 | 185 | 186 | 187 | SimpleRADServerTasks.dpk 188 | 189 | 190 | 191 | 192 | 193 | true 194 | 195 | 196 | 197 | 198 | true 199 | 200 | 201 | 202 | 203 | true 204 | 205 | 206 | 207 | 208 | SimpleRADServerTasks.bpl 209 | true 210 | 211 | 212 | 213 | 214 | 1 215 | 216 | 217 | 0 218 | 219 | 220 | 221 | 222 | classes 223 | 64 224 | 225 | 226 | classes 227 | 64 228 | 229 | 230 | 231 | 232 | res\xml 233 | 1 234 | 235 | 236 | res\xml 237 | 1 238 | 239 | 240 | 241 | 242 | library\lib\armeabi-v7a 243 | 1 244 | 245 | 246 | 247 | 248 | library\lib\armeabi 249 | 1 250 | 251 | 252 | library\lib\armeabi 253 | 1 254 | 255 | 256 | 257 | 258 | library\lib\armeabi-v7a 259 | 1 260 | 261 | 262 | 263 | 264 | library\lib\mips 265 | 1 266 | 267 | 268 | library\lib\mips 269 | 1 270 | 271 | 272 | 273 | 274 | library\lib\armeabi-v7a 275 | 1 276 | 277 | 278 | library\lib\arm64-v8a 279 | 1 280 | 281 | 282 | 283 | 284 | library\lib\armeabi-v7a 285 | 1 286 | 287 | 288 | 289 | 290 | res\drawable 291 | 1 292 | 293 | 294 | res\drawable 295 | 1 296 | 297 | 298 | 299 | 300 | res\values 301 | 1 302 | 303 | 304 | res\values 305 | 1 306 | 307 | 308 | 309 | 310 | res\values-v21 311 | 1 312 | 313 | 314 | res\values-v21 315 | 1 316 | 317 | 318 | 319 | 320 | res\values 321 | 1 322 | 323 | 324 | res\values 325 | 1 326 | 327 | 328 | 329 | 330 | res\drawable 331 | 1 332 | 333 | 334 | res\drawable 335 | 1 336 | 337 | 338 | 339 | 340 | res\drawable-xxhdpi 341 | 1 342 | 343 | 344 | res\drawable-xxhdpi 345 | 1 346 | 347 | 348 | 349 | 350 | res\drawable-xxxhdpi 351 | 1 352 | 353 | 354 | res\drawable-xxxhdpi 355 | 1 356 | 357 | 358 | 359 | 360 | res\drawable-ldpi 361 | 1 362 | 363 | 364 | res\drawable-ldpi 365 | 1 366 | 367 | 368 | 369 | 370 | res\drawable-mdpi 371 | 1 372 | 373 | 374 | res\drawable-mdpi 375 | 1 376 | 377 | 378 | 379 | 380 | res\drawable-hdpi 381 | 1 382 | 383 | 384 | res\drawable-hdpi 385 | 1 386 | 387 | 388 | 389 | 390 | res\drawable-xhdpi 391 | 1 392 | 393 | 394 | res\drawable-xhdpi 395 | 1 396 | 397 | 398 | 399 | 400 | res\drawable-mdpi 401 | 1 402 | 403 | 404 | res\drawable-mdpi 405 | 1 406 | 407 | 408 | 409 | 410 | res\drawable-hdpi 411 | 1 412 | 413 | 414 | res\drawable-hdpi 415 | 1 416 | 417 | 418 | 419 | 420 | res\drawable-xhdpi 421 | 1 422 | 423 | 424 | res\drawable-xhdpi 425 | 1 426 | 427 | 428 | 429 | 430 | res\drawable-xxhdpi 431 | 1 432 | 433 | 434 | res\drawable-xxhdpi 435 | 1 436 | 437 | 438 | 439 | 440 | res\drawable-xxxhdpi 441 | 1 442 | 443 | 444 | res\drawable-xxxhdpi 445 | 1 446 | 447 | 448 | 449 | 450 | res\drawable-small 451 | 1 452 | 453 | 454 | res\drawable-small 455 | 1 456 | 457 | 458 | 459 | 460 | res\drawable-normal 461 | 1 462 | 463 | 464 | res\drawable-normal 465 | 1 466 | 467 | 468 | 469 | 470 | res\drawable-large 471 | 1 472 | 473 | 474 | res\drawable-large 475 | 1 476 | 477 | 478 | 479 | 480 | res\drawable-xlarge 481 | 1 482 | 483 | 484 | res\drawable-xlarge 485 | 1 486 | 487 | 488 | 489 | 490 | res\values 491 | 1 492 | 493 | 494 | res\values 495 | 1 496 | 497 | 498 | 499 | 500 | 1 501 | 502 | 503 | 1 504 | 505 | 506 | 0 507 | 508 | 509 | 510 | 511 | 1 512 | .framework 513 | 514 | 515 | 1 516 | .framework 517 | 518 | 519 | 1 520 | .framework 521 | 522 | 523 | 0 524 | 525 | 526 | 527 | 528 | 1 529 | .dylib 530 | 531 | 532 | 1 533 | .dylib 534 | 535 | 536 | 1 537 | .dylib 538 | 539 | 540 | 0 541 | .dll;.bpl 542 | 543 | 544 | 545 | 546 | 1 547 | .dylib 548 | 549 | 550 | 1 551 | .dylib 552 | 553 | 554 | 1 555 | .dylib 556 | 557 | 558 | 1 559 | .dylib 560 | 561 | 562 | 1 563 | .dylib 564 | 565 | 566 | 1 567 | .dylib 568 | 569 | 570 | 0 571 | .bpl 572 | 573 | 574 | 575 | 576 | 0 577 | 578 | 579 | 0 580 | 581 | 582 | 0 583 | 584 | 585 | 0 586 | 587 | 588 | 0 589 | 590 | 591 | 0 592 | 593 | 594 | 0 595 | 596 | 597 | 0 598 | 599 | 600 | 0 601 | 602 | 603 | 604 | 605 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 606 | 1 607 | 608 | 609 | 610 | 611 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 612 | 1 613 | 614 | 615 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 616 | 1 617 | 618 | 619 | 620 | 621 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 622 | 1 623 | 624 | 625 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 626 | 1 627 | 628 | 629 | 630 | 631 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 632 | 1 633 | 634 | 635 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 636 | 1 637 | 638 | 639 | 640 | 641 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 642 | 1 643 | 644 | 645 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 646 | 1 647 | 648 | 649 | 650 | 651 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 652 | 1 653 | 654 | 655 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 656 | 1 657 | 658 | 659 | 660 | 661 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 662 | 1 663 | 664 | 665 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 666 | 1 667 | 668 | 669 | 670 | 671 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 672 | 1 673 | 674 | 675 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 676 | 1 677 | 678 | 679 | 680 | 681 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 682 | 1 683 | 684 | 685 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 686 | 1 687 | 688 | 689 | 690 | 691 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 692 | 1 693 | 694 | 695 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 696 | 1 697 | 698 | 699 | 700 | 701 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 702 | 1 703 | 704 | 705 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 706 | 1 707 | 708 | 709 | 710 | 711 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 712 | 1 713 | 714 | 715 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 716 | 1 717 | 718 | 719 | 720 | 721 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 722 | 1 723 | 724 | 725 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 726 | 1 727 | 728 | 729 | 730 | 731 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 732 | 1 733 | 734 | 735 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 736 | 1 737 | 738 | 739 | 740 | 741 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 742 | 1 743 | 744 | 745 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 746 | 1 747 | 748 | 749 | 750 | 751 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 752 | 1 753 | 754 | 755 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 756 | 1 757 | 758 | 759 | 760 | 761 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 762 | 1 763 | 764 | 765 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 766 | 1 767 | 768 | 769 | 770 | 771 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 772 | 1 773 | 774 | 775 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 776 | 1 777 | 778 | 779 | 780 | 781 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 782 | 1 783 | 784 | 785 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 786 | 1 787 | 788 | 789 | 790 | 791 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 792 | 1 793 | 794 | 795 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 796 | 1 797 | 798 | 799 | 800 | 801 | 1 802 | 803 | 804 | 1 805 | 806 | 807 | 808 | 809 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF 810 | 1 811 | 812 | 813 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF 814 | 1 815 | 816 | 817 | 818 | 819 | 820 | 821 | 822 | 1 823 | 824 | 825 | 1 826 | 827 | 828 | 1 829 | 830 | 831 | 832 | 833 | 834 | 835 | 836 | Contents\Resources 837 | 1 838 | 839 | 840 | Contents\Resources 841 | 1 842 | 843 | 844 | Contents\Resources 845 | 1 846 | 847 | 848 | 849 | 850 | library\lib\armeabi-v7a 851 | 1 852 | 853 | 854 | library\lib\arm64-v8a 855 | 1 856 | 857 | 858 | 1 859 | 860 | 861 | 1 862 | 863 | 864 | 1 865 | 866 | 867 | 1 868 | 869 | 870 | 1 871 | 872 | 873 | 1 874 | 875 | 876 | 1 877 | 878 | 879 | 0 880 | 881 | 882 | 883 | 884 | library\lib\armeabi-v7a 885 | 1 886 | 887 | 888 | 889 | 890 | 1 891 | 892 | 893 | 1 894 | 895 | 896 | 897 | 898 | Assets 899 | 1 900 | 901 | 902 | Assets 903 | 1 904 | 905 | 906 | 907 | 908 | Assets 909 | 1 910 | 911 | 912 | Assets 913 | 1 914 | 915 | 916 | 917 | 918 | 919 | 920 | 921 | 922 | 923 | 924 | 925 | 926 | 927 | 928 | 929 | False 930 | False 931 | False 932 | True 933 | False 934 | False 935 | True 936 | True 937 | 938 | 939 | 12 940 | 941 | 942 | 943 | 944 |
945 | -------------------------------------------------------------------------------- /Delphi/ChangeViews/Client/ChangeViewsEMSThingPoint.dproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | {AE2CE7DA-D701-4FDB-8C97-06EE8521522C} 4 | 20.3 5 | VCL 6 | True 7 | Debug 8 | Win32 9 | ChangeViewsEMSThingPoint 10 | 3 11 | Application 12 | ChangeViewsEMSThingPoint.dpr 13 | 14 | 15 | true 16 | 17 | 18 | true 19 | Base 20 | true 21 | 22 | 23 | true 24 | Base 25 | true 26 | 27 | 28 | true 29 | Base 30 | true 31 | 32 | 33 | true 34 | Cfg_1 35 | true 36 | true 37 | 38 | 39 | true 40 | Cfg_1 41 | true 42 | true 43 | 44 | 45 | true 46 | Base 47 | true 48 | 49 | 50 | true 51 | Cfg_2 52 | true 53 | true 54 | 55 | 56 | true 57 | Cfg_2 58 | true 59 | true 60 | 61 | 62 | .\$(Platform)\$(Config) 63 | .\$(Platform)\$(Config) 64 | false 65 | false 66 | false 67 | false 68 | false 69 | System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace) 70 | $(BDS)\bin\delphi_PROJECTICON.ico 71 | $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png 72 | $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png 73 | ChangeViewsEMSThingPoint 74 | 75 | 76 | vclwinx;DataSnapServer;fmx;emshosting;vclie;DbxCommonDriver;bindengine;IndyIPCommon;VCLRESTComponents;DBXMSSQLDriver;FireDACCommonODBC;emsclient;FireDACCommonDriver;appanalytics;IndyProtocols;vclx;Skia.Package.RTL;IndyIPClient;dbxcds;vcledge;bindcompvclwinx;FmxTeeUI;emsedge;bindcompfmx;DBXFirebirdDriver;inetdb;FireDACSqliteDriver;DbxClientDriver;FireDACASADriver;Tee;soapmidas;vclactnband;TeeUI;fmxFireDAC;dbexpress;FireDACInfxDriver;DBXMySQLDriver;VclSmp;inet;DataSnapCommon;vcltouch;fmxase;DBXOdbcDriver;dbrtl;FireDACDBXDriver;Skia.Package.FMX;FireDACOracleDriver;fmxdae;TeeDB;FireDACMSAccDriver;CustomIPTransport;FireDACMSSQLDriver;DataSnapIndy10ServerTransport;DataSnapConnectors;vcldsnap;DBXInterBaseDriver;FireDACMongoDBDriver;IndySystem;FireDACTDataDriver;Skia.Package.VCL;vcldb;vclFireDAC;bindcomp;FireDACCommon;DataSnapServerMidas;FireDACODBCDriver;emsserverresource;IndyCore;RESTBackendComponents;bindcompdbx;rtl;FireDACMySQLDriver;FireDACADSDriver;RESTComponents;DBXSqliteDriver;vcl;IndyIPServer;dsnapxml;dsnapcon;DataSnapClient;DataSnapProviderClient;adortl;DBXSybaseASEDriver;DBXDb2Driver;vclimg;DataSnapFireDAC;emsclientfiredac;FireDACPgDriver;FireDAC;FireDACDSDriver;inetdbxpress;xmlrtl;tethering;bindcompvcl;dsnap;CloudService;DBXSybaseASADriver;DBXOracleDriver;FireDACDb2Driver;DBXInformixDriver;fmxobj;bindcompvclsmp;FMXTee;DataSnapNativeClient;DatasnapConnectorsFreePascal;soaprtl;soapserver;FireDACIBDriver;$(DCC_UsePackage) 77 | Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) 78 | Debug 79 | true 80 | CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= 81 | 1033 82 | $(BDS)\bin\default_app.manifest 83 | 84 | 85 | vclwinx;DataSnapServer;fmx;emshosting;vclie;DbxCommonDriver;bindengine;IndyIPCommon;VCLRESTComponents;DBXMSSQLDriver;FireDACCommonODBC;emsclient;FireDACCommonDriver;appanalytics;IndyProtocols;vclx;IndyIPClient;dbxcds;vcledge;bindcompvclwinx;FmxTeeUI;emsedge;bindcompfmx;DBXFirebirdDriver;inetdb;FireDACSqliteDriver;DbxClientDriver;FireDACASADriver;Tee;soapmidas;vclactnband;TeeUI;fmxFireDAC;dbexpress;FireDACInfxDriver;DBXMySQLDriver;VclSmp;inet;DataSnapCommon;vcltouch;fmxase;DBXOdbcDriver;dbrtl;FireDACDBXDriver;FireDACOracleDriver;fmxdae;TeeDB;FireDACMSAccDriver;CustomIPTransport;FireDACMSSQLDriver;DataSnapIndy10ServerTransport;DataSnapConnectors;vcldsnap;DBXInterBaseDriver;FireDACMongoDBDriver;IndySystem;FireDACTDataDriver;Skia.Package.VCL;vcldb;vclFireDAC;bindcomp;FireDACCommon;DataSnapServerMidas;FireDACODBCDriver;emsserverresource;IndyCore;RESTBackendComponents;bindcompdbx;rtl;FireDACMySQLDriver;FireDACADSDriver;RESTComponents;DBXSqliteDriver;vcl;IndyIPServer;dsnapxml;dsnapcon;DataSnapClient;DataSnapProviderClient;adortl;DBXSybaseASEDriver;DBXDb2Driver;vclimg;DataSnapFireDAC;emsclientfiredac;FireDACPgDriver;FireDAC;FireDACDSDriver;inetdbxpress;xmlrtl;tethering;bindcompvcl;dsnap;CloudService;DBXSybaseASADriver;DBXOracleDriver;FireDACDb2Driver;DBXInformixDriver;fmxobj;bindcompvclsmp;FMXTee;DataSnapNativeClient;DatasnapConnectorsFreePascal;soaprtl;soapserver;FireDACIBDriver;$(DCC_UsePackage) 86 | Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace) 87 | Debug 88 | true 89 | CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= 90 | 1033 91 | $(BDS)\bin\default_app.manifest 92 | 93 | 94 | DEBUG;$(DCC_Define) 95 | true 96 | false 97 | true 98 | true 99 | true 100 | true 101 | true 102 | 103 | 104 | false 105 | PerMonitorV2 106 | 107 | 108 | PerMonitorV2 109 | 110 | 111 | false 112 | RELEASE;$(DCC_Define) 113 | 0 114 | 0 115 | 116 | 117 | PerMonitorV2 118 | 119 | 120 | PerMonitorV2 121 | 122 | 123 | 124 | MainSource 125 | 126 | 127 |
Form1
128 | dfm 129 |
130 | 131 | 132 |
dataHighscoresResource
133 | dfm 134 | TDataModule 135 |
136 | 137 |
ChangeViewConnection
138 | dfm 139 | TDataModule 140 |
141 | 142 | 143 | Base 144 | 145 | 146 | Cfg_1 147 | Base 148 | 149 | 150 | Cfg_2 151 | Base 152 | 153 |
154 | 155 | Delphi.Personality.12 156 | Application 157 | 158 | 159 | 160 | ChangeViewsEMSThingPoint.dpr 161 | 162 | 163 | 164 | 165 | 166 | ChangeViewsEMSThingPoint.exe 167 | true 168 | 169 | 170 | 171 | 172 | 1 173 | 174 | 175 | Contents\MacOS 176 | 1 177 | 178 | 179 | 0 180 | 181 | 182 | 183 | 184 | res\xml 185 | 1 186 | 187 | 188 | res\xml 189 | 1 190 | 191 | 192 | 193 | 194 | library\lib\armeabi 195 | 1 196 | 197 | 198 | library\lib\armeabi 199 | 1 200 | 201 | 202 | 203 | 204 | library\lib\armeabi-v7a 205 | 1 206 | 207 | 208 | 209 | 210 | library\lib\mips 211 | 1 212 | 213 | 214 | library\lib\mips 215 | 1 216 | 217 | 218 | 219 | 220 | library\lib\armeabi-v7a 221 | 1 222 | 223 | 224 | library\lib\arm64-v8a 225 | 1 226 | 227 | 228 | 229 | 230 | library\lib\armeabi-v7a 231 | 1 232 | 233 | 234 | 235 | 236 | res\drawable 237 | 1 238 | 239 | 240 | res\drawable 241 | 1 242 | 243 | 244 | 245 | 246 | res\drawable-anydpi-v21 247 | 1 248 | 249 | 250 | res\drawable-anydpi-v21 251 | 1 252 | 253 | 254 | 255 | 256 | res\values 257 | 1 258 | 259 | 260 | res\values 261 | 1 262 | 263 | 264 | 265 | 266 | res\values-v21 267 | 1 268 | 269 | 270 | res\values-v21 271 | 1 272 | 273 | 274 | 275 | 276 | res\values-v31 277 | 1 278 | 279 | 280 | res\values-v31 281 | 1 282 | 283 | 284 | 285 | 286 | res\values-v35 287 | 1 288 | 289 | 290 | res\values-v35 291 | 1 292 | 293 | 294 | 295 | 296 | res\drawable-anydpi-v26 297 | 1 298 | 299 | 300 | res\drawable-anydpi-v26 301 | 1 302 | 303 | 304 | 305 | 306 | res\drawable 307 | 1 308 | 309 | 310 | res\drawable 311 | 1 312 | 313 | 314 | 315 | 316 | res\drawable 317 | 1 318 | 319 | 320 | res\drawable 321 | 1 322 | 323 | 324 | 325 | 326 | res\drawable 327 | 1 328 | 329 | 330 | res\drawable 331 | 1 332 | 333 | 334 | 335 | 336 | res\drawable-anydpi-v33 337 | 1 338 | 339 | 340 | res\drawable-anydpi-v33 341 | 1 342 | 343 | 344 | 345 | 346 | res\values 347 | 1 348 | 349 | 350 | res\values 351 | 1 352 | 353 | 354 | 355 | 356 | res\values-night-v21 357 | 1 358 | 359 | 360 | res\values-night-v21 361 | 1 362 | 363 | 364 | 365 | 366 | res\drawable 367 | 1 368 | 369 | 370 | res\drawable 371 | 1 372 | 373 | 374 | 375 | 376 | res\drawable-xxhdpi 377 | 1 378 | 379 | 380 | res\drawable-xxhdpi 381 | 1 382 | 383 | 384 | 385 | 386 | res\drawable-xxxhdpi 387 | 1 388 | 389 | 390 | res\drawable-xxxhdpi 391 | 1 392 | 393 | 394 | 395 | 396 | res\drawable-ldpi 397 | 1 398 | 399 | 400 | res\drawable-ldpi 401 | 1 402 | 403 | 404 | 405 | 406 | res\drawable-mdpi 407 | 1 408 | 409 | 410 | res\drawable-mdpi 411 | 1 412 | 413 | 414 | 415 | 416 | res\drawable-hdpi 417 | 1 418 | 419 | 420 | res\drawable-hdpi 421 | 1 422 | 423 | 424 | 425 | 426 | res\drawable-xhdpi 427 | 1 428 | 429 | 430 | res\drawable-xhdpi 431 | 1 432 | 433 | 434 | 435 | 436 | res\drawable-mdpi 437 | 1 438 | 439 | 440 | res\drawable-mdpi 441 | 1 442 | 443 | 444 | 445 | 446 | res\drawable-hdpi 447 | 1 448 | 449 | 450 | res\drawable-hdpi 451 | 1 452 | 453 | 454 | 455 | 456 | res\drawable-xhdpi 457 | 1 458 | 459 | 460 | res\drawable-xhdpi 461 | 1 462 | 463 | 464 | 465 | 466 | res\drawable-xxhdpi 467 | 1 468 | 469 | 470 | res\drawable-xxhdpi 471 | 1 472 | 473 | 474 | 475 | 476 | res\drawable-xxxhdpi 477 | 1 478 | 479 | 480 | res\drawable-xxxhdpi 481 | 1 482 | 483 | 484 | 485 | 486 | res\drawable-small 487 | 1 488 | 489 | 490 | res\drawable-small 491 | 1 492 | 493 | 494 | 495 | 496 | res\drawable-normal 497 | 1 498 | 499 | 500 | res\drawable-normal 501 | 1 502 | 503 | 504 | 505 | 506 | res\drawable-large 507 | 1 508 | 509 | 510 | res\drawable-large 511 | 1 512 | 513 | 514 | 515 | 516 | res\drawable-xlarge 517 | 1 518 | 519 | 520 | res\drawable-xlarge 521 | 1 522 | 523 | 524 | 525 | 526 | res\values 527 | 1 528 | 529 | 530 | res\values 531 | 1 532 | 533 | 534 | 535 | 536 | res\drawable-anydpi-v24 537 | 1 538 | 539 | 540 | res\drawable-anydpi-v24 541 | 1 542 | 543 | 544 | 545 | 546 | res\drawable 547 | 1 548 | 549 | 550 | res\drawable 551 | 1 552 | 553 | 554 | 555 | 556 | res\drawable-night-anydpi-v21 557 | 1 558 | 559 | 560 | res\drawable-night-anydpi-v21 561 | 1 562 | 563 | 564 | 565 | 566 | res\drawable-anydpi-v31 567 | 1 568 | 569 | 570 | res\drawable-anydpi-v31 571 | 1 572 | 573 | 574 | 575 | 576 | res\drawable-night-anydpi-v31 577 | 1 578 | 579 | 580 | res\drawable-night-anydpi-v31 581 | 1 582 | 583 | 584 | 585 | 586 | 1 587 | 588 | 589 | Contents\MacOS 590 | 1 591 | 592 | 593 | 0 594 | 595 | 596 | 597 | 598 | Contents\MacOS 599 | 1 600 | .framework 601 | 602 | 603 | Contents\MacOS 604 | 1 605 | .framework 606 | 607 | 608 | Contents\MacOS 609 | 1 610 | .framework 611 | 612 | 613 | 0 614 | 615 | 616 | 617 | 618 | 1 619 | .dylib 620 | 621 | 622 | 1 623 | .dylib 624 | 625 | 626 | 1 627 | .dylib 628 | 629 | 630 | Contents\MacOS 631 | 1 632 | .dylib 633 | 634 | 635 | Contents\MacOS 636 | 1 637 | .dylib 638 | 639 | 640 | Contents\MacOS 641 | 1 642 | .dylib 643 | 644 | 645 | 0 646 | .dll;.bpl 647 | 648 | 649 | 650 | 651 | 1 652 | .dylib 653 | 654 | 655 | 1 656 | .dylib 657 | 658 | 659 | 1 660 | .dylib 661 | 662 | 663 | Contents\MacOS 664 | 1 665 | .dylib 666 | 667 | 668 | Contents\MacOS 669 | 1 670 | .dylib 671 | 672 | 673 | Contents\MacOS 674 | 1 675 | .dylib 676 | 677 | 678 | 0 679 | .bpl 680 | 681 | 682 | 683 | 684 | 0 685 | 686 | 687 | 0 688 | 689 | 690 | 0 691 | 692 | 693 | 0 694 | 695 | 696 | 0 697 | 698 | 699 | Contents\Resources\StartUp\ 700 | 0 701 | 702 | 703 | Contents\Resources\StartUp\ 704 | 0 705 | 706 | 707 | Contents\Resources\StartUp\ 708 | 0 709 | 710 | 711 | 0 712 | 713 | 714 | 715 | 716 | 1 717 | 718 | 719 | 1 720 | 721 | 722 | 723 | 724 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF 725 | 1 726 | 727 | 728 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF 729 | 1 730 | 731 | 732 | 733 | 734 | ..\ 735 | 1 736 | 737 | 738 | ..\ 739 | 1 740 | 741 | 742 | ..\ 743 | 1 744 | 745 | 746 | 747 | 748 | Contents 749 | 1 750 | 751 | 752 | Contents 753 | 1 754 | 755 | 756 | Contents 757 | 1 758 | 759 | 760 | 761 | 762 | Contents\Resources 763 | 1 764 | 765 | 766 | Contents\Resources 767 | 1 768 | 769 | 770 | Contents\Resources 771 | 1 772 | 773 | 774 | 775 | 776 | library\lib\armeabi-v7a 777 | 1 778 | 779 | 780 | library\lib\arm64-v8a 781 | 1 782 | 783 | 784 | 1 785 | 786 | 787 | 1 788 | 789 | 790 | 1 791 | 792 | 793 | 1 794 | 795 | 796 | Contents\MacOS 797 | 1 798 | 799 | 800 | Contents\MacOS 801 | 1 802 | 803 | 804 | Contents\MacOS 805 | 1 806 | 807 | 808 | 0 809 | 810 | 811 | 812 | 813 | library\lib\armeabi-v7a 814 | 1 815 | 816 | 817 | 818 | 819 | 1 820 | 821 | 822 | 1 823 | 824 | 825 | 1 826 | 827 | 828 | 829 | 830 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF 831 | 1 832 | 833 | 834 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF 835 | 1 836 | 837 | 838 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF 839 | 1 840 | 841 | 842 | 843 | 844 | ..\ 845 | 1 846 | 847 | 848 | ..\ 849 | 1 850 | 851 | 852 | ..\ 853 | 1 854 | 855 | 856 | 857 | 858 | 1 859 | 860 | 861 | 1 862 | 863 | 864 | 1 865 | 866 | 867 | 868 | 869 | ..\$(PROJECTNAME).launchscreen 870 | 64 871 | 872 | 873 | ..\$(PROJECTNAME).launchscreen 874 | 64 875 | 876 | 877 | 878 | 879 | 1 880 | 881 | 882 | 1 883 | 884 | 885 | 1 886 | 887 | 888 | 889 | 890 | Assets 891 | 1 892 | 893 | 894 | Assets 895 | 1 896 | 897 | 898 | 899 | 900 | Assets 901 | 1 902 | 903 | 904 | Assets 905 | 1 906 | 907 | 908 | 909 | 910 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 911 | 1 912 | 913 | 914 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 915 | 1 916 | 917 | 918 | 919 | 920 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 921 | 1 922 | 923 | 924 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 925 | 1 926 | 927 | 928 | 929 | 930 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 931 | 1 932 | 933 | 934 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 935 | 1 936 | 937 | 938 | 939 | 940 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 941 | 1 942 | 943 | 944 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 945 | 1 946 | 947 | 948 | 949 | 950 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 951 | 1 952 | 953 | 954 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 955 | 1 956 | 957 | 958 | 959 | 960 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 961 | 1 962 | 963 | 964 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 965 | 1 966 | 967 | 968 | 969 | 970 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 971 | 1 972 | 973 | 974 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 975 | 1 976 | 977 | 978 | 979 | 980 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 981 | 1 982 | 983 | 984 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 985 | 1 986 | 987 | 988 | 989 | 990 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 991 | 1 992 | 993 | 994 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 995 | 1 996 | 997 | 998 | 999 | 1000 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1001 | 1 1002 | 1003 | 1004 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1005 | 1 1006 | 1007 | 1008 | 1009 | 1010 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1011 | 1 1012 | 1013 | 1014 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1015 | 1 1016 | 1017 | 1018 | 1019 | 1020 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1021 | 1 1022 | 1023 | 1024 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1025 | 1 1026 | 1027 | 1028 | 1029 | 1030 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1031 | 1 1032 | 1033 | 1034 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1035 | 1 1036 | 1037 | 1038 | 1039 | 1040 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1041 | 1 1042 | 1043 | 1044 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 1045 | 1 1046 | 1047 | 1048 | 1049 | 1050 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1051 | 1 1052 | 1053 | 1054 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1055 | 1 1056 | 1057 | 1058 | 1059 | 1060 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1061 | 1 1062 | 1063 | 1064 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1065 | 1 1066 | 1067 | 1068 | 1069 | 1070 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1071 | 1 1072 | 1073 | 1074 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1075 | 1 1076 | 1077 | 1078 | 1079 | 1080 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1081 | 1 1082 | 1083 | 1084 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1085 | 1 1086 | 1087 | 1088 | 1089 | 1090 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1091 | 1 1092 | 1093 | 1094 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1095 | 1 1096 | 1097 | 1098 | 1099 | 1100 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1101 | 1 1102 | 1103 | 1104 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1105 | 1 1106 | 1107 | 1108 | 1109 | 1110 | 1111 | 1112 | 1113 | 1114 | 1115 | 1116 | 1117 | 1118 | 1119 | 1120 | 1121 | 1122 | True 1123 | True 1124 | 1125 | 1126 | 12 1127 | 1128 | 1129 | 1130 | 1131 |
1132 | --------------------------------------------------------------------------------