source: cprs/trunk/CPRS-Chart/Options/fOptionsReportsCustom.pas@ 829

Last change on this file since 829 was 829, checked in by Kevin Toppenberg, 14 years ago

Upgrade to version 27

File size: 19.7 KB
Line 
1unit fOptionsReportsCustom;
2
3interface
4
5uses
6 Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
7 StdCtrls, ExtCtrls, Spin, ORCtrls, fOptions, ComCtrls, ORFn, ORNet, Grids, uConst,
8 ORDtTm, rCore, fBase508Form, VA508AccessibilityManager;
9
10type
11 TfrmOptionsReportsCustom = class(TfrmBase508Form)
12 Panel1: TPanel;
13 Bevel3: TBevel;
14 btnApply: TButton;
15 btnCancel: TButton;
16 Panel2: TPanel;
17 grdReport: TCaptionStringGrid;
18 edtMax: TCaptionEdit;
19 odbStop: TORDateBox;
20 odbStart: TORDateBox;
21 odbTool: TORDateBox;
22 btnOK: TButton;
23 Panel3: TPanel;
24 edtSearch: TCaptionEdit;
25 Label1: TLabel;
26 function ValFor(ACol, ARow: Integer): string;
27 procedure FormCreate(Sender: TObject);
28 procedure grdReportMouseDown(Sender: TObject; Button: TMouseButton;
29 Shift: TShiftState; X, Y: Integer);
30 procedure grdReportKeyPress(Sender: TObject; var Key: Char);
31 procedure grdReportDrawCell(Sender: TObject; ACol, ARow: Integer;
32 Rect: TRect; State: TGridDrawState);
33 procedure UMDelayEvent(var Message: TMessage); Message UM_DELAYEVENT;
34 procedure edtMaxExit(Sender: TObject);
35 procedure btnApplyClick(Sender: TObject);
36 procedure btnCancelClick(Sender: TObject);
37 procedure odbStartExit(Sender: TObject);
38 procedure odbStopExit(Sender: TObject);
39 procedure FormClose(Sender: TObject; var Action: TCloseAction);
40 procedure odbStartKeyPress(Sender: TObject; var Key: Char);
41 procedure odbStopKeyPress(Sender: TObject; var Key: Char);
42 procedure edtMaxKeyPress(Sender: TObject; var Key: Char);
43 procedure btnOKClick(Sender: TObject);
44 procedure edtSearchChange(Sender: TObject);
45 procedure edtSearchKeyPress(Sender: TObject; var Key: Char);
46 procedure FormShow(Sender: TObject);
47 procedure grdReportKeyDown(Sender: TObject; var Key: Word;
48 Shift: TShiftState);
49 private
50 { Private declarations }
51 //startDate,endDate,
52 maxOcurs,signal: integer;
53 rptList: TStringList;
54 fDropColumn: Integer;
55 sDate,eDate: string;
56 procedure ShowEditor(ACol, ARow: Integer; AChar: Char);
57 public
58 { Public declarations }
59 end;
60var
61 frmOptionsReportsCustom: TfrmOptionsReportsCustom;
62 const
63 Col_StartDate = 1;
64 Col_StopDate = 2;
65 Col_Max = 3;
66 TAB = #9;
67procedure DialogOptionsHSCustom(topvalue, leftvalue, fontsize: integer; var actiontype: Integer);
68
69implementation
70
71uses rOptions, uOptions, fReports, fLabs, uCore;
72
73{$R *.DFM}
74
75procedure TfrmOptionsReportsCustom.UMDelayEvent(var Message: TMessage);
76{ after focusing events are completed for a combobox, set the key the user typed }
77begin
78 case Message.LParam of
79 Col_StartDate:
80 begin
81 odbStart.Visible := True;
82 odbStart.Text := Chr(Message.WParam);
83 end;
84 COL_StopDate :
85 begin
86 odbStop.Visible := True;
87 odbStop.Text := Chr(Message.WParam);
88 end;
89 COL_Max :
90 begin
91 edtMax.Visible := True;
92 edtMax.Text := Chr(Message.WParam);
93 end;
94 end;
95end;
96
97procedure DialogOptionsHSCustom(topvalue, leftvalue, fontsize: integer; var actiontype: Integer);
98var
99 frmOptionsReportsCustom: TfrmOptionsReportsCustom;
100begin
101 frmOptionsReportsCustom := TfrmOptionsReportsCustom.Create(Application);
102 actiontype := 0;
103 try
104 with frmOptionsReportsCustom do
105 begin
106 if (topvalue < 0) or (leftvalue < 0) then
107 Position := poScreenCenter
108 else
109 begin
110 Position := poDesigned;
111 Top := topvalue;
112 Left := leftvalue;
113 end;
114 ResizeAnchoredFormToFont(frmOptionsReportsCustom);
115 ShowModal;
116 actiontype := btnApply.Tag;
117 end;
118 finally
119 frmOptionsReportsCustom.Release;
120 end;
121end;
122
123procedure TfrmOptionsReportsCustom.FormCreate(Sender: TObject);
124begin
125 rptList := TStringList.Create;
126end;
127
128procedure TfrmOptionsReportsCustom.ShowEditor(ACol, ARow: Integer; AChar: Char);
129
130 procedure PlaceControl(AControl: TWinControl);
131 var
132 ARect: TRect;
133 begin
134 with AControl do
135 begin
136 ARect := grdReport.CellRect(ACol, ARow);
137 SetBounds(ARect.Left + grdReport.Left + 2, ARect.Top + grdReport.Top + 2,
138 ARect.Right - ARect.Left - 1 , ARect.Bottom-ARect.Top -1 );
139 Visible := True;
140 Tag := ARow;
141 BringToFront;
142 Show;
143 SetFocus;
144 end;
145 end;
146 procedure Synch(AEdit: TEdit; const edtText: string);
147 begin
148 AEdit.Text := edtText;
149 AEdit.SelectAll;
150 end;
151begin
152 inherited;
153 if ARow = 0 then Exit; //header row
154 with grdReport do if (ARow = Pred(RowCount)) and (ACol > 4 ) then Exit;
155 case ACol of
156 Col_StartDate: begin
157 if (ARow > 0 ) then
158 begin
159 PlaceControl(odbStart);
160 Synch(odbStart,ValFor(Col_StartDate,ARow));
161 if AChar <> #0 then PostMessage(Handle, UM_DELAYEVENT, Ord(AChar), COL_StartDate);
162 end;
163 end;
164 Col_StopDate: begin
165 if (ARow > 0 ) then
166 begin
167 PlaceControl(odbStop);
168 Synch(odbStop, ValFor(Col_StopDate,ARow));
169 if AChar <> #0 then PostMessage(Handle, UM_DELAYEVENT, Ord(AChar), COL_StopDate);
170 end;
171 end;
172 Col_Max: begin
173 if (ARow > 0 ) and (StrToInt(ValFor(Col_Max,ARow)) > 0) then
174 begin
175 PlaceControl(edtMax);
176 Synch(edtMax, ValFor(Col_Max,ARow));
177 fDropColumn := Col_Max;
178 if AChar <> #0 then PostMessage(Handle, UM_DELAYEVENT, Ord(AChar), COL_Max);
179 end;
180 end;
181 end;
182end;
183
184function TfrmOptionsReportsCustom.ValFor(ACol, ARow: Integer): string;
185begin
186 Result := grdReport.Cells[ACol, ARow];
187end;
188
189procedure TfrmOptionsReportsCustom.grdReportKeyPress(Sender: TObject;
190 var Key: Char);
191begin
192 inherited;
193 if grdReport.Col = 1 then
194 sDate := grdReport.Cells[grdReport.Col,grdReport.Row];
195 if grdReport.Col = 2 then
196 eDate := grdReport.Cells[grdReport.Col,grdReport.Row];
197 if (grdReport.Col = 3) and (grdReport.Cells[grdReport.Col, grdReport.Row]='') then
198 Exit else if Length(grdReport.Cells[3, grdReport.Row]) > 0 then maxOcurs := StrToInt( grdReport.Cells[3,grdReport.Row]);
199 if Key = #13 then ShowEditor(grdReport.Col, grdReport.Row, #0);
200 if Key = #9 then
201 begin
202 odbStart.Visible := False;
203 odbStop.Visible := False;
204 edtMax.Visible := False;
205 ShowEditor(grdReport.Col, grdReport.Row, #0);
206 end;
207 if Key in [#32..#127] then ShowEditor(grdReport.Col, grdReport.Row, Key);
208 signal := 0;
209end;
210
211procedure TfrmOptionsReportsCustom.grdReportMouseDown(Sender: TObject;
212 Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
213var
214 ACol,ARow: integer;
215begin
216 inherited;
217 if (not User.ToolsRptEdit) then // For users with Reports settings edit parameter not set.
218 begin
219 abort;
220 exit;
221 end;
222 grdReport.MouseToCell(X,Y,ACol,ARow);
223 if (ARow < 1) or (ACol < 1) then
224 begin
225 odbStop.Visible := False;
226 odbStart.Visible := False;
227 edtMax.Visible := False;
228 Exit;
229 end;
230 if ACol = 1 then
231 begin
232 odbStop.Visible := False;
233 edtMax.Visible := False;
234 sDate := grdReport.Cells[1,ARow];
235 ShowEditor(ACol, ARow, #0);
236 end;
237 if ACol = 2 then
238 begin
239 odbStart.Visible := False;
240 edtMax.Visible := False;
241 eDate := grdReport.Cells[2,ARow];
242 ShowEditor(ACol, ARow, #0);
243 end;
244 if (ACol = 3) and (grdReport.Cells[ACol,ARow]='') then
245 begin
246 odbStart.Visible := False;
247 odbStop.Visible := False;
248 Exit;
249 end
250 else if (ACol = 3) and (strtoint(grdReport.Cells[ACol,ARow])>0) then
251 begin
252 odbStart.Visible := False;
253 odbStop.Visible := False;
254 maxOcurs := strtoint(grdReport.Cells[ACol,ARow]);
255 ShowEditor(ACol, ARow, #0);
256 end
257 else
258 begin
259 grdReport.Col := 0;
260 grdReport.Row := ARow;
261 end;
262 signal := 0;
263end;
264
265procedure TfrmOptionsReportsCustom.grdReportDrawCell(Sender: TObject; ACol,
266 ARow: Integer; Rect: TRect; State: TGridDrawState);
267begin
268 inherited;
269 grdReport.Canvas.TextRect(Rect, Rect.Left+2, Rect.Top+2,
270 Piece(grdReport.Cells[ACol, ARow], TAB, 1));
271
272end;
273
274procedure TfrmOptionsReportsCustom.edtMaxExit(Sender: TObject);
275var
276 newValue: String;
277 code, I: integer;
278begin
279 if edtMax.Modified then
280 begin
281 newValue := edtMax.Text;
282 if length(newValue) = 0 then
283 begin
284 InfoBox('Invalid value of max occurences', 'Warning', MB_OK or MB_ICONWARNING);
285 edtMax.Text := IntToStr(maxOcurs);
286 edtMax.SetFocus;
287 edtMax.SelectAll;
288 end;
289 if length(newValue) > 0 then
290 begin
291 Val(newValue, I, code);
292 if I = 0 then begin end; //added to keep compiler from generating a hint
293 if code <> 0 then
294 begin
295 InfoBox('Invalid value of max occurences', 'Warning', MB_OK or MB_ICONWARNING);
296 edtMax.Text := IntToStr(maxOcurs);
297 edtMax.SetFocus;
298 edtMax.SelectAll;
299 end;
300 if code = 0 then
301 begin
302 if strtoint(edtMax.Text) <= 0 then
303 begin
304 InfoBox('the value of max should be greater than 0', 'Warning', MB_OK or MB_ICONWARNING);
305 edtMax.Text := intToStr(maxOcurs);
306 edtMax.SetFocus;
307 edtMax.SelectAll;
308 exit;
309 end;
310 grdReport.Cells[Col_Max, edtMax.Tag] := edtMax.Text;
311 if compareStr(Piece(Piece(grdReport.Cells[0,edtMax.Tag],TAB,2),'^',2),'M')=0 then
312 begin
313 edtMax.Visible := False;
314 btnApply.Enabled := True;
315 Exit;
316 end;
317 grdReport.Cells[0,edtMax.Tag] := grdReport.Cells[0,edtMax.Tag] + '^M';
318 edtMax.Visible := False;
319 btnApply.Enabled := True;
320 end;
321 end;
322 end;
323end;
324
325procedure TfrmOptionsReportsCustom.btnApplyClick(Sender: TObject);
326var
327 valueStartdate, valueStopdate,valueMax, rpt, values,name: string;
328 i: integer;
329begin
330 for i := 1 to grdReport.RowCount do
331 begin
332 if CompareStr(Piece(Piece( grdReport.Cells[0,i],TAB,2),'^',2),'M')=0 then
333 begin
334 rpt := Piece(Piece( grdReport.Cells[0,i],TAB,2),'^',1);
335 name := Piece( grdReport.Cells[0,i],TAB,1);
336 odbTool.Text := grdReport.Cells[1,i];
337 valueStartDate := odbTool.RelativeTime;
338 odbTool.Text := grdReport.Cells[2,i];
339 valueStopDate := odbTool.RelativeTime;
340 valueMax := grdReport.Cells[3,i];
341 if Length(valueMax)<1 then
342 valueMax := '7';
343 values := valueStartdate + ';' + valueStopDate + ';' + valueMax;
344{ if CompareStr(name,'Imaging (local only)')=0 then // imaging report id is hard coded to be 10000
345 values := valueStartdate + ';' + valueStopDate + ';;;' + valueMax
346 else}
347 rpcSetIndividualReportSetting(rpt, values);
348 end;
349 end;
350 btnApply.Enabled := False;
351 odbStart.Visible := False;
352 odbStop.Visible := False;
353 edtMax.Visible := False;
354 frmReports.LoadTreeView;
355 frmLabs.LoadTreeView;
356 with frmReports.tvReports do
357 begin
358 if Items.Count > 0 then
359 Selected := Items.GetFirstNode;
360 frmReports.tvReportsClick(Selected);
361 end;
362 with frmLabs.tvReports do
363 begin
364 if Items.Count > 0 then
365 Selected := Items.GetFirstNode;
366 frmReports.tvReportsClick(Selected);
367 end;
368end;
369
370procedure TfrmOptionsReportsCustom.btnCancelClick(Sender: TObject);
371begin
372 rptList.Clear;
373 Close;
374end;
375
376
377procedure TfrmOptionsReportsCustom.odbStartExit(Sender: TObject);
378const
379 TX_BAD_START = 'The start date is not valid.';
380 TX_STOPSTART = 'The start date must not be after the stop date.';
381var
382 x,ErrMsg,datestart,datestop: String;
383begin
384 if odbStart.text = '' then
385 begin
386 InfoBox(TX_BAD_START, 'Warning', MB_OK or MB_ICONWARNING);
387 odbStart.Visible := True;
388 odbStart.Text := sDate;
389 odbStart.Setfocus;
390 odbStart.SelectAll;
391 exit;
392 end;
393 if odbStart.Text = sDate then
394 exit;
395 ErrMsg := '';
396 odbStart.Validate(x);
397 if Length(x) > 0 then
398 begin
399 ErrMsg := TX_BAD_START;
400 InfoBox(TX_BAD_START, 'Warning', MB_OK or MB_ICONWARNING);
401 odbStart.Visible := True;
402 odbStart.Text := sDate;
403 odbStart.Setfocus;
404 odbStart.SelectAll;
405 exit;
406 end;
407 datestart := odbStart.RelativeTime;
408 datestop := MakeRelativeDateTime(
409 StrToFMDateTime(grdReport.Cells[Col_StopDate,odbStart.Tag])
410 );
411 delete(datestart,1,1);
412 delete(datestop,1,1);
413 if StrToIntDef(datestart,0)> StrToIntDef(datestop,0) then
414 begin
415 InfoBox(TX_STOPSTART, 'Warning', MB_OK or MB_ICONWARNING);
416 odbStart.Text := grdReport.Cells[Col_StopDate,odbStart.Tag];
417 odbStart.SetFocus;
418 odbStart.SelectAll;
419 exit;
420 end;
421 grdReport.Cells[Col_StartDate, odbStart.Tag] := DateToStr(FMDateTimeToDateTime(odbStart.FMDateTime));
422 odbStart.Visible := False;
423 btnApply.Enabled := True;
424 if compareStr(Piece(Piece(grdReport.Cells[0,odbStart.Tag],TAB,2),'^',2),'M')=0 then
425 Exit;
426 grdReport.Cells[0,odbStart.Tag] := grdReport.Cells[0,odbStart.Tag] + '^M';
427end;
428
429procedure TfrmOptionsReportsCustom.odbStopExit(Sender: TObject);
430const
431 TX_BAD_STOP = 'The stop date is not valid.';
432 TX_BAD_ORDER = 'The stop date must not be earlier than start date.';
433var
434 x, ErrMsg,datestart,datestop: string;
435begin
436 if odbStop.text = '' then
437 begin
438 InfoBox(TX_BAD_STOP, 'Warning', MB_OK or MB_ICONWARNING);
439 odbStop.Visible := True;
440 odbStop.Text := eDate;
441 odbStop.Setfocus;
442 odbStop.SelectAll;
443 exit;
444 end;
445
446 if odbStop.Text = eDate then
447 exit;
448
449 ErrMsg := '';
450 odbStop.Validate(x);
451 if Length(x) > 0 then
452 begin
453 ErrMsg := TX_BAD_STOP;
454 InfoBox(TX_BAD_STOP, 'Warning', MB_OK or MB_ICONWARNING);
455 odbStop.Visible := True;
456 odbStop.Text := eDate;
457 odbStop.Setfocus;
458 odbStop.SelectAll;
459 exit;
460 end;
461
462 datestart := MakeRelativeDateTime(
463 StrToFMDateTime(grdReport.Cells[Col_StartDate,odbStop.Tag])
464 );
465 datestop := odbStop.RelativeTime;
466 delete(datestart,1,1);
467 delete(datestop,1,1);
468 if StrToIntDef(datestart,0)> StrToIntDef(datestop,0) then
469 begin
470 InfoBox(TX_BAD_ORDER, 'Warning', MB_OK or MB_ICONWARNING);
471 odbStop.Text := grdReport.Cells[Col_StartDate,odbStop.Tag];
472 odbStop.SetFocus;
473 odbStop.SelectAll;
474 exit;
475 end;
476 grdReport.Cells[Col_StopDate, odbStop.Tag] := DateToStr(FMDateTimeToDateTime(odbStop.FMDateTime));
477 odbStop.Visible := False;
478 btnApply.Enabled := True;
479 if compareStr(Piece(Piece(grdReport.Cells[0,odbStop.Tag],TAB,2),'^',2),'M')=0 then
480 Exit;
481 grdReport.Cells[0,odbStop.Tag] := grdReport.Cells[0,odbStop.Tag] + '^M';
482end;
483
484
485procedure TfrmOptionsReportsCustom.FormClose(Sender: TObject;
486 var Action: TCloseAction);
487begin
488 Close;
489 rptList.Clear;
490end;
491
492procedure TfrmOptionsReportsCustom.odbStartKeyPress(Sender: TObject;
493 var Key: Char);
494begin
495 if Key = #13 then
496 begin
497 odbStart.Visible := False;
498 Perform(WM_NextDlgCtl, 0, 0);
499 exit;
500 end;
501end;
502
503procedure TfrmOptionsReportsCustom.odbStopKeyPress(Sender: TObject;
504 var Key: Char);
505begin
506 if Key = #13 then
507 begin
508 odbStop.Visible := False;
509 Perform(WM_NextDlgCtl, 0, 0);
510 exit;
511 end;
512end;
513
514procedure TfrmOptionsReportsCustom.edtMaxKeyPress(Sender: TObject;
515 var Key: Char);
516begin
517 if Key = #13 then
518 begin
519 edtMax.Visible := False;
520 Perform(WM_NextDlgCtl, 0, 0);
521 exit;
522 end;
523end;
524
525procedure TfrmOptionsReportsCustom.btnOKClick(Sender: TObject);
526begin
527 if btnApply.Enabled then
528 btnApplyClick(self);
529 Close;
530end;
531
532procedure TfrmOptionsReportsCustom.edtSearchChange(Sender: TObject);
533var
534 i: integer;
535 needle,hay: String;
536 selRect: TGridRect;
537
538begin
539 if (edtSearch.Modified) and (signal=0) then
540 begin
541 needle := UpperCase(edtSearch.text);
542 if length(needle)=0 then
543 begin
544 selRect.Left := 0;
545 selRect.Top := 1;
546 selRect.Right := 0;
547 selRect.Bottom := 1;
548 grdReport.Selection := selRect;
549 grdReport.TopRow := 1;
550 exit;
551 end;
552 for i := 1 to grdReport.RowCount do
553 begin
554 hay := Piece(UpperCase(grdReport.Cells[0,i]),TAB,1);
555 hay := Copy(hay,0,length(needle));
556 if Pos(needle, hay) > 0 then
557 begin
558 selRect.Left := 0;
559 selRect.Top := i;
560 selRect.Right := 0;
561 selRect.Bottom := i;
562 grdReport.Selection := selRect;
563 grdReport.TopRow := i;
564 exit;
565 end;
566 end;
567 end;
568 if (edtSearch.Modified) and (signal=1) then
569 begin
570 signal := 0;
571 end;
572 Exit;
573end;
574
575procedure TfrmOptionsReportsCustom.edtSearchKeyPress(Sender: TObject;
576 var Key: Char);
577begin
578 if Key = #13 then
579 begin
580 Perform(WM_NextDlgCtl, 0, 0);
581 edtSearch.Text := '';
582 exit;
583 end;
584end;
585
586procedure TfrmOptionsReportsCustom.FormShow(Sender: TObject);
587var
588 i,rowNum: integer;
589 startOff,stopOff: string;
590 today: TFMDateTime;
591begin
592 today := FMToday;
593 signal := 0;
594 rptList := TStringList.Create;
595 CallV('ORWTPD GETSETS',[nil]);
596 MixedCaseList( RPCBrokerV.Results );
597 rptList := TStringList(RPCBrokerV.Results);
598 SortByPiece(rptList,'^',2);
599 rowNum := rptList.Count;
600 grdReport.RowCount := rowNum + 1;
601 grdReport.Cells[0,0] := 'Report Name';
602 grdReport.Cells[1,0] := 'Start Date';
603 grdReport.Cells[2,0] := 'Stop Date';
604 grdReport.Cells[3 ,0] := 'Max';
605
606 for i := 1 to grdReport.RowCount-1 do
607 begin
608 grdReport.Cells[0,i] := Piece(rptList[i-1],'^',2)+ TAB + Piece(rptList[i-1],'^',1);
609 startOff := Piece(Piece(rptList[i-1],'^',3),';',1);
610 stopOff := Piece(Piece(rptList[i-1],'^',3),';',2);
611 delete(startOff,1,1);
612 delete(stopOff,1,1);
613 grdReport.Cells[1,i] := DateToStr(FMDateTimeToDateTime(FMDateTimeOffsetBy(today, StrToIntDef(startOff,0))));
614 grdReport.Cells[2,i] := DateToStr(FMDateTimeToDateTime(FMDateTimeOffsetBy(today, StrToIntDef(stopOff,0))));
615 grdReport.Cells[3,i] := Piece(Piece(rptList[i-1],'^',3),';',3);
616 end;
617 if not edtSearch.Focused then
618 edtSearch.SetFocus;
619 btnCancel.Caption := 'Cancel';
620 if (not User.ToolsRptEdit) then // For users with Reports settings edit parameter not set.
621 begin
622 grdReport.onKeyPress := nil;
623 grdReport.onMouseDown := nil;
624 odbStart.readOnly := true;
625 odbStart.onExit := nil;
626 odbStart.onKeyPress := nil;
627 odbStop.readOnly := true;
628 odbStop.onExit := nil;
629 odbStop.onKeyPress := nil;
630 edtMax.readOnly := true;
631 odbTool.readOnly := true;
632 btnOK.visible := false;
633 btnApply.visible := false;
634 btnCancel.Caption := 'Close';
635 end;
636end;
637
638procedure TfrmOptionsReportsCustom.grdReportKeyDown(Sender: TObject;
639 var Key: Word; Shift: TShiftState);
640begin
641 if (Key = VK_TAB) then
642 begin
643 if ssShift in Shift then
644 begin
645 EdtSearch.SetFocus;
646 Key := 0;
647 end
648 else if ssCtrl in Shift then
649 begin
650 if User.ToolsRptEdit then
651 btnApply.SetFocus
652 else
653 btnCancel.SetFocus;
654 Key := 0;
655 end;
656 end;
657 if Key = VK_ESCAPE then begin
658 EdtSearch.SetFocus;
659 Key := 0;
660 end;
661end;
662
663end.
664
Note: See TracBrowser for help on using the repository browser.