source: trunk/FormMain.pas

Last change on this file was 12, checked in by chronos, 13 days ago
  • Added: Min/max interval position navigation buttons.
  • Modified: Remember last interval position.
File size: 17.7 KB
Line 
1unit FormMain;
2
3interface
4
5uses
6 Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, ComCtrls,
7 EditBtn, Menus, TAGraph, TASeries, Generics.Collections, Generics.Defaults,
8 DateUtils, Ean, Translator, ApplicationInfo, RegistryEx, PersistentForm,
9 Theme, Common, XML, EdcProject;
10
11type
12
13 TPeriod = (prDay, prWeek, prMonth, prYear);
14 TValueUnit = (vukWh, vuWh, vukW, vuW);
15
16 { TFormMain }
17
18 TFormMain = class(TForm)
19 ApplicationInfo1: TApplicationInfo;
20 ButtonIntervalRight: TButton;
21 ButtonIntervalLeft: TButton;
22 ButtonIntervalRightMax: TButton;
23 ButtonIntervalLeftMin: TButton;
24 Chart1: TChart;
25 Chart1LineSeries1: TLineSeries;
26 Chart1LineSeries2: TLineSeries;
27 Chart1LineSeries3: TLineSeries;
28 Chart1LineSeries4: TLineSeries;
29 Chart1LineSeries5: TLineSeries;
30 Chart1LineSeries6: TLineSeries;
31 CheckBoxShowResult: TCheckBox;
32 ComboBoxEan: TComboBox;
33 ComboBoxEan3: TComboBox;
34 ComboBoxEanData: TComboBox;
35 ComboBoxEan2: TComboBox;
36 ComboBoxPeriod: TComboBox;
37 ComboBoxUnit: TComboBox;
38 DateEdit1: TDateEdit;
39 Label1: TLabel;
40 Label2: TLabel;
41 Label3: TLabel;
42 Label4: TLabel;
43 Label5: TLabel;
44 Label6: TLabel;
45 ListViewOverview: TListView;
46 ListViewData: TListView;
47 ListViewSpotPrices: TListView;
48 MainMenu1: TMainMenu;
49 Memo1: TMemo;
50 MenuItemRemove: TMenuItem;
51 MenuItemLoad: TMenuItem;
52 MenuItemSave: TMenuItem;
53 MenuItemTools: TMenuItem;
54 MenuItemImportReports: TMenuItem;
55 MenuItemImportSpotPrices: TMenuItem;
56 MenuItemFile: TMenuItem;
57 PageControl1: TPageControl;
58 PersistentForm1: TPersistentForm;
59 PopupMenuOverview: TPopupMenu;
60 TabSheetSpotPrices: TTabSheet;
61 TabSheetOverview: TTabSheet;
62 TabSheetData: TTabSheet;
63 TabSheetChart: TTabSheet;
64 TabSheetLog: TTabSheet;
65 ThemeManager1: TThemeManager;
66 TimeEdit1: TTimeEdit;
67 Translator1: TTranslator;
68 procedure ButtonIntervalLeftClick(Sender: TObject);
69 procedure ButtonIntervalLeftMinClick(Sender: TObject);
70 procedure ButtonIntervalRightClick(Sender: TObject);
71 procedure ButtonIntervalRightMaxClick(Sender: TObject);
72 procedure CheckBoxShowResultChange(Sender: TObject);
73 procedure ComboBoxEanDataSelect(Sender: TObject);
74 procedure ComboBoxEanSelect(Sender: TObject);
75 procedure ComboBoxPeriodSelect(Sender: TObject);
76 procedure ComboBoxUnitSelect(Sender: TObject);
77 procedure DateEdit1Change(Sender: TObject);
78 procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
79 procedure FormCreate(Sender: TObject);
80 procedure FormDestroy(Sender: TObject);
81 procedure FormShow(Sender: TObject);
82 procedure MenuItemImportReportsClick(Sender: TObject);
83 procedure MenuItemImportSpotPricesClick(Sender: TObject);
84 procedure MenuItemLoadClick(Sender: TObject);
85 procedure MenuItemRemoveClick(Sender: TObject);
86 procedure MenuItemSaveClick(Sender: TObject);
87 procedure TabSheetOverviewShow(Sender: TObject);
88 procedure TabSheetChartShow(Sender: TObject);
89 procedure TabSheetDataShow(Sender: TObject);
90 procedure TabSheetLogShow(Sender: TObject);
91 procedure TabSheetSpotPricesShow(Sender: TObject);
92 procedure TimeEdit1Change(Sender: TObject);
93 procedure Translator1Translate(Sender: TObject);
94 private
95 IntervalFrom: TDateTime;
96 IntervalTo: TDateTime;
97 ValueUnit: TValueUnit;
98 Period: TPeriod;
99 ReportsDir: string;
100 SpotPricesDir: string;
101 ProjectFileName: string;
102 ShowResult: Boolean;
103 EdcProject: TEdcProject;
104 function MeasureToFloat(Value: Double; Interval: Double): Double;
105 function MeasureToStr(Value: Double): string;
106 procedure LoadConfig;
107 procedure Report;
108 procedure ReloadListViewOverview;
109 procedure ReloadListViewData;
110 procedure ReloadListViewSpotPrices;
111 procedure ReloadChart;
112 function GetIntervalLength: TDateTime;
113 function GetIntervalStep: TDateTime;
114 procedure SaveConfig;
115 procedure UpdateInterface;
116 procedure UpdateInterval;
117 procedure ShowActiveTab;
118 public
119 end;
120
121
122var
123 FormMain: TFormMain;
124
125
126implementation
127
128{$R *.lfm}
129
130resourcestring
131 SEAN = 'EAN';
132 SOwner = 'Owner';
133 SShared = 'Shared';
134 SMeasured = 'Measured';
135 SResult = 'Result';
136 SDay = 'Day';
137 SWeek = 'Week';
138 SMonth = 'Month';
139 SYear = 'Year';
140
141{ TFormMain }
142
143procedure TFormMain.CheckBoxShowResultChange(Sender: TObject);
144begin
145 if CheckBoxShowResult.Checked <> ShowResult then begin
146 ShowResult := CheckBoxShowResult.Checked;
147 ReloadChart;
148 end;
149end;
150
151procedure TFormMain.ComboBoxEanDataSelect(Sender: TObject);
152begin
153 ReloadListViewData;
154end;
155
156procedure TFormMain.ButtonIntervalRightClick(Sender: TObject);
157begin
158 IntervalTo := IntervalTo + GetIntervalLength;
159 UpdateInterval;
160end;
161
162procedure TFormMain.ButtonIntervalRightMaxClick(Sender: TObject);
163begin
164 IntervalTo := EdcProject.Eans.GetMaxTime + FifteenMinute;
165 UpdateInterval;
166end;
167
168procedure TFormMain.ButtonIntervalLeftClick(Sender: TObject);
169begin
170 IntervalTo := IntervalTo - GetIntervalLength;
171 UpdateInterval;
172end;
173
174procedure TFormMain.ButtonIntervalLeftMinClick(Sender: TObject);
175begin
176 IntervalTo := EdcProject.Eans.GetMinTime + GetIntervalLength + FifteenMinute;
177 UpdateInterval;
178end;
179
180procedure TFormMain.ComboBoxEanSelect(Sender: TObject);
181begin
182 ReloadChart;
183end;
184
185procedure TFormMain.ComboBoxPeriodSelect(Sender: TObject);
186begin
187 Period := TPeriod(ComboBoxPeriod.ItemIndex);
188 UpdateInterval;
189end;
190
191procedure TFormMain.ComboBoxUnitSelect(Sender: TObject);
192begin
193 ValueUnit := TValueUnit(ComboBoxUnit.ItemIndex);
194 ShowActiveTab;
195end;
196
197procedure TFormMain.DateEdit1Change(Sender: TObject);
198var
199 NewIntervalTo: TDateTime;
200begin
201 NewIntervalTo := DateEdit1.Date + TimeOf(IntervalTo);
202 if NewIntervalTo <> IntervalTo then begin
203 IntervalTo := NewIntervalTo;
204 UpdateInterval;
205 end;
206end;
207
208procedure TFormMain.FormClose(Sender: TObject; var CloseAction: TCloseAction);
209begin
210end;
211
212procedure TFormMain.FormCreate(Sender: TObject);
213begin
214 PageControl1.TabIndex := 0;
215 EdcProject := TEdcProject.Create;
216 LoadConfig;
217end;
218
219procedure TFormMain.FormDestroy(Sender: TObject);
220begin
221 SaveConfig;
222 FreeAndNil(EdcProject);
223end;
224
225procedure TFormMain.FormShow(Sender: TObject);
226begin
227 EdcProject.LoadFromFile(ProjectFileName);
228
229 UpdateInterval;
230 UpdateInterface;
231end;
232
233procedure TFormMain.MenuItemImportReportsClick(Sender: TObject);
234begin
235 EdcProject.ImportReports(ReportsDir);
236
237 if (EdcProject.Eans.Count > 0) and (EdcProject.Eans[0].Values.Count > 0) then
238 IntervalTo := EdcProject.Eans[0].Values.Last.Time + FifteenMinute;
239 UpdateInterval;
240 UpdateInterface;
241end;
242
243procedure TFormMain.MenuItemImportSpotPricesClick(Sender: TObject);
244begin
245 //EdcProject.SpotPrices.Import(SpotPricesDir);
246 EdcProject.SpotPrices.LoadFromWeb;
247
248 ShowActiveTab;
249end;
250
251procedure TFormMain.MenuItemLoadClick(Sender: TObject);
252begin
253 EdcProject.LoadFromFile(ProjectFileName);
254
255 if (EdcProject.Eans.Count > 0) and (EdcProject.Eans[0].Values.Count > 0) then
256 IntervalTo := EdcProject.Eans[0].Values.Last.Time + FifteenMinute;
257 UpdateInterval;
258 UpdateInterface;
259end;
260
261procedure TFormMain.MenuItemRemoveClick(Sender: TObject);
262begin
263 if Assigned(ListViewOverview.Selected) then
264 EdcProject.Eans.Remove(ListViewOverview.Selected.Data);
265 ReloadListViewOverview;
266end;
267
268procedure TFormMain.MenuItemSaveClick(Sender: TObject);
269begin
270 EdcProject.SaveToFile(ProjectFileName);
271end;
272
273procedure TFormMain.TabSheetOverviewShow(Sender: TObject);
274begin
275 ReloadListViewOverview;
276end;
277
278procedure TFormMain.TabSheetChartShow(Sender: TObject);
279begin
280 EdcProject.Eans.LoadToStrings(ComboBoxEan.Items, True);
281 if (ComboBoxEan.Items.Count > 1) and (ComboBoxEan.ItemIndex = -1) then
282 ComboBoxEan.ItemIndex := 1;
283 EdcProject.Eans.LoadToStrings(ComboBoxEan2.Items, True);
284 EdcProject.Eans.LoadToStrings(ComboBoxEan3.Items, True);
285 ReloadChart;
286end;
287
288procedure TFormMain.TabSheetDataShow(Sender: TObject);
289begin
290 EdcProject.Eans.LoadToStrings(ComboBoxEanData.Items);
291 if (ComboBoxEanData.Items.Count > 0) and (ComboBoxEanData.ItemIndex = -1) then
292 ComboBoxEanData.ItemIndex := 0;
293 ReloadListViewData;
294end;
295
296procedure TFormMain.TabSheetLogShow(Sender: TObject);
297begin
298 Report;
299end;
300
301procedure TFormMain.TabSheetSpotPricesShow(Sender: TObject);
302begin
303 ReloadListViewSpotPrices;
304end;
305
306procedure TFormMain.TimeEdit1Change(Sender: TObject);
307var
308 NewIntervalTo: TDateTime;
309begin
310 NEwIntervalTo := DateOf(IntervalTo) + TimeEdit1.Time;
311 if NewIntervalTo <> IntervalTo then begin
312 IntervalTo := NewIntervalTo;
313 UpdateInterval;
314 end;
315end;
316
317procedure TFormMain.Translator1Translate(Sender: TObject);
318begin
319 ComboBoxPeriod.Items[Integer(prDay)] := SDay;
320 ComboBoxPeriod.Items[Integer(prWeek)] := SWeek;
321 ComboBoxPeriod.Items[Integer(prMonth)] := SMonth;
322 ComboBoxPeriod.Items[Integer(prYear)] := SYear;
323 Ean.Translate;
324end;
325
326function TFormMain.MeasureToFloat(Value: Double; Interval: Double): Double;
327begin
328 case ValueUnit of
329 vukWh: Result := Value;
330 vuWh: Result := Value * 1000;
331 vukW: Result := Value / Interval;
332 vuW: Result := Value / Interval * 1000;
333 else Result := 0;
334 end;
335end;
336
337function TFormMain.MeasureToStr(Value: Double): string;
338begin
339 Result := CurrToStr(MeasureToFloat(Value, GetIntervalLength * 24));
340end;
341
342procedure TFormMain.Report;
343var
344 I: Integer;
345 TotalIn, TotalOut: Double;
346begin
347 Memo1.Lines.BeginUpdate;
348 try
349 Memo1.Lines.Clear;
350 for I := 0 to EdcProject.Eans.Count - 1 do
351 with EdcProject.Eans[I] do begin
352 Memo1.Lines.Add(SEAN + ': ' + Number);
353 Memo1.Lines.Add(SOwner + ': ' + Owner);
354 TotalIn := GetTotalIn(IntervalFrom, IntervalTo);
355 TotalOut := GetTotalOut(IntervalFrom, IntervalTo);
356 Memo1.Lines.Add(SMeasured + ': ' + IntToStr(Trunc(TotalIn)));
357 Memo1.Lines.Add(SResult + ': ' + IntToStr(Trunc(TotalOut)));
358 if TotalIn <> 0 then
359 Memo1.Lines.Add(SShared + ': ' + IntToStr(Trunc(GetSharedPercent(IntervalFrom, IntervalTo))) + ' %');
360 Memo1.Lines.Add('');
361 end;
362 finally
363 Memo1.Lines.EndUpdate;
364 end;
365end;
366
367procedure TFormMain.ReloadListViewOverview;
368var
369 ListItem: TListItem;
370 I: Integer;
371begin
372 ListViewOverview.BeginUpdate;
373 try
374 ListViewOverview.Items.Clear;
375 for I := 0 to EdcProject.Eans.Count - 1 do
376 with EdcProject.Eans[I] do begin
377 ListItem := ListViewOverview.Items.Add;
378 ListItem.Caption := Number;
379 ListItem.Data := EdcProject.Eans[I];
380 ListItem.SubItems.Add(Owner);
381 ListItem.SubItems.Add(Address);
382 ListItem.SubItems.Add(EanKindText[Kind]);
383 ListItem.SubItems.Add(MeasureToStr(GetTotalIn(IntervalFrom, IntervalTo)));
384 ListItem.SubItems.Add(MeasureToStr(GetShared(IntervalFrom, IntervalTo)));
385 ListItem.SubItems.Add(IntToStr(Trunc(GetSharedPercent(IntervalFrom, IntervalTo))));
386 ListItem.SubItems.Add(FloatToStr(PriceLow));
387 ListItem.SubItems.Add(FloatToStr(PriceHigh));
388 ListItem.SubItems.Add(FloatToStr(PriceSpot));
389 ListItem.SubItems.Add(CurrToStr(GetPrice(IntervalFrom, IntervalTo, EdcProject.SpotPrices, Low(Integer))));
390 ListItem.SubItems.Add(CurrToStr(GetSavings(IntervalFrom, IntervalTo, EdcProject.SpotPrices)));
391 ListItem.SubItems.Add(DistributionTariff);
392 ListItem.SubItems.Add(CurrToStr(GetPrice(IntervalFrom, IntervalTo, EdcProject.SpotPrices, 0)));
393 end;
394 finally
395 ListViewOverview.EndUpdate;
396 end;
397end;
398
399procedure TFormMain.ReloadListViewData;
400var
401 ListItem: TListItem;
402 I: Integer;
403 Ean: TEan;
404begin
405 ListViewData.Items.Clear;
406 if ComboBoxEanData.ItemIndex = -1 then Exit;
407 Ean := TEan(ComboBoxEanData.Items.Objects[ComboBoxEanData.ItemIndex]);
408
409 if Assigned(Ean) then begin
410 ListViewData.BeginUpdate;
411 try
412 for I := 0 to Ean.Values.Count - 1 do
413 with Ean.Values[I] do
414 if (Time >= IntervalFrom) and (Time < IntervalTo) then begin
415 ListItem := ListViewData.Items.Add;
416 ListItem.Caption := DateTimeToStr(Time);
417 ListItem.SubItems.Add(FloatToStr(ValueIn));
418 ListItem.SubItems.Add(FloatToStr(ValueOut));
419 ListItem.SubItems.Add(IntToStr(Trunc(GetShared)));
420 end;
421 finally
422 ListViewData.EndUpdate;
423 end;
424 end;
425end;
426
427procedure TFormMain.ReloadListViewSpotPrices;
428var
429 ListItem: TListItem;
430 I: Integer;
431begin
432 ListViewSpotPrices.Items.Clear;
433
434 ListViewSpotPrices.BeginUpdate;
435 try
436 for I := 0 to EdcProject.SpotPrices.Count - 1 do
437 with EdcProject.SpotPrices[I] do
438 if (Time >= IntervalFrom) and (Time < IntervalTo) then
439 begin
440 ListItem := ListViewSpotPrices.Items.Add;
441 ListItem.Caption := DateTimeToStr(Time);
442 ListItem.SubItems.Add(FloatToStr(Value));
443 end;
444 finally
445 ListViewSpotPrices.EndUpdate;
446 end;
447end;
448
449procedure TFormMain.ReloadChart;
450var
451 I: Integer;
452 Ean: TEan;
453begin
454 Chart1LineSeries1.BeginUpdate;
455 Chart1LineSeries4.BeginUpdate;
456 Chart1LineSeries1.Clear;
457 Chart1LineSeries4.Clear;
458 if ComboBoxEan.ItemIndex <> -1 then begin
459 Ean := TEan(ComboBoxEan.Items.Objects[ComboBoxEan.ItemIndex]);
460 if Assigned(Ean) then
461 with Ean do begin
462 for I := 0 to Values.Count - 1 do
463 if (Values[I].Time >= IntervalFrom) and (Values[I].Time < IntervalTo) then begin
464 Chart1LineSeries1.AddXY(Values[I].Time, MeasureToFloat(Values[I].ValueIn, 1 / 4));
465 if ShowResult then Chart1LineSeries4.AddXY(Values[I].Time, MeasureToFloat(Values[I].ValueOut, 1 / 4));
466 end;
467 end;
468 end;
469 Chart1LineSeries1.EndUpdate;
470 Chart1LineSeries4.EndUpdate;
471
472 Chart1LineSeries2.BeginUpdate;
473 Chart1LineSeries5.BeginUpdate;
474 Chart1LineSeries2.Clear;
475 Chart1LineSeries5.Clear;
476 if ComboBoxEan2.ItemIndex <> -1 then begin
477 Ean := TEan(ComboBoxEan2.Items.Objects[ComboBoxEan2.ItemIndex]);
478 if Assigned(Ean) then
479 with Ean do begin
480 for I := 0 to Values.Count - 1 do
481 if (Values[I].Time >= IntervalFrom) and (Values[I].Time < IntervalTo) then begin
482 Chart1LineSeries2.AddXY(Values[I].Time, MeasureToFloat(Values[I].ValueIn, 1 / 4));
483 if ShowResult then Chart1LineSeries5.AddXY(Values[I].Time, MeasureToFloat(Values[I].ValueOut, 1 / 4));
484 end;
485 end;
486 end;
487 Chart1LineSeries2.EndUpdate;
488 Chart1LineSeries5.EndUpdate;
489
490 Chart1LineSeries3.BeginUpdate;
491 Chart1LineSeries6.BeginUpdate;
492 Chart1LineSeries3.Clear;
493 Chart1LineSeries6.Clear;
494 if ComboBoxEan3.ItemIndex <> -1 then begin
495 Ean := TEan(ComboBoxEan3.Items.Objects[ComboBoxEan3.ItemIndex]);
496 if Assigned(Ean) then
497 with Ean do begin
498 for I := 0 to Values.Count - 1 do
499 if (Values[I].Time >= IntervalFrom) and (Values[I].Time < IntervalTo) then begin
500 Chart1LineSeries3.AddXY(Values[I].Time, MeasureToFloat(Values[I].ValueIn, 1 / 4));
501 if ShowResult then Chart1LineSeries6.AddXY(Values[I].Time, MeasureToFloat(Values[I].ValueOut, 1 / 4));
502 end;
503 end;
504 end;
505 Chart1LineSeries3.EndUpdate;
506 Chart1LineSeries6.EndUpdate;
507end;
508
509function TFormMain.GetIntervalLength: TDateTime;
510begin
511 case Period of
512 prDay: Result := 1;
513 prWeek: Result := 7;
514 prMonth: Result := 31;
515 prYear: Result := 365;
516 end;
517end;
518
519function TFormMain.GetIntervalStep: TDateTime;
520begin
521 case Period of
522 prDay: Result := FifteenMinute;
523 prWeek: Result := 1;
524 prMonth: Result := 1;
525 prYear: Result := 30;
526 end;
527end;
528
529procedure TFormMain.UpdateInterface;
530begin
531 ComboBoxUnit.ItemIndex := Integer(ValueUnit);
532 ComboBoxPeriod.ItemIndex := Integer(Period);
533 CheckBoxShowResult.Checked := ShowResult;
534end;
535
536procedure TFormMain.UpdateInterval;
537begin
538 IntervalFrom := IntervalTo - GetIntervalLength;
539 DateEdit1.Date := IntervalTo;
540 TimeEdit1.Time := IntervalTo;
541 ShowActiveTab;
542end;
543
544procedure TFormMain.ShowActiveTab;
545begin
546 if Assigned(PageControl1.ActivePage.OnShow) then
547 PageControl1.ActivePage.OnShow(nil);
548end;
549
550procedure TFormMain.LoadConfig;
551begin
552 PersistentForm1.RegistryContext := ApplicationInfo1.GetRegistryContext;
553
554 with TRegistryEx.Create do
555 try
556 CurrentContext := ApplicationInfo1.GetRegistryContext;
557 if ValueExists('LanguageCode') then
558 Translator1.Language := Translator1.Languages.SearchByCode(ReadStringWithDefault('LanguageCode', ''))
559 else Translator1.Language := Translator1.Languages.SearchByCode('');
560 if ValueExists('Theme') then
561 ThemeManager1.Theme := ThemeManager1.Themes.FindByName(ReadStringWithDefault('Theme', 'System'))
562 else ThemeManager1.Theme := ThemeManager1.Themes.FindByName('System');
563 ValueUnit := TValueUnit(ReadIntegerWithDefault('Unit', Integer(ValueUnit)));
564 Period := TPeriod(ReadIntegerWithDefault('Period', Integer(Period)));
565 ReportsDir := ReadStringWithDefault('ReportsDir', ReportsDir);
566 SpotPricesDir := ReadStringWithDefault('SpotPricesDir', SpotPricesDir);
567 ProjectFileName := ReadStringWithDefault('ProjectFileName', ProjectFileName);
568 PageControl1.TabIndex := ReadIntegerWithDefault('ActiveTab', PageControl1.TabIndex);
569 ShowResult := ReadBoolWithDefault('ShowResult', ShowResult);
570 IntervalFrom := ReadDateTimeWithDefault('IntervalFrom', IntervalFrom);
571 IntervalTo := ReadDateTimeWithDefault('IntervalTo', IntervalTo);
572 finally
573 Free;
574 end;
575end;
576
577procedure TFormMain.SaveConfig;
578begin
579 with TRegistryEx.Create do
580 try
581 CurrentContext := ApplicationInfo1.GetRegistryContext;
582 if Assigned(Translator1.Language) and (Translator1.Language.Code <> '') then
583 WriteString('LanguageCode', Translator1.Language.Code)
584 else DeleteValue('LanguageCode');
585 if Assigned(ThemeManager1.Theme) and (ThemeManager1.Theme.Name <> '') then
586 WriteString('Theme', ThemeManager1.Theme.Name)
587 else DeleteValue('Theme');
588 WriteInteger('Unit', Integer(ValueUnit));
589 WriteInteger('Period', Integer(Period));
590 WriteString('ReportsDir', ReportsDir);
591 WriteString('SpotPricesDir', SpotPricesDir);
592 WriteString('ProjectFileName', ProjectFileName);
593 WriteInteger('ActiveTab', PageControl1.TabIndex);
594 WriteBool('ShowResult', ShowResult);
595 WriteDateTime('IntervalFrom', IntervalFrom);
596 WriteDateTime('IntervalTo', IntervalTo);
597 finally
598 Free;
599 end;
600end;
601
602end.
603
Note: See TracBrowser for help on using the repository browser.