From 3ad8894107b52d25c4bb9bd95e893bed6bbdfe3c Mon Sep 17 00:00:00 2001 From: "alexey.zablotskiy" Date: Wed, 2 Jul 2025 12:34:35 +0300 Subject: [PATCH] LMS2.1 --- baseconnection.pas | 28 +++++++++---- cgi_daemon.pas | 17 +++++++- cgi_mapper.lfm | 2 + cgi_mapper.pas | 27 ++++++++++++- cgidm.pas | 19 ++++++++- cgireport.pas | 67 +++++++++++++++++++++++++++---- commandcol.pas | 5 +++ connectionsdmunit.lfm | 2 +- connectionsdmunit.pas | 97 ++++++++++++++++++++++++++++++++++++++++----- exttypes.pas | 1 + fr_utils.pas | 1 - lms_cgi.lpr | 17 +++++++- lms_cgi.obj | Bin 62696 -> 86744 bytes lms_cgi_server.ini | 2 +- lms_cgi_server.lpi | 8 +++- lmsreport.lpi | 6 +++ maintcpserver.lfm | 79 +++++++++++++++++++----------------- maintcpserver.pas | 19 ++++++++- reports/allreportsunit.pas | 2 +- tcpclient.pas | 3 +- tcpserver.pas | 14 ++++--- tcpthreadhelper.pas | 45 +++++++++++++-------- 22 files changed, 364 insertions(+), 97 deletions(-) diff --git a/baseconnection.pas b/baseconnection.pas index 6fb85e8..88548fd 100644 --- a/baseconnection.pas +++ b/baseconnection.pas @@ -18,7 +18,7 @@ type fConnectionID: string; fTimeout: integer; fProcessor: TNIDBDM; - + fJournal: TStrings; Commands: TStrings; DoneCommands: TList; fCreated, @@ -51,7 +51,7 @@ type property ConnectionID: string read fConnectionID; property Processor: TNIDBDM read fProcessor; procedure Init; - constructor Create(AOwner: TComponent;ATimeOut: integer; aLogger: TLogger); + constructor Create(AOwner: TComponent;ATimeOut: integer; aLogger: TLogger; ID: string=''); destructor Destroy; override; // CommandID,Param,ACommand,Fields,iParam.Data function AddCommand(ACode: DWORD; iParam: QWORD; ACommandClass,ACommandName: string; Arguments: TStrings; intArgs: TParamArray; CmdData: TStream; out ID: string; out retCode:DWORD; out Errors: TStrings): boolean; @@ -63,6 +63,7 @@ type function ProcessOptionValues(ReportName,ParamName: string; ParamValues: TStrings; out Answer: string; out RetValue: QWORD; out OptionValues: TStrings): boolean; class function newID: string; function calchash(data: TStream): string; + property Journal: TStrings read fJournal; end; implementation @@ -84,10 +85,13 @@ end; constructor TBaseConnection.Create(AOwner: TComponent; ATimeOut: integer; - aLogger: TLogger); + aLogger: TLogger; ID: string); begin inherited Create(true); - fConnectionID:=newID; + if ID='' then + fConnectionID:=newID + else + fConnectionID:=ID; fTimeout:=ATimeOut; fOwner := AOwner; flogger := ALogger; @@ -103,7 +107,7 @@ begin nCommandReceived:=0; nCommandReady:=0; nErrors:=0; - + fJournal := TStringList.Create; end; @@ -113,6 +117,7 @@ begin Processor.Free; Commands.Free; DoneCommands.Free; + fJournal.free; inherited; end; @@ -132,7 +137,7 @@ begin cc := TCommandCollection.Find(ACommandClass,ACommandName); if assigned(cc) then begin - cmd := cc.Create(self.newID, self.Processor,ACommandName,fLogger,User,UserID); + cmd := cc.Create(self.newID, self.Processor,ACommandName,@log,User,UserID); cmd.AccessTime:=NOW(); try result := cmd.ParseCommand(ACode,iParam,ACommandName,Arguments,intArgs,CmdData, Errors); @@ -145,14 +150,18 @@ begin end; if result then begin + Commands.AddObject(ACommandName,cmd); ID := cmd.CommandID; retCode := Commands.Count; + log(mtInfo,cmd, format('%s(%s) %s поставлена в очередь %d',[cmd.CommandName, cmd.CommandSubClass, cmd.CommandID,Commands.Count])); end else begin ID := 'неверные параметры запроса'; retCode := ErrorArguments; + log(mtError,cmd, format('%s(%s) %s неверные параметры запроса %s',[cmd.CommandName, cmd.CommandSubClass, cmd.CommandID, Errors.CommaText])); + inc(nErrors); cmd.Error:=true; cmd.Done; @@ -217,7 +226,7 @@ begin fCheckConnect:=false; d := Created; if LastAccess>d then d := LastAccess; - if (now()-d)*24*60>fTimeout then + if (ConnectionID<>'0') and ((now()-d)*24*60>fTimeout) then begin log(mtInfo,self,'TIMEOUT'); terminate; @@ -251,6 +260,11 @@ end; procedure TBaseConnection.Log(ALevel: TLogLevel; sender: TObject; msg: string); begin + case ALevel of + mtError: fJournal.AddObject('ERROR:'#09+msg, TObject(PtrInt(trunc(now()*24*60*60*10)))); + mtWarning: fJournal.AddObject('WARNING:'#09+msg, TObject(PtrInt(trunc(now()*24*60*60*10)))); + mtInfo: fJournal.AddObject('INFO:'#09+msg, TObject(PtrInt(trunc(now()*24*60*60*10)))); + end; if assigned(fLogger) then flogger(ALevel,sender,msg); end; diff --git a/cgi_daemon.pas b/cgi_daemon.pas index 231a862..fcba685 100644 --- a/cgi_daemon.pas +++ b/cgi_daemon.pas @@ -17,7 +17,7 @@ type procedure Execute;override; function sleepMin(n: integer): boolean; constructor Create(AOwner: TLMSReportCGI); - + function CheckTerminated(Sender: TObject): boolean; end; { TLMSReportCGI } @@ -60,6 +60,12 @@ begin {$ENDIF} self.logger.Identification:='LMS-Report-Service'; self.Logger.Active:=true; + if Definition<>nil then + try + self.logger.Info(format('Daemon(%d) %s/%s {%s} (%s)',[Definition.ID, Definition.Name,Definition.DisplayName,Definition.Description,Definition.RunArguments])); + except on e: Exception do + self.logger.Error('DataModuleCreate '+e.Message); + end; workThread := TDaemonThread.create(self); end; @@ -88,7 +94,9 @@ procedure TDaemonThread.Execute; begin fData := TConnectionsDM.CreateWithLog(fLogger); try - fData.Start; + flogger.Debug('TDaemonThread.Execute.1'); + fData.Start(@CheckTerminated); + flogger.Debug('TDaemonThread.Execute.Started'); while not terminated do begin if sleepMin(5) then @@ -119,6 +127,11 @@ begin fLogger:=AOwner.Logger; end; +function TDaemonThread.CheckTerminated(Sender: TObject): boolean; +begin + result := terminated; +end; + initialization RegisterDaemon; diff --git a/cgi_mapper.lfm b/cgi_mapper.lfm index 4a1f5eb..c618b03 100644 --- a/cgi_mapper.lfm +++ b/cgi_mapper.lfm @@ -13,8 +13,10 @@ object DaemonMapper1: TDaemonMapper1 WinBindings.ServiceType = stWin32 WinBindings.ErrorSeverity = esIgnore WinBindings.AcceptedCodes = [] + OnCreateInstance = DaemonMapper1DaemonDefs0CreateInstance LogStatusReport = False end> + OnCreate = DaemonMapper1Create Left = 1065 Top = 332 end diff --git a/cgi_mapper.pas b/cgi_mapper.pas index 03bff21..969769c 100644 --- a/cgi_mapper.pas +++ b/cgi_mapper.pas @@ -8,7 +8,12 @@ uses Classes, SysUtils, DaemonApp; type + + { TDaemonMapper1 } + TDaemonMapper1 = class(TDaemonMapper) + procedure DaemonMapper1Create(Sender: TObject); + procedure DaemonMapper1DaemonDefs0CreateInstance(Sender: TObject); private public @@ -19,7 +24,8 @@ var DaemonMapper1: TDaemonMapper1; implementation - +uses + lazutf8; procedure RegisterMapper; begin RegisterDaemonMapper(TDaemonMapper1) @@ -27,6 +33,25 @@ end; {$R *.lfm} +{ TDaemonMapper1 } + +procedure TDaemonMapper1.DaemonMapper1Create(Sender: TObject); +var + i: integer; +begin + for i := 0 to DaemonDefs.Count-1 do + begin + DaemonDefs.Daemons[i].DisplayName:=UTF8ToConsole(DaemonDefs.Daemons[i].DisplayName); + DaemonDefs.Daemons[i].Description:=UTF8ToConsole(DaemonDefs.Daemons[i].Description); + end; +end; + +procedure TDaemonMapper1.DaemonMapper1DaemonDefs0CreateInstance(Sender: TObject + ); +begin + +end; + initialization RegisterMapper; diff --git a/cgidm.pas b/cgidm.pas index fdbd232..d9a7a63 100644 --- a/cgidm.pas +++ b/cgidm.pas @@ -43,6 +43,7 @@ type function CheckConnection: boolean; function QueryValue(ASQL: string; Default: string=''): string; function QueryIntValue(ASQL: string): integer; + function QueryDateValue(ASQL: string): TDateTime; function GetData(ASQL: string): TDataSet; function CheckUser(const login,password: string; out UserID: integer): boolean; procedure OpenConnection; @@ -330,6 +331,22 @@ begin end; end; +function TNIDBDM.QueryDateValue(ASQL: string): TDateTime; +begin + log(mtDebug,self,'QueryIntValue'#13#10+ASQL); + CheckConnection; + with TnnzQuery.Create(self) do + try + Connection := fcon; + SQL.Text:=ASQL; + Open; + if not eof then result := Fields[0].AsDateTime else result := 0; + finally + free; + end; +end; + + function TNIDBDM.GetData(ASQL: string): TDataSet; begin @@ -355,7 +372,7 @@ end; procedure TNIDBDM.OpenConnection; begin - log(mtDebug,self,'OpenConnection'); + log(mtDebug,self,format('OpenConnection %s:%d',[connection.RemoteHost,connection.RemotePort])); fcon.Connected:=true; fcon.Identify; end; diff --git a/cgireport.pas b/cgireport.pas index bb6b45b..2ac4b61 100644 --- a/cgireport.pas +++ b/cgireport.pas @@ -85,11 +85,11 @@ var d: TStringDynArray; i: integer; begin - ReportCode := Processor.QueryValue(format('select report_routine from xp_report_cgi where cgi_name=%s',[TNidbDM.StringAsSQL(ReportName)])); + ReportCode := Processor.QueryValue(format('select report_routine from xp_report_cgi where cgi_name=%s',[TNIDBDM.StringAsSQL(ReportName)])); UpdateCodeWithArguments(ReportCode); if reportcode<>'' then Processor.ExecuteSQL(format('select %s;',[ReportCode])); - ASQL := format( 'select array_to_string(extra_routines,'';'') as v from xp_report_cgi where cgi_name=%s',[TNidbDM.StringAsSQL(ReportName)]); + ASQL := format( 'select array_to_string(extra_routines,'';'') as v from xp_report_cgi where cgi_name=%s',[TNIDBDM.StringAsSQL(ReportName)]); v := Processor.QueryValue(ASQL); if v>'' then begin @@ -106,7 +106,7 @@ end; procedure TReportCommand.PrepareVars; begin - VarCode := Processor.QueryValue(format('select report_routine_vars from xp_report_cgi where cgi_name=%s',[TNidbDM.StringAsSQL(ReportName)])); + VarCode := Processor.QueryValue(format('select report_routine_vars from xp_report_cgi where cgi_name=%s',[TNIDBDM.StringAsSQL(ReportName)])); UpdateCodeWithArguments(VarCode); if VarCode<>'' then Processor.ExecuteSQL(format('select %s;',[VarCode])); @@ -144,7 +144,7 @@ begin vs := ''; end; script := script + format(#13#10'insert into tmp_report_variables(name,value_string,var_type) values (%s,%s,0); ', - [TNIDBDM.StringAsSQL(fieldByName('name').asString),TNidbDM.StringAsSQL(vs)]); + [TNIDBDM.StringAsSQL(fieldByName('name').asString),TNIDBDM.StringAsSQL(vs)]); Next; end; finally @@ -212,13 +212,13 @@ begin fcurrentStage := 'исполняется (инициализация)'; fileData := TMemoryStream.Create; try - ReportID := Processor.QueryIntValue(format('select xp_rpt_id from xp_report_cgi where cgi_name=%s',[TNidbDM.StringAsSQL(ReportName)])); + ReportID := Processor.QueryIntValue(format('select xp_rpt_id from xp_report_cgi where cgi_name=%s',[TNIDBDM.StringAsSQL(ReportName)])); if ReportID<=0 then begin fResult := TCommandData.Create(ErrorArguments,0,'Отчет не найден',nil,[],nil); exit; end; - ReportTitle := Processor.QueryValue(format('select r.name from xp_report_cgi g join xp_report r on r.xp_rpt_id=g.xp_rpt_id where cgi_name=%s',[TNidbDM.StringAsSQL(ReportName)])); + ReportTitle := Processor.QueryValue(format('select r.name from xp_report_cgi g join xp_report r on r.xp_rpt_id=g.xp_rpt_id where cgi_name=%s',[TNIDBDM.StringAsSQL(ReportName)])); CreateVariablesTable; log(mtInfo,'Построение отчета '+ReportTitle); ReportProcessor.RecordID:=ReportID; @@ -253,7 +253,7 @@ begin exit; end; end; - fResult := TCommandData.Create(0,fileData.size,ReportTitle+'.pdf',['type=application/pdf'],[],fileData); + fResult := TCommandData.Create(0,fileData.size,ReportTitle+'.pdf',['{"type":"application/pdf"}'],[],fileData); fileData.Seek(0,soFromBeginning); {$IFDEF DEBUG} (fileData as TMemoryStream).SaveToFile(format('%sout/%s_%s.pdf',[ Extractfilepath(paramstr(0)),self.CommandID,ReportTitle])); {$ENDIF} fileData.Seek(0,soFromBeginning); @@ -269,6 +269,19 @@ var asql: string; ids: string; i: integer; + value: string; + val_int: integer; + val_float: double; + val_date: TDateTime; + fmt: TFormatSettings; + val_ids: TStringDynArray; +procedure AddToErrors(error: string); +begin + if not assigned(Errors) then + Errors := TStringList.Create; + Errors.Add(error); +end; + begin result := false; Errors := nil; @@ -302,7 +315,45 @@ begin finally free; end; - + asql := format( + 'select p.name, p.type from xp_report_cgi c '+ + 'join xp_report_params p on p.xp_rpt_id=c.xp_rpt_id and coalesce(p.required,true) '+ + 'where c.cgi_name=%s and p.name in (%s) '+ + ' and p.type in (1,2) '+ + 'order by fill_order,p.name ', + [TNIDBDM.StringAsSQL(ReportName),(ids)]); + fmt.DateSeparator:='-'; + fmt.TimeSeparator:=':'; + fmt.ShortDateFormat:='yyyy-mm-dd'; + fmt.ShortTimeFormat:='hh:nn:ss'; + with Processor.GetData(asql) do + try + while not eof do + begin + value := Arguments.Keys.Values[fieldbyname('name').AsString]; + case FieldByName('type').asInteger of + 1: if not TryStrToInt(value,val_int) then AddToErrors(format('{name:"%s",type:"ID"}',[TNIDBDM.StringAsJSON(FieldByName('name').AsString)])); + 2: if not TryStrToInt(value,val_int) then AddToErrors(format('{name:"%s",type:"integer"}',[TNIDBDM.StringAsJSON(FieldByName('name').AsString)])); + 3: if not TryStrToFloat(value,val_float) then AddToErrors(format('{name:"%s",type:"float"}',[TNIDBDM.StringAsJSON(FieldByName('name').AsString)])); + 4: if not TryStrToDate(value,val_date,'yyyy-mm-dd','-') then AddToErrors(format('{name:"%s",type:"date"}',[TNIDBDM.StringAsJSON(FieldByName('name').AsString)])); + 5: if not TryStrToDateTime(value,val_date,fmt) then AddToErrors(format('{name:"%s",type:"time"}',[TNIDBDM.StringAsJSON(FieldByName('name').AsString)])); + 6: if not( (Value='0') or (Value='1') ) then AddToErrors(format('{name:"%s",type:"boolean"}',[TNIDBDM.StringAsJSON(FieldByName('name').AsString)])); + 17: begin + val_ids := SplitString(value,','); + for i := low(val_ids) to high(val_ids) do + if not TryStrToInt(val_ids[i],val_int) then + begin + AddToErrors(format('{name:"%s",type:"IDS"}',[TNIDBDM.StringAsJSON(FieldByName('name').AsString)])); + break; + end; + end; + end; + next; + end; + finally + free; + end; + result := not assigned(Errors); end; function TReportCommand.ProcessOptionValues(ParamName: string; out diff --git a/commandcol.pas b/commandcol.pas index 8601c50..540ea52 100644 --- a/commandcol.pas +++ b/commandcol.pas @@ -125,6 +125,8 @@ end; constructor TCommand.Create(ID: string; aProcessor: TNIDBDM; ASubClass: string; aLogger: TLogger; AUser: string; IDUser: integer); begin + if assigned(aLogger) then + aLogger(mtExtra,self,'CREATE '+self.ClassName); fProcessor := AProcessor; fSubClass := ASubClass; fStatus:=StatusWaiting; @@ -149,6 +151,7 @@ end; procedure TCommand.doRun; begin + log(mtInfo,format('%s(%s) %s - начато выполнение',[commandName,CommandSubClass, commandID])); fStatus:=StatusProcessing; fcurrentStage := 'исполняется'; try @@ -156,11 +159,13 @@ begin begin fStatus:=StatusComplete; fcurrentStage := 'завершена'; + log(mtInfo,format('%s(%s) %s - выполнена',[commandName,CommandSubClass, commandID])); end else begin fStatus := StatusError; fcurrentStage := 'завершена c ошибкой'; + log(mtInfo,format('%s(%s) %s - ошибка',[commandName,CommandSubClass, commandID])); end; except on e: Exception do diff --git a/connectionsdmunit.lfm b/connectionsdmunit.lfm index a02bef0..6b206e3 100644 --- a/connectionsdmunit.lfm +++ b/connectionsdmunit.lfm @@ -4,7 +4,7 @@ object ConnectionsDM: TConnectionsDM OldCreateOrder = False Height = 150 HorizontalOffset = 738 - VerticalOffset = 342 + VerticalOffset = 344 Width = 533 object Process1: TProcess Active = False diff --git a/connectionsdmunit.pas b/connectionsdmunit.pas index cd8fb77..dfcee80 100644 --- a/connectionsdmunit.pas +++ b/connectionsdmunit.pas @@ -34,8 +34,9 @@ type fLogger: TEventLog; fTimeOut: integer; fRunning: boolean; + fTermiinateCheck: TChecker; function getConnection(ID: string): TBaseConnection; - function NewConnection: TBaseConnection; + function NewConnection(ID: string=''): TBaseConnection; procedure Remove(con: TBaseConnection); overload; procedure Remove(ID: string); overload; procedure ClearConnections; @@ -55,7 +56,7 @@ type procedure Log(ALevel: TLogLevel; Sender: TObject; msg: string); procedure LogError(Sender: TObject; e: Exception; Command: string); procedure InitBaseCon; - procedure Start; + procedure Start(isTerminated: TChecker); procedure Stop; procedure Idle(Sender: TObject); property Running: boolean read fRunning; @@ -65,6 +66,7 @@ type constructor CreateWithLog(ALogger: TEventLog); procedure FillTemplates(RepList: TStrings); procedure EditTemplate(ReportID: integer); + procedure TestReport(ReportID: integer); function CalcHash(Data: TStream): string; end; @@ -82,12 +84,20 @@ uses { TConnectionsDM } procedure TConnectionsDM.DataModuleCreate(Sender: TObject); +var + con: TBaseConnection; begin fRunning := false; conList := TList.Create; MainCon := TNIDBDM.CreateWithLogger(@log); LoadConfig; - input := TServerMainThread.Create(@log,fServicePort,@ProcessRequest); + input := nil; + {$IFDEF DEBUG} + con := NewConnection('0'); + con.User:='anonymous'; + con.UserID := 0; + con.Start; + {$ENDIF} end; procedure TConnectionsDM.DataModuleDestroy(Sender: TObject); @@ -99,8 +109,10 @@ begin begin Input.Terminate; Input.WaitFor; + Input.Free; end; - Input.Free; + + MainCon.Free; conList.Free; @@ -120,13 +132,13 @@ begin result := nil; end; -function TConnectionsDM.NewConnection: TBaseConnection; +function TConnectionsDM.NewConnection(ID: string): TBaseConnection; var g: TGUID; s: string; i: integer; begin - result := TBaseConnection.Create(self,fTimeOut,@Log); + result := TBaseConnection.Create(self,fTimeOut,@Log,ID); conlist.add(result); result.Host:=DataHost; result.port:=DataPort; @@ -209,14 +221,24 @@ function TConnectionsDM.ProcessRequest(Sender: TMainThread; const Fields: TStrings; const iParams: TParamArray; const Data: TStream; out Code: DWORD; out RetValue: QWord; out Answer: string; out rValues: TStrings; out iValues: TParamArray; out ByteData: TStream): boolean; +procedure waitforresult(Pause: integer; acmd: TCommand); +begin + if acmd.Status in [StatusComplete,StatusError] then exit; + while (pause>0) and not(acmd.Status in [StatusWaiting,StatusProcessing]) do + begin + Sleep(1000); + dec(pause); + end; +end; var UserID: integer; con: TBaseConnection; userName,conID,cmdID: string; cmd: TCommand; + i: integer; begin try - log(mtDebug, Self,'Обработка запроса '+ACommand); + log(mtInfo, Self,'Обработка запроса '+ACommand); ClearTerminated; result := false; RetValue := 0; @@ -240,10 +262,11 @@ begin rvalues.Add('"help"'); rvalues.Add('"version"'); rValues.add('"reports"'); - rValues.add('{action:"arguments",params:["name"]}'); + rValues.add('{action:"arguments",params:["report"]}'); rValues.add('{action:"login",params:["user","password"]}'); rValues.add('{action:"logout",params:["connect"]}'); rValues.add('{action:"test",params:["connect"]}'); + rValues.add('{action:"log",params:["connect"]}'); rValues.add('{action:"option_values",params:["connect","report","name"]}'); rValues.add('{action:"report",params:["connect","name"]}'); rValues.add('{action:"status",params:["connect","operation"]}'); @@ -257,7 +280,7 @@ begin end; if ACommand='arguments' then begin - result := ProcessArguments(Fields.Values['name'],RetValue,Answer,rValues); + result := ProcessArguments(Fields.Values['report'],RetValue,Answer,rValues); if not result then begin Code := ErrorArguments; @@ -310,6 +333,19 @@ begin Remove(con.ConnectionID); exit; end; + if ACommand='log' then + begin + result := true; + Answer := 'OK'; + rValues := TStringList.Create; + for i := 0 to con.Journal.count-1 do + begin + rValues.add('"'+TNIDBDM.StringAsJSON(con.Journal[i])+'"'); + end; + con.Journal.Clear; + exit; + end; + con.Log(mtInfo,self,'Получен запрос '+ACommand); if ACommand='connectStatus' then begin result := true; @@ -348,7 +384,8 @@ begin else begin rValues := TSTringList.Create; - rValues.Assign(cmd.Journal); + for i := 0 to cmd.Journal.count-1 do + rValues.add('"'+TNIDBDM.StringAsJSON(cmd.Journal[i])+'"'); end; code := cmd.Status; if (code=StatusComplete) and assigned(cmd.Results.Data) then @@ -360,12 +397,19 @@ begin end; if ACommand='result' then begin + waitforresult(StrToIntDef(Fields.Values['wait'],0),cmd); if cmd.Status=StatusComplete then begin cmd.Results.AssignTo(Code,RetValue,Answer,rValues,iValues,ByteData); cmd.Done; result := true; end + else if cmd.Status=StatusError then + begin + cmd.Results.AssignTo(Code,RetValue,Answer,rValues,iValues,ByteData); + cmd.Done; + result := false; + end else begin Code := ErrorComplete; @@ -463,6 +507,30 @@ begin end; end; +procedure TConnectionsDM.TestReport(ReportID: integer); +var + asql: string; + RName: string; + con: TBaseConnection; + cc: TCommandClass; + cmd: TReportCommand; +begin + asql := format('select cgi_name from xp_report_cgi where xp_rpt_id=%d',[ReportID]); + RName := MainCon.QueryValue(asql); + cc := TCommandCollection.Find('report',RName); + cmd := cc.Create('', MainCon,RName,@Log,'',0) as TReportCommand; + try + cmd.ReportID := ReportID; + cmd.ReportName:=RName; + cmd.FillDefaults; + cmd.Run(); + + finally + cmd.free; + end; +end; + + function TConnectionsDM.ProcessLogin(UserName, UserPassword: string; out UserID: integer): boolean; var ASQL: string; @@ -636,6 +704,8 @@ begin log(mtInfo,self,format('База данных %s:%d/%s Порт для соединения %d',[fDataHost,fDataPort,fDataBase,fServicePort])); end; + + procedure TConnectionsDM.Log(ALevel: TLogLevel; Sender: TObject; msg: string); var s: string; @@ -655,7 +725,10 @@ begin mtError: fLogger.Error(s); mtWarning: fLogger.Warning(s); mtInfo: flogger.Info(s); + {$IFDEF DEBUG} mtDebug: fLogger.Debug(s); + mtExtra: fLogger.Log(#09+s); + {$ENDIF} end; except end; @@ -675,9 +748,11 @@ begin MainCon.OpenConnection; end; -procedure TConnectionsDM.Start; +procedure TConnectionsDM.Start(isTerminated: TChecker); begin + fTermiinateCheck := isTerminated; InitBaseCon;//Input.OnIdle:=@Idle; + input := TServerMainThread.Create(@log,fServicePort,fTermiinateCheck,@ProcessRequest); Input.Start; fRunning:=true; end; diff --git a/exttypes.pas b/exttypes.pas index 5eed2ea..4288a9c 100644 --- a/exttypes.pas +++ b/exttypes.pas @@ -30,6 +30,7 @@ type TParamArray=Array of QWORD; TLogLevel=(mtError,mtWarning,mtInfo,mtDebug,mtExtra); TLogger=procedure(ALevel: TLogLevel; Sender: TObject; Msg: String ) of object; + TChecker=function(Sender: TObject): boolean of object; EFormatException=class(Exception); { TConnectionThread } diff --git a/fr_utils.pas b/fr_utils.pas index fb260e5..c0e5d85 100644 --- a/fr_utils.pas +++ b/fr_utils.pas @@ -65,7 +65,6 @@ begin if AMethodName = '_' then Result := _(Params[0]) else if AnsiSameText(AMethodName,'Log') then begin - {$IFDEF DEBUG} cxlogger.TLogSystem.Loggers['fastreport'].writelog(Params[0],Params[1]); {$ENDIF} result := true; end else diff --git a/lms_cgi.lpr b/lms_cgi.lpr index 92a379d..6e321de 100644 --- a/lms_cgi.lpr +++ b/lms_cgi.lpr @@ -9,8 +9,8 @@ uses {$IFDEF HASAMIGA} athreads, {$ENDIF} - Interfaces, Classes, SysUtils, inifiles, httpDefs, fpweb, custweb, custcgi, - lnetbase, tcpClient, tcpthreadhelper, extTypes, eventlog; + Interfaces, Classes, SysUtils, inifiles, httpDefs, fpweb, custweb, custcgi, + lnetbase, tcpClient, tcpthreadhelper, extTypes, eventlog; Type @@ -178,6 +178,18 @@ log(mtDebug,self,'Data READY'); {$ENDIF} if not assigned(fData) then begin + if fmODE=3 then + case fCode of + ErrorProcessor: AResponse.Code:=503; + ErrorLogin: AResponse.Code:=401; + ErrorConnect: AResponse.Code:=401; + ErrorCommand: AResponse.Code:=501; + ErrorComplete: AResponse.Code:=202; + ErrorArguments: AResponse.Code:=400; + ErrorInternal: AResponse.Code:=500; + end + else + AResponse.Code:=200; AResponse.ContentType := 'application/json'; AResponse.Contents.add('{'); AResponse.Contents.add('"type":'+aTypes[fMode]+','); @@ -259,6 +271,7 @@ begin flogger := TEventLog.Create(self); flogger.Identification:='lms_cgi_client'; flogger.LogType:={$IFDEF LINUX}ltSystem{$ELSE}ltFile{$ENDIF}; + flogger.AppendContent:=true; inherited Create(AOwner); end; diff --git a/lms_cgi.obj b/lms_cgi.obj index 939c58e44a893b027fff8466f84ade3f2c538683..c802a7db0b5c430ba429988086de0026fa2845c0 100644 GIT binary patch delta 58576 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

e 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�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 delta 35173 zcmeFZWmpwo_xL?@cO5!J1f*NKL%O?_2I+=FOG|eONVjxKOM}vlA|Vpe3i6D22j183 z`~G?Hp9|M#*4nXlo!N2DIA4UYvkQmzEDQ$teNCSN@o2<2Y{vi~2afbSm?$o_*}=O64= z|6uq0%YNtokK^#a0)Ch4k3H=l>?QwTZ~h1S(Enxs?SKCN3IOdp|6srT2RkzE??T_d z{?!HlV5bM|_uC&#`L8bchXk_!VAuHvyVd{Lf9I}(1_Y$R0RjIiX5tbY2GsL^;<15& z0bo2)1Rx*@qz=d$kd7cnL571|2AK!)6l60?avKyo*$a#=@Adf&gf<#6F0%Ac@fvf<@ z2eK8U3dl*2Rv^EC3;=lwG7TguCRhoOR3L{ya)De2se%awor5=apaB~h2=E0-4>Ad) zD98$sIv_uSbOd<-G8`m67T5wH*+4dfR025((g@@ZNOzC`3RqB(5Rio+*+8~}lm$5o z(gfreD0t%u-T>HO3xI@xEcvbfb^RF{;s4WB{~j`F|6niq2Yd59yZs+Oe;f?m3%GBe z{|EcdKiDt-!H%403PS_~xs&vFlJ8E+-btN1X>}((?_~I$OuLgMce43T4&BN5JGpZw zFYhFB;_+Snza{Q*_y^}h3(&|on-pTMgnRX{j?qu_w9J-V9cXH=WUfxOML?^i4 z<^L_|?H^?}U^B{9T9)YX?i41=7T0v5Q90JJ)@}5Uj@cv(8=B`j_ce3P8Hs8siJ2`(R zckblnokUKALHb?A-;(~fgykcwA4U&@ORT{rNyNmVON_%IgTYLEf=ga+gc}J1l_dlK zu0Ou+3gAohw_XGJTmMW9>Tv%pD})@>;s2{EQ2!l2fadS`Zy){@9}4U+{GEX8@!ttl zSpG@?gmC;FznSyz`1?G6$EOnbJH7@ung6!};4?g2C@zvFkS{2l*P<6ivVa|pfGJp-s4X#cIp=>Py&>Hl1Ppze9E%LMhnAlUx|1A+zs zAbU>_F#-UudpckW0Mh^J!n-+4_8GXmx!0#}EdgNno`XDV0Fbzs!Dm|lAh;L*+Trg4 zxjOz`AXn$V3)Jok0Ca!yyYmlxb_X5ab1>-z0NM8(IQjv=;=OQ%000oXH|XL*03aRV zzb(KN2>{RT#gB^y0MmQ~-H2&?txA|`e^lg7T zQ0N2z8sz_`cN_o!gnRjUj)LJx{|(Rj004NP{%`+4%_0Ec-m78X8UVbwS3|B107$y0 z4{iQECeXJ40Qp`x{ucl+yQh0@gDr4RzuW|Iw5FNALR|{S?&i z7YOu-oN#Zzm9V2DyF6<|1_XL6Ea8hkNh31UxsMIoVG&md&O&1fj+ zROgtet376N?c(v?A)7dY;_Ao94!ErBY1SS=wD=@M?s;6+ubU^EGQ3`R-nQo=-J&vZ z$i>UO6qbum)N%@hCgw+Feb9_-x1TaE7NIsD{P_|~LMe#aru9W#_p6uaZ*Um*BdDr4 zp{}OLdvhzwDdES|bLKRO==K<5*#-8U0+v=w4Y|^*WH%Pbd#nYY5=jLvx&2AR_Km@q z#Ct5_p^wWN@>`*nC;J;QG#d0r$c;QtsBi@gdsFKB&N+t5AH8`L!e!rVTHsV|Im{N}lc4(Kg zysYT+sWPlU)(x#-+&+))&bSI+7=Q6)Szk;P0p5r3d(xtbB=*&4^etxctQAk>ct3Dj zdKX)M>7i)Lizwm2(KPf&Q+1#o&UnTsH0t!KVs47Qj-U&TNNBV+>Y*W1dJ29-`Srn~ z9EaR{*kCBG%%B%XOfwC037HAcQ+#EF0Y-|TWzR?+17TAo1EwcEDJ&_zbOK(I%Y{yQ zsE>kbDZ=5ur(s#*E5jqgB*1V^JaX+sxo-C06fc&ZoMi;i9+8_Zr{d=et7Dl6@yM*M z;JR+Q;-Yom3d=vVrWW?e#G6g*YruZ;Je*l(#4;Sp?DI@0TUX9C9y0{d(j2BiikR?M z;z*$);p~s_er3Y)Ur4e>Y2FmSiWRG<*lOMrtX}bV4S3qqAUW~tFSttYKu~zjP_oM* znFEo<81dt51L7-Es%8oLAB75?8$47qCTu5f){9py`B9S25?iA_o|S((vA-HAWM+vY zzx26AeaC8ecE(EsFaJ5Q+nO?Q!W<_xP4+*X)Bn43bV9$Sh$#1nLI$8OD-+3#C0tX) z5(fIl=+m$_E#Ws|!=w;<*L#daWYF{(bU)YeW)v;3!iWLLJ2wpW4pE*{j8w_e zoIN4sgrB6}Wj5Fk$<_5i*eb@J1}t zqLy1u;QjR2JIr`YZLLT2cq>Ji)j1trwa{+&$uWKQ@O6>Ai(N4lr^R3y?T|o->h>!P zeK(7mXNpT(gS;zZ+IstaUPn(lSOs%0wgQnZ*Kj}Th^d%|c4P}9XSEY_2<9j;%L@9q z|15;os~bBHL;Xa-&|}xVR+?iPQWTjr=vwrg&Nj=;mR`UzUMF!!0=bfrCauvVBR@sE zZ_{~$^;RvixJO2q=K-c$?Dsu+r4}?LECY2~Bj2C)cp=?F2_~xbWCi4bZ8)u-g4r6% zF~bb4uQKMxTgC=Bi?X|K0_q|WwTc76) zk~Mn2`&o|6k}plD3h%*oMEMr2SMBf$-sWW{VQQ^3%+udf69*Kw_g@d=q!DF2RYj42bYc3ipmw>K^(?_N{=zzP`H8GlGC$-@}dJuF*zU{!N! zDo&4;ZteBfeX*6Exrmtxi-;~~YnipnrOSnm=(1YENqF;%beb1>FzbzyA%X$-(;u$f z*Pe6VGB0ePI$LC6`7BxSBR$FH&$@?>tJ{^@`U^K0D!X-O8}T~2D4wmFVeZP?cVC4s z^?hgUP-+XM^GY%@v5r*xNR5F9OcI5bOUvadtq-nXW~S5Oi)YfL^n8uORHL@$oe9Q~ z3}7U81l{}g`OS{S2;L5Sto&Fna^#ywh@rj{$1`Vyt@x7SG)E6=u$!Xe7;*@)F#K!6yRl^XZH zOw)&14K{`u-SpJ*@7#s~Np`8ly-NvS-{_WGrWb7QwIA&vK1wry_iqd{sq}k;>TR+A z3oPWu;dx@Yfw1*IW{kScG>nGWR&Yu6FNG3gX0D>rqd;AaeV z7D&m9k3JC-hO5_vlW^Zr(D#m>44%3b{BC3-mpK!5>1WmQQ>| zx%}J@`s_V3{BF7zs%i@Li_Q4sJV+-TbziNGsys>E6%O(BzCD1z@j)g94~Lx(cM}H4 z%9ZkrGoMM|u^jq>$T5%P%^pN@E-Cpr6dMWPtIU~cQtWm$S~Y~l+&@p;<|eNeh9Vt% zA0I3kZ57(k=B;=5p=Ea?$P8+tJ`1CM>?CIgWmC4)l*KwU_uHNn6lPabiE~>0q9huq zaJ}m0GJO4PqO8&j?_7L=BR3r)Q5izfP$-otKmRl@xZuOMVD+xfRhgOlCXOA+h8U)k z+-F@%UB_P*<^lMxD_$`TJowbk<&72bh{hO={hQ4}^Qv{uxZaoZ4E0l7qs^VkDi5=! zIj9}MFh60Vv;EVZC(4$TTGhwM)ac{6;UnFb--ykY+VS{26BFu%GnyNfI#&^Wvh9%}k{xl8!qk2>m=p?quySQuxGG zfF@wOE|UCf1tU1xInOgvq*2Ls?J)Jha z{=7A3Zd1*pjM_H5yd=jo%I>9ohiv#`Z@rvl`!6S28)oA@EfIR+`r_fe`+W}z>lwdi ztePqH8x@&*JX)vEXB)b@0`%85;RqvKwGb4rW*f0u%~m1Z#IH*phEm76p*iJWA=pEU z-+yW?6SeSt#!ema&f=#(C5&mkLM4H zid*-aHY*o*M83FA=ak#lKlr^7k&{wN9JFS*Kl@w!nf;3rJLJVp@dt9h{-icaMvrVq z#1O;4d@d;uQInvg;+vVqZk}6puf3(Z4QjNSEzHZSrVg@kj!((MC()>)bn`pxU`C`{ z&D^NZ*}ifb_nJUMr+;5tCT@Yd;GjEzqp{P$#L~v3jdRYHk}AaXZHo(y;My1UlmX&O*kTZ6u+8>8I^B0>u>jB zNN!3B$emDTtk9{7@v|}0r5!c@Yyy0H_#N(bddgOPu-A$LtvQZO8e!c;sC4b?6>e9Y zm#BuYK!&q!TREEhm9dRPMp2o&<{FfUv{7J38y_%8(2&m+;fwB$d1ja58WRWn;-k&z z!7bn-dZpka(JTCn0&VP~%zf=N!fk(J1ZPqi;@Aww7@z29rJ)5Y{457G#!R!#e$T9u zbAKL28;33{+xck_Gj$a-r*et+$dW{7jXF6kbG4MA;a~kAStV`~1f+IK!wCJEcwxH# zOuRG6%B*l=;5uv}+j_>mR4b!OgtuSpHFfhPo)EHXUw?KKUar`1>Ji2=?duH<6wJ+l z=1m$gtk;!e?%XQ}e3NwI`}_P}Uf(+p(T~=o3^ZR*6|%JsqC~6pWehShD#_5Q zzPLqfg^e~GY?w8z)Xi4Ov4$cpnJ8_C;MQ;3j?uC` zZ=y9rp&g=%(@#Pq2580ONWziKsNFs?L@;f>usjYZ^z+Sp%+xPlR?V=EL=Er6Jem_3 zX3?pUFdNhn45uLkBTRiEyZFeXoY1CQjfla3t9W)3Tu3daj@f>PD+&bo^g8$~y zZ+2Kxq_X$P;IA#k-O{|=6dJ9v*-QR_HxD~`xIfcPUW8;laBXDSEEuWD;rL@V&%HUdW2;nOQKRB@~(lM#ACYo zIQTXDKpM7|G{OU$={G1QwY^l6yW~XlDbstSZv)U)x0VIA{SL;SJlckBV^nztd30&J z^Y({`<$^AfInj`2&L;;brwQu=QR69O;Y^HP9gZ%9;xxJoa-OC4CO)55`?oZsl@yqZ z=z|vHcp8fUab!g@RzZi7lrq>cBhtaD&~Rq@6e^v10G-<0zr`2&!gi(g3Gh)?34V!0 zDn~3WI?rbWpr0AR7V|4jQsUE zUo65m{EkdnmRxz3YQA;?TvHCUMfwmo0DuISolOZu)-8%Ol{`f%f9gdS+=JZr!@)E} zy`)M2bz|4QG}stgHGe9UAxk63-jOuj@L>^qzy&tWRI6)xPBr}2IJsImjYXooEItcj zbrB&Ll@m^MjN15{wxNLP4Us4P#8;DA^^nth>(P zwPfKnr*i1Xnn$zIv-BA1lk9drU{19I>DpzjlS8@tu)z}Qb^Cz~2!DQp-R>TjTG^1C zJm}XTeqM*;(!Gg+OwHvY=ry%KB`+g*p!jXM^FH~>7-!v$f_vk3j3uGy+}j+Fsg`Qxwef4&4G-nZ9f)Y3EIsY>&{J-<5 z|93w1|IVlW-}%)4PtKOOjrxiXK^t|gH(!2c0-h!nyzYFhkvR?lq@O2d{igQTGH>VtT@`fOv5U| z)nmv?Cx*oV9%1js!X(&aDZMOOF??%(;_goPl{!Kh4J~*sI5Dw;q%m&ZQIFZ^VE>3e z)to&wvooR>s;TgJ1j4!6e&xl|)OblT$W>L<%=x7{KnzRTUN&FU);yR|* zXVI)sGb_SXfr~(CTZ(EMbEuaiA@{5qsX58Kniw^g;>i@k6L)orvRFEoVoYvD%0s4Z z70-|Jc5{=OgfgU#XfP50U%q_FfSsM4T@HB|kc7+dP&~YK@VLPo_XyqwzKy**w}J8_ zPhPs97;dt%@`3`LE^g3P)eo0Vt;wg9Hs3D3(2+iP;7Un$m-}0w{fVD{ z&O|9bt84b7T1ZTv`gMRbRfBH50J0_&EusWO6C-q1PE%HzlF9Ox8MG#K#Ksx(CKeT0PJ z6cpd-;zhM*Zc#BY&ez|N?!&;Ji#{DMelzsy)yeT?S}sh%JhsUaj}n1co*IXozjMO3 z6PHdxRGm5K+FP@OteLN3%oPc;N9Gn`Nc#G|i%Xx}1P_QmY~A>k&G9-Yj=ruyLS96Y zpYv*I9llx6Rke`4nViUVc5YUEt|%{1#PEP@sQn@04>3Fd9q+j*EqX-#OlGb$@TM z65A{2?=8gPNd7FuJ5rV9Nq=v$-XGAi-)4wLQ`_J#OJHFn8=(>=EoPR4h!Rv&XdKa< zl7{n&1Q1CHA&*jN~Cora8`|H7kelNIY=BqO-1Bh-oA7Q#u^&0e4*& z*&dd1f)o=t;s%~{@9TVp1O@k*U+Id6KZZcj)pE9}kzwJ*MBOULQqAQO000dQEeybo zkQ}p61VoVo-#>$;E@YYYo@LSmqQ$ugL`Rx&B-LR^h;7BV$nzGk(_=8~8sAbqMK)vk zCNTi}!zhp>gg(*@ZTNL~uX3(qV_nd@bNBWd9c;y7Qn(#%EphsXpPlE?UW&!W9_2$T zF)YHY(~3v}UW#gbz4#@ZAR)0s3t!!Cv{RXoLBfWrI=j0_(s^<5iMt5dOR#n9G4bRF zPYrWbNgHR}g)znUi=P`@nVO0v3(-4JlOM!!@}v{xvjG&y856^+!w@&eY&1km2UBa<}+H=Ppd2Vix zFF3ySoDU0&eR2Uspy(A361snMj(D=>ndq{TBDDZV5NkR*%lE4#l{f=gknv?fsE>qMqo+z_j_fzcJ89Nj54wANZnH#m7+7^v|Wk&s3+zW9pQyKb@&JH01 zcMo&kOerxZ?MVcaLUN>Fv5?*k=x|R0ZQz;b5nX(MpD&s5#KiH-?L!2UWFUqL5+8(@;kG_;Zxx zdX%IMha+pibebA!(-Ow3LAaFXZp5Sn>Z2PYCNh>KFyE%YexWnEuj5p7IsUVP*xYi z9u)cc!$@B*58ny}RVM_oWJ;qz8jDWI>Dc5Wm+U2;;9f-EV+H&M=*jktl z9u19e4lGvH%eCPoVhw9mK6Uqk4_Japg47!Q`@7m+UliWe9n z-|P+@?z`#b=C-Sav-lJ~kHNV3xu5J>orQP;9CQVg@*e%bTSgA%W8%X<5-3diq(G~$ z`Psj3Zq<&W`f5wfOY`ZIIk>M&RL>XQSfi3tq^AF>l)(=nIBF)Zl3uZ!UVrCi<=#`! zG}GBg_!6xYnxlpjnMB|kQ-zQ}hjw8Ww^Dj87l&LJ^jXHgNy7?WXDO)o(3I2o@PkLB zk4Y8%x^L>rq9(?NGBh>#w{5Q|s%d&_hISDM+HA$BdGgSt(iICiiuAf=d6)T(5y`a$ zlNnI^&_BGp?h>n88tq3LMBIhy$$kAUVRlm7!rD6;^Zav}^n!!>7dRpN?EHYWd~5Ck zJDooD^vw%5AzQrx`iTj;ymQVN=(mqGZ@|iu8>KF|&#!*VHlr>k(g;jrk5u5`O(-X` z&N`5+OID+XwJ}~WsWS0kW+SioI%uq`_1W=#^NVl)vvh##{5|GmBN~$Btqh*y4??%w zc&p|3y|@xR)b$#?(iiiY-P9E%9SbrGt?|XQ35kTUolJS9;uz_JT5%;+N+;=FH;`TmI59 zYfy5m7fPd7^fVutv&`AB-$-IYp2I4Ae!X~D$ z0)B3vk&_BN%^TI23zA~WOLJRT8HtIAqgd7tV`WPOjvh%{pZMt>G9BoK4Q}s}XN9lD z_NRXQM8HoftibBX<+|J*QKkkR_|^KacdV#wz~R+k%l#l|p5`4`d%!8LwI#>D*Jbed=wpDf*;J=! ze)XxNV=;Tevll4hOa3~3^6Xf`zYsbP9+xKvQf+(&!}pu z-}pi?uJR3!`oypUtE+pKwl~UI95DoaAbZ1!umi|HZHA)*)#~=6JofWwhCUEH^yd}f zwH>?RnV}s&^j`mX=(tOHc};VDO#}&iBV_wkH7-@rD`JhHm-8`C>THhmI}L64###zW zgMe*jp0VBx3>x^`>>TXIiav+Xo2;rscD^@+Y*N3nlGYvZ!yJ09oy82{ zCU|>S8FeCiuT;vq&wVLjF>_`gc8c1!KxFFbIn)ZY-?1O<6<{yJ#Ou7K=;bVRTF@m9 z4>x%$NKGaEfrIr^{37iY>6-X$j3TUC`uOX(%cucO%?I+eZ(+HgN1S9HaD5h~C6Uo2 zfSNKLBkbKo@U5OM+w)GOwpeez2xjBLn5!!G!*Uo8RXt*xMjDBs`!9*! zZU@4(x4n)G9TC#0f*%GGZ-)1e-JQ?Az7B4;)xBtAj$d>(m(lCda0cjz1f@iDYajAI z+3PIsk<`9zZg7|9Rt{`jhPFC30Uh-mj=}P%yh$WZ z(@PKU$`{Y)F=EFhKTa#j^e$+?G;>xxmcJ%O+I#%0K&Xb|xOq$Muq0M#e6YefC^oD~ z>!&)Bzy3}dWOeMlWBr~x((>N4uK}+n{g>aPaR(fYGOvv!E87(;Z)CoH;?Ygd&r^o@ zsY_tkoV*tVEkAn3%KdBubAePV3|=e?yE0^y&f*jTEu-3LwlL6Pmoif^-H znsYa~$ato=*sv&1uPJ+jv7$(}Wk2>270`tYy=H}s;RdmyvPMR*+PtQL;`aAL)}oPR z;Xj!`pF`n!c$RKZ;Gd)vC)u%l7rUNZ2#MdNKQX zerOZv$j7J}%_$mZmkrOgM8H5^pbJICyZxsbSk~ zHSIkUEoxI9O;!xJx{)JVv(Y#o3Q5&9azP&!KWs$W=^|Vge`U-p4bNxwGs~TYD{{4iHFaff+k83!!H(^35ss zrs(+hEA#|8f<(6RM30f?ZyS%ZDFnTgRJ1ZxJm<1j zcMfL4hHPnMS5{V&gx6Y08Y?3ji!DuWJ&vX=kA{hAF5s8L({Jb# ze}q%pbSqAQS9;rX^>}?O^g~C~Ah%b&yriO2U?!>hC$s2}`i{exR5iqTLy3u6M~jlD za-rM^N1xwFcDYdr1=76Al-C|mO=iZf4-hX6=&PPh&Z|N-vN01EIB7$?A;uOrEzcqI*V??QzycRo*ZL?}KbmV@Wo<$dt^iRoMc%GR1k_ajSO z26plI|=G$lq8xyv{4TMqwvHzD5+xm4N-{;@DBa5)6bGnCry1Y#NHhKnX_K^!C zM&YS_5pO}L9#RTslPiP*1GeNj4Rap~cBydi?m3bKXa9ph6=|&!hS0qPt2P%1e^`q4 z0VNg=`dGkbLD@M|AJ&FbL;#tF)ROlNF@l6W1D9Qda6{3^gmzxR8YSz@Y7`Nj%fe)x zv#@A0KRfXoC|ev%XmUQ3O>`Y94G9@Z8M!jOzU>=xX*bg&Y0JQmHQYbWTw0EOi-01D zhW*&0Y<#0A`4zml!TxapHqJ9;=c0Cc`?T!rpDGKP&zsVJ?hSLqMiwRI+IJ0%+VzRg zTauUBC{ZXICb_%&#mW}o#K(L^Evg%>-)vP0>H*>EGvf@)(72ge*&E#NEawN=I+H`qsb+ zyffAttLuN3;xHS3mg32YBT9N=kU=PCFODE`pJM>wu8>13M@k=y?iFfS980Uy#)C^h zP@KpiW8TCMQM=hi%&OIz=uHDoDMP9x3k6I%r=f=alZO~LhjdqKoxW?xZ}RHo6flOo zD6oLS!Z#90^#ZQf22K~p#{_aoj3m9%d?dvBCs23D`l8#<8>5MY1izS7BR}~Q)?k~! z?O`>f+GmU#&!%0TmPXK4a#z;>*x8gR*o`^+VH2U;h2fA;evuDH z*5{v|h1zw8)^b1+<3K`bh%wnBKh0Y=E>rB7!G1HwU7Zw0*r8!McJp~hj@=gM!?n;v zT~w%doCpgxMhQ%dBNNB@1Uj4NiE~+?Mx>*w>2ll7XIhF^%u9{MIK?rJQBRf{*##4% zP1x#FZsA}CkfZyKzAd_~+;T%&50V4acNfUceL4bWy)9~sxl>pCsm$m{_A$vB7G7k} z$kdZ?*_`EL?=z?Fpa$&O;!dkm9*AUa#OXPJB|j?^=JI}SpL*WMFcQG8qwtXYQ9XWA zXM?xihmx6>+0q52LLI+0$#dUbq%(Svji^aseczbx;p4lt?dW|x*Rg*JCtkzLe~1N(Cto3 z0qWYv0yJ7rLnI=wk;{TmYHD|X$DFr&zT7X*Ys?qt_EdZ zVHUmj#ivT#%nQ$QhI^-?d^>lbEhGdP)IFd2Aso7(n#daQ$*ij-7XoP?S9vsvQ_{IPQYgja(8LOXz&%-J>15b9Lfm0o zySyMK14f5nJvw|`LHSwbV)B?lB}ev{o>*}Z!7op=nq#sYO(BEt?RyG5Z8Y7dk||d~ z+L|*GnXI*3lNW<$KisD6u-eP}oBa!oSd7)n2NQ|-uD;yVJ!?zc44^5_HlcdkY7dPe zwXStE>P*|}|M0%mxIEc!W-V;``sSeR&6Jl*ntkkZ_;^E_0avLWrJ4t{18%iv{4>r{ z+h{phv)biz0R`{5JTko+M!%5$oZmog3#7!6LzZ-N+O@=~g40geZkZYW6!nz=Rfo5* zPjlSye^!j}tp8pyDn_e=D@N#cWA(SM3Y46*>cUyXY@-1VvXK$E9{Z1^6~jWs#SI`T z5}T+I5lS?Yx@q)i1lp1c=rtUh8O>sSoAS)54#>3*U#J~w{)*MUs89@8|q>P?2YKRcW ziENI$bd{oY)=Scyou(E7oY^GnsT3J7u?uNZWt~-OVo06wggr=qaoNcXAha~TDu6P! zvzp;Lc%<%jLDx(QBW%q@`onk1_O- zii%lRq#Fe@q^NTrK`q5A8(_*TIVIX_v1#gR)<$l8!{d3$2O};H=UGb6zAo`1VLP_9 z$-YrjW59o)^^G$TVYF1_(ps!urWJb5U#-*IG$6VB&e9`1^C>gG|7N8z#m{fhTA!)L zWVML>Gg2FSKdq2CJ(nJ?7c4QGdK-8+iSspXj&djN$)|$T`iN3}v^81Ho&kM$KrP=3 zupOG(Mov$Q=0@8~S6xY(%126uv{*l{n*(5zLp)_9vpNF8+D z-o`^!12!OS1kpUTLQti0)C9=4#cp;$4a3mk}S=XVEd1t6j7p@Ct@ z!HlSkF>(_y^qxqZ82l z*0i2xM~S!Syx#jsn6}&!v-Sn%Jg2xSEK!SlbnU%6`nu^ki&jJA5meX3oWmGH9;Xw3 zX34+Etl0UAo0nDL%hAXde;JhMf$z#Sl)_}f+814>LQllQQv7kzE;na&($mk6>dI{3 z);olXk25E7=-ag~PGE*qAMN$=zMxD<)*37tJzTq#@703@P^`IynO9DX^pS$E_3 z?T~_LnHX>^c=AVpK-x40&7X5+v^40m>(qTQonoUPxYTmt+jZeHer41j z=ZUzj9yiB^F&WCr(%uR)7~D|CTiSylMkJ=i0fCA{$e~QqIg-K`plYJ*R1vNZ5(g1E zO640V;p8?;I**>Z;8FP&xjD-Y9?+o8txHI%1ir`l_)~YfMb7MID3GrwQJL>$!O*fM z-!$-GM@GHxk+`EBI}{O;quZwu>p3e!R1j!ikVT?fY97&{fsKP>=_0?Uqc(^OQc`js zS`_rLwoqEDQB?_ngAU=!C5>u-VQFP>!BfHe8xOFV9oOoD*Q7D9w1U)~2N{INxb`YA zr3;li9lr6pr52UkOc~}n6yC9Ah>;`vG+_lp%+Fl(D+4W0Oo2$a4c^{_shw<1=TV0@ zT9bw}f3~dL$twTQt`Cct{`z{?OJq?3=*=lJ3M>44)MFga`2|wkY{nlbr;zt~t78eB zRyUdPoq?mw!7G-}V-`nnCX{a94Rhp2?gm2=+|UI;`@Z{p5icnF&zD1qx>=9zy@doP z^zW5b*9&lE1&)RvKV;185(JUhc0(LPO6#c*-@I;Q!-2EbBc%Hk5YF<@kkL)768vXo z!60FnRFaloMvse!8-zeZ+>cBs`#ONS&navEqGRO9C^z>LB{Q6icdySy=i!C_1b7;; z{@~?KlTH8*ir4bCI^53=Xl@ER6VQ){Khe8{MMK{WII4C(gn194PNc0!YU+rPAgFAr zK{y%@Gln;Kf^>FEOW&Oq; zAfAU*i*|Q9maiJhxmx2SKUohF@ms|sql)f3cIY_8_ceiF`$5~#akKJ*w%+_)ZE^bO zte!+JlbV|^|NP@SI315KZLMg_TCf%H1WX!Jt&c84v?nLNYs7A^^iU3;((20C!oBi^ z&1(*2wt34Z={wo<+K68Di9dqK>{GWgo z{qcg=_c4EYwI4Rr@~q*-#*Y}YOhscgUf9_(ia_JiHB+sgtzKG*UdhEIc$lDCmv0yt zIW-QXX*Y=e7;lhav;$s7X}Do5-IfwvjyI6-JTF`9zQJfF>9&`uF|?E|$xHA*4nuri zre~f)OO_e7RRs?~dw$W4!pJbcSl{1ccjRdgR5x8>cQo!%bj5Ce4AadW-ft@1bJ2Z3 zPn{@P3Vq>&_tNd{>Hs0^EZLACcgj2i)8Q>|60Ax8AmT`5+EH-bevdPx;M2cV%S@&mr$osB?O%3)3ffl zG!!lo%AzNQXK2Aa4PxbC=n0O*h?$ZOQSq&LtB)S~gGSj;0(Ud2(t&o$q>s?-d6Rsb z0H;9LNbj|~yCs-qIqeU>jF#)w{C;$>+l`0>@geC?hV8 zwKmaL=Os?eaoCi&kL(3;b#lW4vE#mP!!b1cDi#g9z?BjHZ22?o<`qKwD9bgxK5T6n z_AD{m>p~jFh&&ec)O3xD7jE?#47Mm&KA&q1+np6*aW|fKz6y@tj5BL~7uWFg=CqOB zeq5j`ZB`aa>=IvmJM>P1S(Tig$&gR-ny3qNpB1@ZnFN!USZjB65fAS58Dpeba|I4w zZda`G%J6P|VJB>7e_~)YQU4~hbk8I7iVRPNS$e$!d^&D%IzMlrP^WR0)epxg{=GT_ z$3ZIX{jw0l=R?{(Nns*wSsBv?CKHh2ZF{F*gM2g4z7O%6S`vnzXF3ETrXs^@8$58N zlb5aNB_ktx2TNR0hUD!>;>_loO^|H;Jtr6OCW!rh$wG0cAvagADuj-+;w^KAqZ&fL zYN9hBF7u5BUY&^__)$C4usPRrn>zJq9(EL;aU>lyE1Hg2G^};zX!{p$7fevHUmj_T zdHv*pjzu($WoKHwAXagdV_u(S_xFy(cOfwD4l6U$-mz55aX%wsZM?-2c7=M-I!_=` zwsv*6p3Tc!3>bg&oYQ+q5E>AJ(3l7f>Wh^$C|)L?O;Y#{7EPoVsg6k3d8^8 z9p?AaYN4mIn&-0&^31E`Dx(O?ILHq=>V$~`p*&OToj>&&y;s(GDRc;)L^Jx#DGXiO z>5H1Ei%R9fe|=<@{Mk9S{gs^!nyj59{Tbe*gkX7_N9xu%Y9oMs<+#6 zF+&lyLXo}NnH>-0JzA}>$oRP9nb+!J`REF5u&qP>{l~z=mLEOGm^d>+#=4t+y%iQc z{UXP7UaWjli;4=q*3z5~D%RVl%PlDR9C=XRx$~55EU4v`n!Mb%(L;P5gW|W}+_hr` zzYcE{pjour>nWxn_}6r8or-_^+`D}>G+P0|Rjep3_LNY73O-hh-fJm!kN}n})IBm8W-QkLXAlm=u-ACPao%H7&Z_ zuzp{2zgbmCLTg^s#n|fiOcAhREMWsL1F!Etj;oE)IaS)b*T$bSO^FAyrw<)0==<3mu7~g1^@)(;S6q(~BGr7dV z^9ZpKc0Ae0{>dub%iW8CeY9!SsG8bf9O;<;v~ zo3uJkANZp|HYHR`THH2^Cb|RGA1xH^8kM%`LRb2V_SMv(<|eXIqw?P&7aDqFnl(`>ruo~ z+jUB9)0Mx^+0^$x2z_vKy?_RZ=o56ei%7HHTLJ8o$T=Cv*$v}W8U631Y@ozkL$9Yg$`9}(pHuH_ z+VzQkReX(F?d6yCEy7=a+{PMx_Ozq`p@@Ee0CMCO8JZ5~9E%d&;&F_#C<<<)@yy<)|4D)pe_oLJOPP{~nt>0=%+mH0o(9jT0T~aXc z6{B{36#2j^s`oRUH@E}t|5$jy=KooEd;@>lhj;g4jkP68Ly;lwz6hVyk|!IxDDprF zGkXp^zDN)fp7|waN4n=jUz8AWv#CV6CmMJK3|WDR8c{>JS{`otmU9xiyVFH016twr!er1pc$&yIak zp@|f8T;#00jRe1->LX^9Cj+Afpr%d4}8?gNU+PkZuxPotC^n(rVF2PB#po4305AN>n8f0(_ z?h-s$a0u>Ba0%}2u0b#VbIvz)>#O^CAJ4qZuX<0_mfE$ad+lDUSu6yr{E%#;6h^k- z3!@$rCqSL>wlOiYeq|X|dksm?smkiB@A=Hm2^na0JiO{pr*qG?@PTP=ikt4U14j;D z$iYqQB!{TC-jxwBpxagwX%?rr_Y;}uyRjUl9_RQl;gWeZ{)M%`+NU!T z$@S(l4ziRSxf&mw2*$N+xuUAbaO@STU{O^yX$!_p3$_Z?ZTf%h-tVx!W$=8{>KZ5r z<%u3Wcw2bBJ3K3*geLLw2_qOo>^T8kr2$!yeQO8W5lSe@+7+3xu@)L?(T6eAdqHrbN=MK@#Fd>`}*Y>!B6GSYp6&f z`3Wmhx$6Fp(hMdU*4?=gFYt@U=Jg?9<5!cpTxOx|@s0PfbZzsA<2CER!ew+BUh&R8 zcUl(;!88BBvcc`wn2^FtDMmjjG{lNKMnAq^eO%%7`l6J%JBHh6lA*h!HK)g)mBisF z{Cl&})ZjrMJlR=-LsN<|rDI~5hMlQ`=QeSHUw2u&GPrM>%k028GcG#%V4A^}v{PgObW?T(L*zl$Z+He^Kp zxSL5{OjMb2=fswRuew!;g{>P%;$syz!bC+(o8gg)EI&MRpw~@{u)0f z|4whTq7RR30D9P1n7}Yb|M0nh0BcufwTh-Cq6@HW~p-D3b) z6#YdcB`q>RcXlV2_eP)>`(Zw1liI-(wJbjefy~9LHJ=#8?j!A7s)=dqW znjYXk_LFLX%YPRRIWB`T_uCBp_3_%tGoPIv`W#6+(I!boSDKw$-ptj7_(UJ|{E>f- zisQM>bn1>dc;qEVLPB}0=j1d~T_=UN4l7wgA!bi@)RR z>xkvky;6%>jpV#R)9rz+`L~Sr@=2>KA+8_{j2k}^rE`xPvF*sCOx91(2!oZA7*=Td zRjPpBUHdw!&pZy>V~!rp@vK~cKHSsNa!Wr}#Se0!NRKeDwbFQBj>ZB1uigRd)PMI5 zl9R3ERNsR&Z}+Q>qb%&&l?mH+M=)-p5c(sw_+_F!}%}Xrne3KT{xQ*L!dT4sa#rXyq0tjpcp}9FYspDIegs zNkkc#T=p3Bu-k}{#yBvjJz0N!);r8xTJrHVtu!$)t?>R)N6HYVu3jIA9~_y? z6S4PW2bTT{L|u6Z_PZ*}m_4Q6=z%36 zF2mQM3_fqbV{VYEmkf4BII;N*p+-r_Z zA!owHo2m0~bOb9KT(=xFiUCzN+rsXWy?MmpICQ#*cOO^t z)SXJI5X!Mv4tqhVg&y)V)b!dh!hKMC368Z~=F{uv8VH2(FZj(XoBJG-%3dq3MN_bZ zQ$j75>zi|(1-|SOet&WXSIKIn+0`jT1)RVy5UgLD^pV<-92m*Zm&;oy#Pq{S{!vsU zFD&0L*N7`#V8ee)nyZUM)!3Rmx8G01B04M@UXa#A*eOQ!e z`C=S-mBto5@#yXDnPD`A%@Ws8j3Faj%|1y|3MfoU!*~S!k#P(${gs;BpY$G#O(rI{ zJ~0`*2w|lem1_K2!brH8eC#pYsm!%nV_S{s4rFUN4IMtyQWv9Rtv{pW!vsO;59|zh z?Koxx;EO+ULKiFwfG#CvyEct2Y7%%B(XgQz;npTeI~5$XcwO-|?m=220>m;L>fRm?9Xw;b|j6r4}F!Q(fXYenulo57(sZp@zn3J z*~$(-cLyVEz|WM~@&wPvQh{MkBQN)SyKxjgSfWSQM_klTt9p+$2F$~ezj&AL@#dmQ zO$DL+Lo%&fT;&apU)xG}s9WraQ>Rm_>3gVsaxEWE=%%oJFInTUzVe`~bX4g!`|0e^ zX)vQdaWnr=?` zExf37{fEL?o0OE<@l;mP(^#Ui;b<<4&x~pYF&~xx-<~Q`lf~Si1Ub&593K*zPXoaI zqaJd8F*pRM@C1|~D)%OK7TEbE@6&lcAclCn3sbA9B~Sc3$END>xuRJ@vfo`+dKObvKb$S*IXmacen^oV;#IU8ZQxUu49B2$@nVy5O&>+4a_SaeI zWwV15dX(ru7J?F2S>sZA&G<$xi+WyqN>Fb4SLBWf5+*46vP|8qRhSp1Y@yt)6AK<< z^)j;9nBbQ}33R~rxq@N~xNvKsjVEuhpT|axabN=r01P{2;kJblQ}QPy>JjDWs(mGN zx)127cGJtaS|ZbPnnkrMT%IdtaBGorjOeiU159)%y?zl(Gned^wNd429aRLko0OML zL_tx&o0pKnN~M@;Q6VTt$rSEj8y76>6yw1iQvU8BXIV4&f${Y-SR11%2@&uqN~o3D zzhkl~rSQ-rp`D~yL1BI52jZP!_r^>t~EZdnbg(NA9RZCCvfhce(v;e#}Bhq z?LMTFruf<#b1G|LD~LwUMK)4J#90u$=BJ{z z8}j{!EUaS$U`6a0>tnA@_Gb)gCmw+I`a}Ons)a4Tc(;);{TK_e#*qe{ZqJL*ygy(p z?3#^qjsQUJ70Zgs?m9b+OL#O{Ep-7TNB3mzvUqUZV-$T$1OG_KLz_DCPc?r%qk_t% zQ)PdHv!NrTi&^6g4K2aEAyoFB(l^80Bj8sV3g6bgT+zp_; zG>t;Z%*)Fg0DnYK-m@LO4H>9^6fwzqTKWVd!;iMvZtc-o)0~|scIjOp;XuOR4UO$I*D$}*L@;W`RcFd4P@s%?mxot4bd^%o7 zxB#7XOjAPgpYNGPcE0SQiwx7yg!oz+T2jQBANF64MsPG*>|$0eV=_Yivt3(qyW8F< zTF%>gHf z4)-V*CTRF0Y_4SF7<6Knf#hS7IJ8*CuEs|*$Q+kbn2O4;iFT9LZx8d+KVa5!{W$zF zgmeC&B!lsfbteix)<{Pnmk1N4lNE+ES^8p#VDuqFYf9Q82ViW#K~eT{WYt}6HF>@NU2Xy`p}W&uqAtdm#RK0h_L1`mR<;Lg0U zpAoxUX$^>a0jT2;dYeIA6=!%e6dvsG$EA(Y7dn^8?NBSk^_WE%iecvWEr`tgl@ANz zLuPYx=iPqWofE>s8+_dSpve4xzl8qZK;r)f68|@l_`iX~{|zMmZy@pi_dw!*s<~o- z;s0x*lc)YzikB_!Jnldz-}Qh4tDpW_@4$jTzHJvL0Xzx$-+Hal3}7P8Pg)tJ1m)?H ziX;Tge9#Rd5?oSe0v}BP7jl(?ip}i@2AQ~ zQ*qDY!mY9US1K4Q8m8~Ybv{2b(?K4qHZJ)t)7WY(G_Q}-cDhY|_-BI5E#F=YQ5*-f zHp8POzPPhxXRtsMmLkG7txZRGG?3it+S^tI58jK&){neN!8FV2Dv`$ilUs~xbFxt% zjjWZBw%pjr3LD>CnN>%~2PlCtxYNF15D=uri!0$w?>NzEHaJqUHDiKVqHg&*P)Pax z{$-5qfoos=86F%^Xc>Js2d>1~ulDR8W_9b3=&D*GKf`~$?nB8(nn%I-5g)~<2uLT6 zGlTOX7{QnC=^-;ydCRbqgaHe=m)8Efo;3rgxaMDw3;K2sB+p#Um{);)>ytLl&-p^` z@8+Gu0n%&~^pW55>HoxOB~zEa@H=19IwmfoXAQ<&U7I?NU1{y*2SzQXe|6AD1fUa2 zX|;8CLzRIWjT_|IA{M-Nu!hU3Fw-_NkOrtXLwK4spROrw^?2aDbtg6o8u2#JtME(? zN1ejI*BpJMQ~zPzSF8r+kCpDqFc@tRm)^2YE_9LC4#qLfG|+t(I~n@Pt!s7E74}vV z6hRyhN(WVZ>%hpTO?c2qpw1+mnxp+mGq^Q~tx|KiJ#%nyMaejXp$Y39qc34UpcwUG zw{PS-vPt8aP(5K6g9MzjtgdKNZy~dQ3N5{2^=_9Hf*g4+)30FgAJfs+r9h+fpM-g@ z!34-DqXY#S(fPFD3vLgTH~?lQPm!H}DZk`;{pZcKSbU9J;tU(NoK4{ESKM7nay9(B zaA+_$!=oIImTUec@|HhtP_M112Zn^J5zU0{`lQ+X^e(F+Vbq!ly4b-9roVEe1dNLTUS8&ClxS{eHRmh%m{(SrTb+ zq+`|QYTXcxXq#RG%*`ctaK#efTya0viO!FZl@&&WhsNY+HjinbiX148gVOWh6;S;w zgIbUNnSCl@f=pApszWiq$CGsS=rJCC*69(^5$RJnj zu%*ke)Z+6k1gJK1jE+s^9!_XG$KQ@mZUx}R*=67*pcjD6^p|V3pqrH{3l<)qDkn*p%Z$2CN8ESqkFZIY zMioXk!3<>t`49o=*C?CMSx4}CEGQS$t+6@wH_%--U_>h5y0RR)1Uk*K_F`1lpo7VM z1m{UbJG>S}&=QNZ!@zRl;766gsU=_)NxTPfYuDbb#^1jje*|9qmMFETJ~Yj)$uio} zBpwjnM49!MJ|@eBztm@`BK``0MN?J6;w`FE#-8ND5S~p3YMBw?mQ=Z;2KQcdbgKUq zC-6_r0W;<9Bt>l`O*UCKdrMJDeGCXTq>WPK7Wq_IE~74m)C`p}P9Qn^ypxmq@Gbei zRBqMZy;8Q!-PgULxV|pOfC!D>AOk*dWC?GE3LZm@wA_$3STUTK92?UylJzd}upmAi zD-7)(Ajqw_yp1kXM%of{uG%q$iz3chvFf)%4Bqk=7hg={qrt}fkRRY>9QY8VOLBl5 zy19?!sD#@z6m0(6QiOgFr)cWBCClL3OTgsEWR4;K%FLXqZ}+BpGc~tl>Toy!p-iCw z8~*4ijSxhILccdhs#n#iU^~f-nu=PuFS7u(fTF ze=5`QTO@&is_9m68RA)KNvkoZcWOzL{xz{j_@-%)eDu=J5Ed{f>FWS1;Ng z&>=}czSwj^*YD6~Uc+YqwpS0>O}0RmF9_`q*ql1`w!bM5-S2to314~R3a1w-di2SXk%9F37?8v747joDO{bX@~HwfG4x$C2|R?}8fLX(7(nRE2+ z@RV`NT+S$Nm3#r>+xe+M_Guk7C(J~G;QOeP6%04}pYWll{%oqAEr|y1AlO6jZlqQJ zoVT?h2pb1`o(!>Hn!H5SCpfhTO)VF$b5dlDK0vz^x?42fa~CQPS_GOjE>KKKREdE^ z7d{&Uhdv#|T9ddi{0Y&0j@Y5?IBWI2jzhEO&nf!MKc-IabIK(x?kwFV&V}yBPqbbg zz#!yBp)TaQjJt7LYG*qMwUHSSP`i)BeAW1`qeH8QBdeimR774&qEHUCmk8vXk=xs5 zn5O~kKLLLE>5TENNM*X+jL9tO=hZEqHR_Bwsua69c60_jXc~enU3B5pxVwX05$*8k zVs|9IGD?}8E1v_5gnOaS>xx8G!z!5$z+)ShL>d<3P4lmAc>zhE9GcHYm;>8C`x6dP z^re6J_q?!e;4O&fl;QaD@$VR*#OHz+GYlQwxD@HS({Gg#_nfIknba3}_WBjDMv6qi zgc2Qn8||~p6J1ENP{LnZn#879{0Wsxl(F-l`}JO7Azx_HQ*rLIl)p-DQSiglB>3Q< zdvm{|q{b0*RARDl{U-1B>5H*aUx!g;huhNY{qAnFJe?3boC0lEdH%DZBht9&Y8L}OqnEX`6%V(ecYuWe~mTOZzIvkSA`ABn3&v>y=m0s)bn-dft z7cBbE{@f(TW9B5A+}x-PqlG!5x=5Ji$WVR*wNoJ?EquEv!^y?|>-FPZ7h%{uCHN=Wwl~4~3FZ!8xnbt|2H_q{<9ntR?XiMe=r+&o z=q`4Kh3q306;g79038R6w@JX(^Ooi^p(6$UpZ&NHx1agH!*O|sJkDF}kF^m3@@e&f zmKE?DOY%2sq|`f0P(S647QrZI!`jHXbr(e5m;h%I_%4{sIUpG{-PDY9Rf;u?VsMFe zXuSFj!t~`TfPV8TLyC?MdTu;hoQz0hZ2!wVE3$YnMyAvvv~ZVpyQZ8+KV?(&0H>}; zib~m(uBI?G)`2&WwJ_R$D~LINWR_t*tQAd;oGW_nkn`)03*EpZ5EvQmgqSNXbn0&9 z3DeUI{wOrSn&>aRnr_nqa5CwtF(l->q;n2;oGl+{mR_Mo%EheTTSP>^zB|JJU6}So zYgl%kYqi494)AeQm9y-Z+cD9d5HkhMnmV~W`$28p6M0+`Z3L~d2FqwDa1^)~AVfdx z;EuLad?nfna`8j#0pq>-pKW7%)9E$8-_3IdLO=ubXM*&~r_q*r*6V}9=d`P}>ozMOYyDysi{52*csff<|d&6$kr z4P>F2aykaH4uh})<^SurgZ_BW!r|?7B`@HU;4k9y_X(e)7hs*`O*zk}H8;=TWDjOd z^Il$q#H*(d7Cnu*l0hN1Oo?RAH&CnG-syX*&fy~$tnwp;hZzqDW#>!_na8`cy!@nW z*gy_cKG@NL?V8I~Nwj{mv7a5DFoPu?u2n@?eUk8)mk5n-YzB?;$ANH(6FrX&ulUc< zH+~Q4lzrFf9bj7!*i*OLcCtw&zu9Ob166k!N>4mOTxkaJ<`qRo%*@WdSxdjwLdWrn z+Q){-I#??BZ-Q`YYA4DX%KfT6H_3O&tg}~J{<-Do6q#JN{_1GnXlK+iRio|k_RoW; zZZLam!Sf2eY>IGE>SrjzJ@8ViIUZl$sQFo;a*je@X^p5k!a?1fc`Z==E*EQjERE1` zotq#1?zTzuOuR7ipE~&BFI-k)X)&Nwg&)5!`6K=f&}MiZ@N-`%3SOs$+X-0h(l;b| zAaER-cnZKYM6bp^fHL-%fq%hg>@;xSQi_v*Pncr^1OI2VH=Ckkt2zi3`j*bKe==s% z#=U_Ys-2e9gwcqBgk?pcWGStzhA30<5tY)g8csTCE4b*V8jbcBWe$1Odga8F$Sd_O z=UG~R#59~B#I!&PjP>fv)mEGH{S(}dvat1bE(+|E^FaM2V|L4S{gIl?4CgA zrd1?r8N+nmo=uj=766BIqeJ*~b$3lkUk3>&vB=Tdn5iz9!4 zB_-nOB*6Gfia%uz@h**^r|Cvw!J7;a90nx%G?!<9a|3YWgx zFg-YO>IM1OxO(3?odg_y>~w4g7Wu?ntU^?y&44naBv^$mO09 zcbdPbJAfR>Jw+F!*EoPMD@Gm^cmQDhjy3)nO^r+5NnlTvdR|O~=6Ww_6b!|MZ~npG zWrpDomRu!eVS0v2irDSs39!U>g6{8I2suz#4zb$R9@7aRssO)D8Js*VPs>KNQro5l zPp%pnRQ4~4hyaOZ+KaRwwnVReRX8K?XF7ri?JQkD_viO>d`vSZ_@$E1B!Ym?hNemB zNO{aIj9`-)CCRc}W|LvL1$iHr@ z^p=!3tvY4fh!ZVeM3?-n*1ij*LWbgDpmTR|h4NEKRTID^NeJpTK7goqr8}@VXW` zJj9YU>K&o>0Tb!$*wST+fiIiKr;VYpdd*XA2ii|#vCFM3%kc2<(a5Px9w6UMaB&6K z+yWm7S=rj)vmpy-&%rlkcf z4k^JE{I`~tZ{z4O58yYKc4lSok(>t$@+73$*AuRI`PtUF)!EpoB0Hf9N4m6AV7}%xWvz7wQ_3c6!J$p{XiDcMf>tMRF$Zg*Lp|et|w!|cGv6uu~Va} z+PRPQ1Roep_l&f2$BB3P$)q_AB^gt6vC~GEs<#cpfcV z;LU3y#jf?v7^pZ3Fpf`Adb?n39MuJK&Ai5UnVSC1`AW-C(sR2v6W#wRoGTf>LnmRm z+0})y$)fGVT)I~Cv{kwnQ#q1ll0#y}?Y6ag4_TQ(tI|!Qf(FqcT5iue{9iJDZe>ZyE z#KI+q5fQ!qGzLly1qSkLuj{o+g!I$JknjXc(W0%g#Df#J{TZzYV%MhgHx=sg@{W4C8hH8x7mC%Um?_f4$4vbS7$N64F)q2y*f`9LXs z>FoP?+&B+Db&70YreRXX?!~&#md8zSdh_V(jew|l-;tCtNweLuxHJ@EdG^Ugp76*> zBt|;sAn*vy+d~JOq8h{E47RXnufA@lA8tVbMR1SOj?jj<0ho-p^;^8u&nNYYj4WjT z)iP09vm{B$?bt%)Z)5c~n>m1$F#@>#lu1&p;Om_~vZ;ZcM8w~DpoT>BEKMbh?#M)G z3i$2Lv>NU8)RdH_Y>2t+U4<15465AS+&)-ZTZ4I_$vEv$(~7-^KG=i*eth)IRtxF&J?+xn+}-2sKFg)U z5eOanJSMc;emJvW=^|8_`A=1ME-KTw;8i8IJFL(abGRznv=AT=9 zS)1L@_>Hwb-k{$E=F@h~DXHOtK0^x#>~C&#`+n2$Zj}qah_>Q8&Mxz*tWnGuq`p|P zsb?LDCyN)m)Dl;c#b?&1oM?F@f@%-y?gslEkdXic*r7F&^#0)I{~h2!2=2vHG{v1h zG~&Kf`R?}M$lmSx5);2vBDGhP%wXfqECaYEo(7pA3SPpx9juy}naz!Ht>^1=n0!nt zf+|%-QtlOv`(o(WB+G(2)0OQ(f|P`vcVdDN0-F5G^0rv20`3Zc5jy&_rVkChC;^st z={=g|2)jb~J3C94S6#jxG~N?}oMmG^_A%a(U>YGs2GuE6u6H9h(BdRKMJ%0}WaSUh zu2>pfEwnW)EM^4(kj44w{=A^``CCGGpt7oxQg^>hTe#-Q>E&Pw^87?+z`-MeE46~C zhX?fIV*-gTIjk6EAZ<%%%TS<5mo9ivH=(7pK>acISQp+}EJ(+pJvy9H8jc~vb61>3 z+LoAvBsgyqirc%AIFw~4#R}?+Vvq1Yo}6Ipn;(NczV}r=mpp%=RwpUa<)AU8_)EAF zaN)WlIy&@kNohvvY6u#7YI zye@lD<5vULI{vyH%@h<8Jv1WR2L~&yJy%q5-mGlpyi3c=u0DH;U!Y3{20WJ?5~xSW z|Ku}pGY78(2K!(^84iAj9XsmT?J0|r#8TAwK!JG>5D3dgSk@1c|CFU5s)_t$bvdrE z=F8bg>dAr?hmYF`>RtHx`1k}CPU<&Ro4pR<@D~})UAX(m%SZAVXR~>n6J-LMEb8+S zIMpI42CIk|sD}8Z?Xx`}o*lueo%F>(!znY^+Kv?z1yC0UB()42F9RdJ{lEGHX8=5g zZ$vIg?d|Q8-%bb$p;vi7LJeYdNV~clS2dFV45_6UC4?#N>X@(LGVKN*9!ND=5QE7O z@xLf3VMay$gugX<8e~OO)zJ7Ka=wOmj!HReR(%d74Cq~aj>&XpPJwv@-fghxRWo)x>4**{ES%^BBLd(%+ z0|sN?GEiahUFH(_V3B|Y0`XGV$wOaeT|7aTr*rSCrFK^Y6nv<-`7 z*0*J$lge$WeXKSj$c!biagtOKK-J7Pf_3~}bkn0C)qDY_Y=Xh-J`-qlJt1&Y zQ&ZF1rrdBJkn>VeQOU4VteLhVA5msP)r3BYIt~Lz2xN?eaHN+5LA0;mK(yM5sWZS+1;?D>B<|bAMlma*AfjCt-ak^ z?e=bjaAGhcaxn)lnQ%NT{!@H$8`P#Y0-J`qQc6qKXN54Kju?AQl{X` zf}HC|&e_i24KcXb8Km4g+k_*yzZEAb?BC8rQUve!DQLq1KM9GmdQ3Ug|p z@~OA`H_T8#fDg(Z$M2eBSx8#@f0mVrP)uBNrU1h({&&3ZG}*>d#e(F$SdhRz^(SdN zpP5!<2Z#3k z<#zarZd_D0Z~srng^xI9`$iX0X#qlcU@u$oe#`c1_!7 zMc+zC%)GW3QR74vi2>l|w99|{gZ;Po>mT$G9H@2FvH&i^#nrRD{8~1FZ;znIHn7)0 zokanyOu{#oaJwnWe0*kQ0+gekO-(-nnXoZ`|MSRSWy!A$8d72f1jL-wAprpgNx1Re zX&&dwn(F3A3w(?~v>wo48tcfltjzChWc=#c**y7dIm-Cl*49iZ>OiZEl8_K?^@^?8 z*|HsY=!`vgW`0;?p(THy_jenc3UC_#b&A=hW+R%v!XkXPA&WGRf_l&5N>t&mK8KYq z1N|7F9UiSH=OkLPmLFKHa=vVM^t~(<`PFrzF;nVyoE`4wk8S$8^6xRU4taZpnCgE% ziA$T`DF~~D;~$K+w))!=qKi$19Jl<1 z9Ht@{QEgQP3+;P$;-^G2uA^fWN(VlJNa>IJhpv9FJdb@5H^cM~vhV2);Z@*(lY34@ zgfibc^XNJuaOKU*C49{7F&Hy6e%O!P+`@t?-AK-oXmPm#6MTmvNgcR+&V^O|uN~zX zg=vmN}HIzAMkSqq1p zZkPQ6T`zH92?%iSQc;Bf3oDNiD5m?_<-Rr8%j+8s7f42-!pf~R=O_O@c|prL_wy1B zB3f)jZ!Zc}va<^^&jIt0`J9H>4xPckSC3`%S7dUHd48P;lxRv?gDI&lvwZbo@cYMR z&KO$bO6TffQke18+3<&g)G6wt{9LV>*xmV{&qLgEAoQ`5t0keINy)ETLmZs6|#PQ}m1T?;U=^ znZb1LbQ`we;j5ENlaWCDirk;~{$+@Gp&PjXGAab@?DbF%J4cdmhPDuR0s%xprEZol zCTZjw9J$ow?)cfzdcw@69kcX?0C!;&hpoPV*G{WTgKh)1{On9#ffvL7Osi{r&(GDu z1TSFx=V1r{zyJ;)dVmN4^Z#rmfQS|%Ziu8H(uBwoB2S3IAxisif!}vr0%>f5Xb7SO zhz=lnfCvE#a)1!gLc|S`6hxX3S-$JP7Q2Q4ctRS(AxeX&1fnL0h9Fvi=m4Szh!C(L z2M7@@MBHEqr6AIT$Pyw?h{7RCgQx_eCWwY0T7c*PqKE$x7zTjwKPz;@00 zDTp*7vV_PJqHu`PAS!{V38JC@=s(vV2Cx8WJb>r{A_QE>C4`6;B5sJJAku`$5+YBC z!XZk-{h!6o-)}-lV-rL}5G_D-0MP?P2zZbKgoqX*ZitwiU7St+`=@~aEZYv_0}J#1 G_5T2_8e - + @@ -166,6 +166,12 @@ + + + + + + diff --git a/lmsreport.lpi b/lmsreport.lpi index 8bd8e2c..8da44ac 100644 --- a/lmsreport.lpi +++ b/lmsreport.lpi @@ -55,6 +55,12 @@ + + + + + + diff --git a/maintcpserver.lfm b/maintcpserver.lfm index 031ca8b..ab24c7f 100644 --- a/maintcpserver.lfm +++ b/maintcpserver.lfm @@ -1,5 +1,5 @@ object CGIServerGUI: TCGIServerGUI - Left = 401 + Left = 602 Height = 566 Top = 219 Width = 870 @@ -8,7 +8,7 @@ object CGIServerGUI: TCGIServerGUI ClientWidth = 870 OnCreate = FormCreate OnDestroy = FormDestroy - LCLVersion = '2.2.2.0' + LCLVersion = '3.6.0.0' object Panel1: TPanel Left = 0 Height = 50 @@ -25,8 +25,8 @@ object CGIServerGUI: TCGIServerGUI Top = 14 Width = 75 Caption = 'Запрос' - OnClick = SendButtonClick TabOrder = 0 + OnClick = SendButtonClick end object StartButton: TButton Left = 8 @@ -34,8 +34,8 @@ object CGIServerGUI: TCGIServerGUI Top = 14 Width = 75 Caption = 'Запуск' - OnClick = StartButtonClick TabOrder = 1 + OnClick = StartButtonClick end end object GroupBox1: TGroupBox @@ -45,14 +45,14 @@ object CGIServerGUI: TCGIServerGUI Width = 368 Align = alLeft Caption = 'Запрос' - ClientHeight = 227 - ClientWidth = 366 + ClientHeight = 226 + ClientWidth = 364 TabOrder = 1 object Keys: TMemo Left = 0 - Height = 197 - Top = 30 - Width = 366 + Height = 203 + Top = 23 + Width = 364 Align = alClient Lines.Strings = ( 'user=nnz' @@ -62,11 +62,11 @@ object CGIServerGUI: TCGIServerGUI end object edtRequest: TComboBox Left = 0 - Height = 30 + Height = 23 Top = 0 - Width = 366 + Width = 364 Align = alTop - ItemHeight = 0 + ItemHeight = 15 ItemIndex = 3 Items.Strings = ( 'version' @@ -91,42 +91,41 @@ object CGIServerGUI: TCGIServerGUI Width = 497 Align = alClient Caption = 'Ответ' - ClientHeight = 227 - ClientWidth = 495 + ClientHeight = 226 + ClientWidth = 493 TabOrder = 2 object edtAnswer: TEdit Left = 0 - Height = 30 + Height = 23 Top = 25 - Width = 495 + Width = 493 Align = alTop - OnDblClick = edtAnswerDblClick TabOrder = 0 + OnDblClick = edtAnswerDblClick end object retValues: TMemo Left = 0 - Height = 92 - Top = 85 - Width = 495 + Height = 105 + Top = 71 + Width = 493 Align = alClient TabOrder = 1 end object intValues: TListBox Left = 0 Height = 50 - Top = 177 - Width = 495 + Top = 176 + Width = 493 Align = alBottom Columns = 4 ItemHeight = 0 TabOrder = 2 - TopIndex = -1 end object edtQValue: TEdit Left = 0 - Height = 30 - Top = 55 - Width = 495 + Height = 23 + Top = 48 + Width = 493 Align = alTop TabOrder = 3 end @@ -134,7 +133,7 @@ object CGIServerGUI: TCGIServerGUI Left = 0 Height = 25 Top = 0 - Width = 495 + Width = 493 Align = alTop TabOrder = 4 end @@ -152,17 +151,17 @@ object CGIServerGUI: TCGIServerGUI Width = 870 Align = alBottom Caption = 'Шаблоны' - ClientHeight = 251 - ClientWidth = 868 + ClientHeight = 250 + ClientWidth = 866 TabOrder = 4 object ReportsPanel: TPanel Left = 0 Height = 50 - Top = 201 - Width = 868 + Top = 200 + Width = 866 Align = alBottom ClientHeight = 50 - ClientWidth = 868 + ClientWidth = 866 TabOrder = 0 object EditTemplate: TButton Left = 760 @@ -170,19 +169,27 @@ object CGIServerGUI: TCGIServerGUI Top = 11 Width = 100 Caption = 'Шаблон' - OnClick = EditTemplateClick TabOrder = 0 + OnClick = EditTemplateClick + end + object TestButton: TButton + Left = 672 + Height = 25 + Top = 11 + Width = 75 + Caption = 'Проверка' + TabOrder = 1 + OnClick = TestButtonClick end end object ReportsList: TListBox Left = 0 - Height = 201 + Height = 200 Top = 0 - Width = 868 + Width = 866 Align = alClient ItemHeight = 0 TabOrder = 1 - TopIndex = -1 end end end diff --git a/maintcpserver.pas b/maintcpserver.pas index 08c0098..1ea70b5 100644 --- a/maintcpserver.pas +++ b/maintcpserver.pas @@ -17,6 +17,7 @@ type { TCGIServerGUI } TCGIServerGUI = class(TForm) + TestButton: TButton; EditTemplate: TButton; edtAnswer: TEdit; edtQValue: TEdit; @@ -40,12 +41,14 @@ type procedure StartButtonClick(Sender: TObject); procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); + procedure TestButtonClick(Sender: TObject); private fLogger: TEventLog; Server: TConnectionsDM; Client: TClientMainThread; cmdDone: boolean; started: boolean; + function IsTerminated(Sender: TObject): boolean; procedure LogQuery(const qtype: integer; const command: string; const aKeys: TStrings; const code: DWORD; const Param: QWORD; const data: TParamArray); function onAnswer(Sender: TMainThread; const mode: byte; const Code:DWORD; const QValue: QWORD; const Answer: string; const Values: TStrings; const iValues: TParamArray; const Data: TStream): boolean; @@ -122,7 +125,7 @@ end; procedure TCGIServerGUI.StartButtonClick(Sender: TObject); begin - Server.Start; + Server.Start(@isTerminated); Server.FillTemplates(ReportsList.Items); started := true; Panel1.Caption := 'запущен'; @@ -135,6 +138,20 @@ begin fLogger.Free; end; +procedure TCGIServerGUI.TestButtonClick(Sender: TObject); +var + rID: integer; +begin + rID := PtrInt(ReportsList.Items.Objects[ReportsList.ItemIndex]); + Server.TestReport(rID); +end; + +function TCGIServerGUI.IsTerminated(Sender: TObject): boolean; +begin + result := false; +end; + + procedure TCGIServerGUI.LogQuery(const qtype: integer; const command: string; const aKeys: TStrings; const code: DWORD; const Param: QWORD; const data: TParamArray); diff --git a/reports/allreportsunit.pas b/reports/allreportsunit.pas index f10afed..98aed63 100644 --- a/reports/allreportsunit.pas +++ b/reports/allreportsunit.pas @@ -9,7 +9,7 @@ uses implementation uses - cgiReport,applicantlist,applicantresult; + cgiReport,applicantlist,applicantresult, journal; initialization TCommandCollection.Register(TReportCommand); end. diff --git a/tcpclient.pas b/tcpclient.pas index bde57cd..ee9cf15 100644 --- a/tcpclient.pas +++ b/tcpclient.pas @@ -81,7 +81,7 @@ end; procedure TClientMainThread.execute; begin doStart; - log(mtExtra, self,'start main thread'); + log(mtExtra, self,format('start main thread %s:%d',[Host,Port])); Connect.Connect(Host,Port); try while not terminated and not Complete do @@ -100,6 +100,7 @@ end; procedure TClientMainThread.ProcessConnect(thread: TConnectionThread); begin + log(mtDebug,self,'ProcessConnect '+GuidToString(thread.ID)); thread.SendMessage(cmdRequest,1,0,self.Command,self.fFields); end; diff --git a/tcpserver.pas b/tcpserver.pas index fc6ab57..8d907c4 100644 --- a/tcpserver.pas +++ b/tcpserver.pas @@ -23,12 +23,13 @@ type private fOnReceive: TCommandReceived; fOnIdle: TNotifyEvent; + fTerminateCheck: TChecker; function processReceive(const CommandID:DWORD; const Param:QWord; const ACommand: string; const Fields: TStrings; const iParams: TParamArray; const Data: TStream; out Code: DWORD; out RetValue: QWord; out Answer: string; out rValues: TStrings; out iValues: TParamArray; out ByteData: TStream): boolean; public property OnIdle: TNotifyEvent read fOnIdle write fOnIdle; procedure execute; override; - constructor Create( ALogger: TLogger; APort: integer; OnReceive:TCommandReceived); + constructor Create( ALogger: TLogger; APort: integer;TermCheck: TChecker; OnReceive:TCommandReceived); end; implementation @@ -62,10 +63,10 @@ var n: integer; begin doStart; - log(mtExtra,self,'start main thread'); + log(mtExtra,self,format('start main thread %d',[Port])); Connect.Listen(Port); n := 0; - while not terminated and not Complete do + while not terminated and not Complete and not fTerminateCheck(self) do begin try Connect.CallAction; @@ -73,9 +74,9 @@ begin except on e: Exception do log(mtError,e, '!!ERROR '+e.message); end; - sleep(10); + sleep(100); inc(n); - if n>100 then + if n>1000 then begin if Assigned(fOnIdle) then fOnIdle(self); n :=0; @@ -86,9 +87,10 @@ begin end; constructor TServerMainThread.Create(ALogger: TLogger; APort: integer; - OnReceive: TCommandReceived); + TermCheck: TChecker; OnReceive: TCommandReceived); begin inherited Create(TServerThread,ALogger,APort); + fTerminateCheck:=TermCheck; fOnReceive := OnReceive; Connect.OnAccept:=@Accept; //FreeOnTerminate:=true; diff --git a/tcpthreadhelper.pas b/tcpthreadhelper.pas index b6325e8..3f6761c 100644 --- a/tcpthreadhelper.pas +++ b/tcpthreadhelper.pas @@ -129,6 +129,7 @@ var clt: TConnectionThread; i: integer; begin + result := nil; for i := 0 to fclients.Count-1 do if TConnectionThread(fclients[i]).Socket=index then begin @@ -137,7 +138,7 @@ begin exit; end; result := fThreadClass.Create(self,index); - log(mtExtra,self,format('new Thread(%d) %s',[index.Handle,guidToString(result.ID)])); + log(mtDebug,self,format('new Thread(%d) %s',[index.Handle,guidToString(result.ID)])); fclients.Add(Result); end; @@ -147,13 +148,13 @@ var i: integer; clt: TConnectionThread; begin - log(mtExtra,Self,'Terminate Clients'); + log(mtDebug,Self,'Terminate Clients '+inttostr(fclients.Count)); for i := fclients.Count-1 downto 0 do begin sleep(0); clt := TConnectionThread(fclients[i]); try - log(mtExtra,self,GuidToString(clt.ID)); + log(mtDebug,self,GuidToString(clt.ID)); clt.Terminate; clt.WaitFor; clt.free; @@ -182,7 +183,11 @@ end; procedure TMainThread.RemoveClient(clt: TConnectionThread); begin + clt.Terminate; + clt.WaitFor; + log(mtDebug,self,'RemoveClient '+GuidToString(clt.ID)); fclients.Remove(clt); + clt.free; end; @@ -190,7 +195,7 @@ procedure TMainThread.dataReady(aSocket: TLSocket); var clt: TConnectionThread; begin - log(mtExtra,self,'dataReady'); + log(mtExtra,self,format('dataReady(%s:%d<-%s:%d) ',[aSocket.LocalAddress,aSocket.LocalPort,aSocket.PeerAddress,aSocket.PeerPort])); if Terminated then exit; clt := Client[aSocket]; @@ -203,19 +208,19 @@ end; procedure TMainThread.ProcessConnect(thread: TConnectionThread); begin - + log(mtExtra,self,'ProcessConnect'+GUIDToString(thread.ID)); end; procedure TMainThread.ProcessAccept(thread: TConnectionThread); begin - + log(mtExtra,self,'ProcessAccept'+GUIDToString(thread.ID)); end; procedure TMainThread.Accept(aSocket: TLSocket); var clt: TConnectionThread; begin - log(mtExtra,self,'connect'); + log(mtExtra,self,format('accept(%s:%d<-%s:%d) ',[aSocket.LocalAddress,aSocket.LocalPort,aSocket.PeerAddress,aSocket.PeerPort])); if Terminated then exit; clt := Client[aSocket]; log(mtExtra,self,format('connected %s on %d ',[GUIDToString(clt.ID), aSocket.Handle])); @@ -229,14 +234,17 @@ var clt: TConnectionThread; begin if terminated then exit; - log(mtExtra,self,'disconnect'); + log(mtDebug,self,format('disconnect(%s:%d<-%s:%d) ',[aSocket.LocalAddress,aSocket.LocalPort,aSocket.PeerAddress,aSocket.PeerPort])); try clt := Client[aSocket]; - if clt.terminated then exit; - log(mtExtra,self,format('disconnected %s on %d ',[GUIDToString(clt.ID), aSocket.Handle])); - clt.Terminate; - fclients.remove(clt); - + if assigned(clt) then + begin + log(mtDebug,self,format('disconnected %s on %d ',[GUIDToString(clt.ID), aSocket.Handle])); + clt.Terminate; + fclients.remove(clt); + clt.WaitFor; + clt.free; + end; except on e: Exception do begin log(mtError,self,'!!ERROR doDisconnect '+e.Message); @@ -249,7 +257,7 @@ procedure TMainThread.doConnect(aSocket: TLSocket); var clt: TConnectionThread; begin - log(mtExtra,self,'doConnect'); + log(mtExtra,self,format('doConnect(%s:%d<-%s:%d) ',[aSocket.LocalAddress,aSocket.LocalPort,aSocket.PeerAddress,aSocket.PeerPort])); if Terminated then exit; clt := Client[aSocket]; log(mtExtra,self,format('connected %s on %d ',[GUIDToString(clt.ID), aSocket.Handle])); @@ -1040,7 +1048,7 @@ begin fOwner := AOwner; CreateGuid(ID); recNo := 0; - log(mtExtra,'Create'); + log(mtExtra,'Create client thread '); end; destructor TConnectionThread.Destroy; @@ -1064,7 +1072,12 @@ begin log(mtExtra,'start thread'); while not terminated do begin - if cache.ReadReady.WaitFor(1000)<>wrSignaled then begin sleep(10);continue;end; + if cache.ReadReady.WaitFor(10000)<>wrSignaled then + begin + log(mtDebug,'TConnectionThread.Wait'); + sleep(100); + continue; + end; if terminated then break; if not Socket.Connected then break; Keys := nil;