source: Registry/UGeneralRegistry.pas

Last change on this file was 539, checked in by chronos, 5 years ago
  • Added: Allow to add, edit and delete registry values.
File size: 20.6 KB
Line 
1unit UGeneralRegistry;
2
3{$mode delphi}{$H+}
4
5interface
6
7uses
8 Classes, SysUtils, IniFiles, XMLRead, XMLWrite, DOM, Registry;
9
10type
11 TRegistryRoot = (rrUnknown, rrApplicationUser, rrApplicationGlobal,
12 rrSystemUser, rrSystemGlobal);
13
14 TRegKeyInfo = record
15 NumberSubKeys: Integer;
16 MaxSubKeyLength: Integer;
17 NumberValues: Integer;
18 MaxValueLength: Integer;
19 MaxDataLength: Integer;
20 CreationTime: TDateTime;
21 ModificationTime: TDateTime;
22 end;
23
24 TRegValueType = (vtUnknown, vtInteger, vtString, vtBinary, vtFloat, vtBoolean,
25 vtText);
26
27 TRegValueInfo = record
28 ValueType: TRegValueType;
29 Size: Integer;
30 end;
31
32 TRegKey = record
33 Root: NativeInt;
34 Path: string;
35 end;
36
37 { TBaseRegistry }
38
39 TBaseRegistry = class
40 private
41 protected
42 FCurrentRoot: NativeInt;
43 FCurrentKey: string;
44 procedure SetCurrentKey(const AValue: string); virtual; abstract;
45 procedure SetCurrentRoot(const AValue: NativeInt); virtual; abstract;
46 public
47 function KeyExists(const Name: string): Boolean; virtual; abstract;
48 function ValueExists(const Name: string): Boolean; virtual; abstract;
49 function GetKeyInfo(var Value: TRegKeyInfo): Boolean; virtual; abstract;
50 function GetValueInfo(const Name: string; var Value: TRegValueInfo): Boolean; virtual; abstract;
51 function GetValueType(const Name: string): TRegValueType; virtual; abstract;
52 function GetValueSize(const Name: string): Integer; virtual; abstract;
53 function OpenKey(const Key: string; CreateNew: Boolean): Boolean; virtual; abstract;
54 procedure CloseKey; virtual; abstract;
55 function DeleteKey(const Name: string; Recursive: Boolean = False): Boolean; virtual; abstract;
56 function DeleteValue(const Name: string): Boolean; virtual; abstract;
57 function RenameValue(const OldName, NewName: string): Boolean; virtual; abstract;
58 function ReadBool(const Name: string): Boolean; virtual; abstract;
59 function ReadDateTime(const Name: string): TDateTime; virtual; abstract;
60 function ReadFloat(const Name: string): Double; virtual; abstract;
61 function ReadInteger(const Name: string): Integer; virtual; abstract;
62 function ReadString(const Name: string): string; virtual; abstract;
63 function ReadBinaryData(const Name: string; var Buffer; BufSize: Integer): Integer; virtual; abstract;
64 procedure WriteBool(const Name: string; Value: Boolean); virtual; abstract;
65 procedure WriteDateTime(const Name: string; Value: TDateTime); virtual; abstract;
66 procedure WriteFloat(const Name: string; Value: Double); virtual; abstract;
67 procedure WriteInteger(const Name: string; Value: Integer); virtual; abstract;
68 procedure WriteString(const Name: string; Value: string); virtual; abstract;
69 procedure WriteBinaryData(const Name: string; var Buffer; BufSize: Integer); virtual; abstract;
70 function HasSubKeys: Boolean; virtual; abstract;
71 procedure GetKeyNames(Strings: TStrings); virtual; abstract;
72 procedure GetValueNames(Strings: TStrings); virtual; abstract;
73 property CurrentRoot: NativeInt read FCurrentRoot write SetCurrentRoot;
74 property CurrentKey: string read FCurrentKey write SetCurrentKey;
75 end;
76
77 EBackendNotDefined = class(Exception);
78
79 { TGeneralRegistry }
80
81 TGeneralRegistry = class(TComponent)
82 private
83 FBackend: TBaseRegistry;
84 procedure CheckBackend; inline;
85 function GetCurrentKey: string;
86 function GetCurrentRoot: NativeInt;
87 procedure SetBackend(const AValue: TBaseRegistry);
88 procedure SetCurrentKey(const AValue: string);
89 procedure SetCurrentRoot(const AValue: NativeInt);
90 public
91 constructor Create(AOwner: TComponent); override;
92 destructor Destroy; override;
93 procedure CloseKey;
94 function KeyExists(const Name: string): Boolean;
95 function ValueExists(const Name: string): Boolean;
96 function DeleteKey(const Name: string; Recursive: Boolean = False): Boolean;
97 function DeleteValue(const Name: string): Boolean;
98 function RenameValue(const OldName, NewName: string): Boolean;
99 function GetKeyInfo(out Value: TRegKeyInfo): Boolean;
100 function GetValueInfo(const Name: string; out Value: TRegValueInfo): Boolean;
101 function GetValueType(const Name: string): TRegValueType;
102 function GetValueSize(const Name: string): Integer;
103 function OpenKey(const Key: string; CreateNew: Boolean): Boolean;
104 function ReadBool(const Name: string): Boolean;
105 function ReadDateTime(const Name: string): TDateTime;
106 function ReadFloat(const Name: string): Double;
107 function ReadInteger(const Name: string): Integer;
108 function ReadString(const Name: string): string;
109 function ReadBinaryData(const Name: string; var Buffer; BufSize: Integer): Integer;
110 function ReadBoolDefault(const Name: string; const DefaultValue: Boolean): Boolean;
111 function ReadDateTimeDefault(const Name: string; const DefaultValue: TDateTime): TDateTime;
112 function ReadFloatDefault(const Name: string; const DefaultValue: Double): Double;
113 function ReadIntegerDefault(const Name: string; const DefaultValue: Integer): Integer;
114 function ReadStringDefault(const Name: string; const DefaultValue: string): string;
115 procedure WriteBool(const Name: string; Value: Boolean);
116 procedure WriteDateTime(const Name: string; Value: TDateTime);
117 procedure WriteFloat(const Name: string; Value: Double);
118 procedure WriteInteger(const Name: string; Value: Integer);
119 procedure WriteString(const Name: string; Value: string);
120 procedure WriteBinaryData(const Name: string; var Buffer; BufSize: Integer);
121 function HasSubKeys: Boolean;
122 procedure GetKeyNames(Strings: TStrings);
123 procedure GetValueNames(Strings: TStrings);
124 property Backend: TBaseRegistry read FBackend write SetBackend;
125 property CurrentRoot: NativeInt read GetCurrentRoot write SetCurrentRoot;
126 property CurrentKey: string read GetCurrentKey write SetCurrentKey;
127 end;
128
129 { TXMLRegistry }
130
131 TXMLRegistry = class(TBaseRegistry)
132 XMLDocument: TXMLDocument;
133 function OpenKey(const Key: string; CreateNew: Boolean): Boolean; override;
134 constructor Create;
135 destructor Destroy; override;
136 end;
137
138 { TIniRegistry }
139
140 TIniRegistry = class(TBaseRegistry)
141 IniFile: TIniFile;
142 constructor Create;
143 destructor Destroy; override;
144 end;
145
146 TMemoryRegistry = class(TBaseRegistry)
147 end;
148
149 { TWinRegistry }
150
151 TWinRegistry = class(TBaseRegistry)
152 protected
153 procedure SetCurrentKey(const AValue: string); override;
154 procedure SetCurrentRoot(const AValue: NativeInt); override;
155 public
156 BasePath: string;
157 Registry: TRegistry;
158 function KeyExists(const Name: string): Boolean; override;
159 function ValueExists(const Name: string): Boolean; override;
160 function GetKeyInfo(var Value: TRegKeyInfo): Boolean; override;
161 function GetValueInfo(const Name: string; var Value: TRegValueInfo): Boolean; override;
162 function GetValueType(const Name: string): TRegValueType; override;
163 function GetValueSize(const Name: string): Integer; override;
164 function OpenKey(const Key: string; CreateNew: Boolean): Boolean; override;
165 procedure CloseKey; override;
166 function DeleteKey(const Name: string; Recursive: Boolean = False): Boolean; override;
167 function DeleteValue(const Name: string): Boolean; override;
168 function RenameValue(const OldName, NewName: string): Boolean; override;
169 function ReadBool(const Name: string): Boolean; override;
170 function ReadDateTime(const Name: string): TDateTime; override;
171 function ReadFloat(const Name: string): Double; override;
172 function ReadInteger(const Name: string): Integer; override;
173 function ReadString(const Name: string): string; override;
174 function ReadBinaryData(const Name: string; var Buffer; BufSize: Integer): Integer; override;
175 procedure WriteBool(const Name: string; Value: Boolean); override;
176 procedure WriteDateTime(const Name: string; Value: TDateTime); override;
177 procedure WriteFloat(const Name: string; Value: Double); override;
178 procedure WriteInteger(const Name: string; Value: Integer); override;
179 procedure WriteString(const Name: string; Value: string); override;
180 procedure WriteBinaryData(const Name: string; var Buffer; BufSize: Integer); override;
181 function HasSubKeys: Boolean; override;
182 procedure GetKeyNames(Strings: TStrings); override;
183 procedure GetValueNames(Strings: TStrings); override;
184 constructor Create;
185 destructor Destroy; override;
186 end;
187
188const
189 RegValueTypeName: array[TRegValueType] of string = ('Unknown', 'Integer', 'String',
190 'Binary', 'Float', 'Boolean', 'Text');
191
192procedure Register;
193
194
195implementation
196
197resourcestring
198 SBackendNotDefined = 'Backend not defined';
199
200procedure Register;
201begin
202 RegisterComponents('Samples', [TGeneralRegistry]);
203end;
204
205{ TWinRegistry }
206
207procedure TWinRegistry.SetCurrentKey(const AValue: string);
208begin
209 if FCurrentKey = AValue then Exit;
210 OpenKey(AValue, False);
211end;
212
213procedure TWinRegistry.SetCurrentRoot(const AValue: NativeInt);
214begin
215 if FCurrentRoot = AValue then Exit;
216 FCurrentRoot := AValue;
217 if AValue = Integer(rrApplicationUser) then begin
218 Registry.RootKey := HKEY_CURRENT_USER;
219 BasePath := '\Software\Company\Product';
220 end;
221 if AValue = Integer(rrApplicationGlobal) then begin
222 Registry.RootKey := HKEY_LOCAL_MACHINE;
223 BasePath := '\Software\Company\Product';
224 end;
225end;
226
227function TWinRegistry.KeyExists(const Name: string): Boolean;
228begin
229 Result := Registry.KeyExists(Name);
230end;
231
232function TWinRegistry.ValueExists(const Name: string): Boolean;
233begin
234 Result := Registry.ValueExists(Name);
235end;
236
237function TWinRegistry.GetKeyInfo(var Value: TRegKeyInfo): Boolean;
238var
239 KeyInfo: Registry.TRegKeyInfo;
240begin
241 Result := Registry.GetKeyInfo(KeyInfo);
242 if Result then begin
243 Value.CreationTime := KeyInfo.FileTime;
244 Value.ModificationTime := KeyInfo.FileTime;
245 Value.MaxDataLength := KeyInfo.MaxDataLen;
246 Value.MaxSubKeyLength := KeyInfo.MaxSubKeyLen;
247 Value.MaxValueLength := KeyInfo.MaxValueLen;
248 Value.NumberSubKeys := KeyInfo.NumSubKeys;
249 Value.NumberValues := KeyInfo.NumValues;
250 end;
251end;
252
253function TWinRegistry.GetValueInfo(const Name: string; var Value: TRegValueInfo): Boolean;
254var
255 ValueInfo: Registry.TRegDataInfo;
256begin
257 Result := Registry.GetDataInfo(Name, ValueInfo);
258 if Result then begin
259 Value.Size := ValueInfo.DataSize;
260 case ValueInfo.RegData of
261 rdUnknown: Value.ValueType := vtUnknown;
262 rdString: Value.ValueType := vtString;
263 rdExpandString: Value.ValueType := vtText;
264 rdBinary: Value.ValueType := vtBinary;
265 rdInteger: Value.ValueType := vtInteger;
266 end;
267 end;
268end;
269
270function TWinRegistry.GetValueType(const Name: string): TRegValueType;
271var
272 ValueInfo: TRegValueInfo;
273begin
274 if GetValueInfo(Name, ValueInfo) then
275 Result := ValueInfo.ValueType else Result := vtUnknown;
276end;
277
278function TWinRegistry.GetValueSize(const Name: string): Integer;
279begin
280 Result := Registry.GetDataSize(Name);
281end;
282
283function TWinRegistry.OpenKey(const Key: string; CreateNew: Boolean): Boolean;
284begin
285 Result := Registry.OpenKey(Key, CreateNew);
286 FCurrentKey := Key;
287end;
288
289procedure TWinRegistry.CloseKey;
290begin
291 Registry.CloseKey;
292end;
293
294function TWinRegistry.DeleteKey(const Name: string; Recursive: Boolean
295 ): Boolean;
296var
297 SubKeys: TStringList;
298 I: Integer;
299begin
300 try
301 SubKeys := TStringList.Create;
302 if Recursive and OpenKey(Name, False) and HasSubKeys then begin
303 GetKeyNames(SubKeys);
304 for I := 0 to SubKeys.Count - 1 do
305 DeleteKey(Name + '\' + SubKeys[I], True);
306 end;
307 Result := Registry.DeleteKey(Name);
308 finally
309 SubKeys.Free;
310 end;
311end;
312
313function TWinRegistry.DeleteValue(const Name: string): Boolean;
314begin
315 Result := Registry.DeleteValue(Name);
316end;
317
318function TWinRegistry.RenameValue(const OldName, NewName: string): Boolean;
319begin
320 Result := True;
321 Registry.RenameValue(OldName, NewName);
322end;
323
324function TWinRegistry.ReadBool(const Name: string): Boolean;
325begin
326 Result := Registry.ReadBool(Name);
327end;
328
329function TWinRegistry.ReadDateTime(const Name: string): TDateTime;
330begin
331 Result := Registry.ReadDateTime(Name);
332end;
333
334function TWinRegistry.ReadFloat(const Name: string): Double;
335begin
336 Result := Registry.ReadFloat(Name);
337end;
338
339function TWinRegistry.ReadInteger(const Name: string): Integer;
340begin
341 Result := Registry.ReadInteger(Name);
342end;
343
344function TWinRegistry.ReadString(const Name: string): string;
345begin
346 Result := Registry.ReadString(Name);
347end;
348
349function TWinRegistry.ReadBinaryData(const Name: string; var Buffer;
350 BufSize: Integer): Integer;
351begin
352 Result := Registry.ReadBinaryData(Name, Buffer, BufSize);
353end;
354
355procedure TWinRegistry.WriteBool(const Name: string; Value: Boolean);
356begin
357 Registry.WriteBool(Name, Value);
358end;
359
360procedure TWinRegistry.WriteDateTime(const Name: string; Value: TDateTime);
361begin
362 Registry.WriteDateTime(Name, Value);
363end;
364
365procedure TWinRegistry.WriteFloat(const Name: string; Value: Double);
366begin
367 Registry.WriteFloat(Name, Value);
368end;
369
370procedure TWinRegistry.WriteInteger(const Name: string; Value: Integer);
371begin
372 Registry.WriteInteger(Name, Value);
373end;
374
375procedure TWinRegistry.WriteString(const Name: string; Value: string);
376begin
377 Registry.WriteString(Name, Value);
378end;
379
380procedure TWinRegistry.WriteBinaryData(const Name: string; var Buffer;
381 BufSize: Integer);
382begin
383 Registry.WriteBinaryData(Name, Buffer, BufSize);
384end;
385
386function TWinRegistry.HasSubKeys: Boolean;
387begin
388 Result := Registry.HasSubKeys;
389end;
390
391procedure TWinRegistry.GetKeyNames(Strings: TStrings);
392var
393 I: Integer;
394begin
395 Registry.GetKeyNames(Strings);
396// for I := 0 to Strings.Count - 1 do
397// Strings[I] := AnsiToUtf8(Strings[I]);
398end;
399
400procedure TWinRegistry.GetValueNames(Strings: TStrings);
401begin
402 Registry.GetValueNames(Strings);
403end;
404
405constructor TWinRegistry.Create;
406begin
407 Registry := TRegistry.Create;
408end;
409
410destructor TWinRegistry.Destroy;
411begin
412 Registry.Free;
413 inherited Destroy;
414end;
415
416{ TIniRegistry }
417
418constructor TIniRegistry.Create;
419begin
420 //IniFile := TIniFile.Create;
421end;
422
423destructor TIniRegistry.Destroy;
424begin
425 //IniFile.Free;
426 inherited Destroy;
427end;
428
429{ TXMLRegistry }
430
431function TXMLRegistry.OpenKey(const Key: string; CreateNew: Boolean): Boolean;
432begin
433
434end;
435
436constructor TXMLRegistry.Create;
437begin
438 XMLDocument := TXMLDocument.Create;
439end;
440
441destructor TXMLRegistry.Destroy;
442begin
443 XMLDocument.Free;
444 inherited Destroy;
445end;
446
447{ TGeneralRegistry }
448
449procedure TGeneralRegistry.CheckBackend;
450begin
451 if not Assigned(Backend) then
452 raise EBackendNotDefined.Create(SBackendNotDefined);
453end;
454
455function TGeneralRegistry.GetCurrentKey: string;
456begin
457 CheckBackend;
458 Result := Backend.CurrentKey;
459end;
460
461function TGeneralRegistry.GetCurrentRoot: NativeInt;
462begin
463 CheckBackend;
464 Result := Backend.CurrentRoot;
465end;
466
467procedure TGeneralRegistry.SetBackend(const AValue: TBaseRegistry);
468begin
469 if FBackend = AValue then Exit;
470 if Assigned(FBackend) then FreeAndNil(FBackend);
471 FBackend := AValue;
472end;
473
474procedure TGeneralRegistry.SetCurrentKey(const AValue: string);
475begin
476 CheckBackend;
477 Backend.CurrentKey := AValue;
478end;
479
480procedure TGeneralRegistry.SetCurrentRoot(const AValue: NativeInt);
481begin
482 CheckBackend;
483 Backend.CurrentRoot := AValue;
484end;
485
486procedure TGeneralRegistry.CloseKey;
487begin
488 CheckBackend;
489 Backend.CloseKey;
490end;
491
492function TGeneralRegistry.KeyExists(const Name: string): Boolean;
493begin
494 CheckBackend;
495 Result := Backend.KeyExists(Name);
496end;
497
498function TGeneralRegistry.ValueExists(const Name: string): Boolean;
499begin
500 CheckBackend;
501 Result := Backend.ValueExists(Name);
502end;
503
504function TGeneralRegistry.DeleteValue(const Name: string): Boolean;
505begin
506 CheckBackend;
507 Result := Backend.DeleteValue(Name);
508end;
509
510function TGeneralRegistry.RenameValue(const OldName, NewName: string): Boolean;
511begin
512 CheckBackend;
513 Result := Backend.RenameValue(OldName, NewName);
514end;
515
516function TGeneralRegistry.GetKeyInfo(out Value: TRegKeyInfo): Boolean;
517begin
518 CheckBackend;
519 Result := Backend.GetKeyInfo(Value);
520end;
521
522function TGeneralRegistry.GetValueInfo(const Name: string; out Value: TRegValueInfo): Boolean;
523begin
524 CheckBackend;
525 Result := Backend.GetValueInfo(Name, Value);
526end;
527
528function TGeneralRegistry.GetValueType(const Name: string): TRegValueType;
529begin
530 CheckBackend;
531 Result := Backend.GetValueType(Name);
532end;
533
534function TGeneralRegistry.GetValueSize(const Name: string): Integer;
535begin
536 CheckBackend;
537 Result := Backend.GetValueSize(Name);
538end;
539
540function TGeneralRegistry.DeleteKey(const Name: string; Recursive: Boolean = False): Boolean;
541begin
542 CheckBackend;
543 Result := Backend.DeleteKey(Name, Recursive);
544end;
545
546function TGeneralRegistry.OpenKey(const Key: string; CreateNew: Boolean): Boolean;
547begin
548 CheckBackend;
549 Result := Backend.OpenKey(Key, CreateNew);
550end;
551
552function TGeneralRegistry.ReadBool(const Name: string): Boolean;
553begin
554 CheckBackend;
555 Result := Backend.ReadBool(Name);
556end;
557
558function TGeneralRegistry.ReadDateTime(const Name: string): TDateTime;
559begin
560 CheckBackend;
561 Result := Backend.ReadDateTime(Name);
562end;
563
564function TGeneralRegistry.ReadFloat(const Name: string): Double;
565begin
566 CheckBackend;
567 Result := Backend.ReadFloat(Name);
568end;
569
570function TGeneralRegistry.ReadInteger(const Name: string): Integer;
571begin
572 CheckBackend;
573 Result := Backend.ReadInteger(Name);
574end;
575
576function TGeneralRegistry.ReadString(const Name: string): string;
577begin
578 CheckBackend;
579 Result := Backend.ReadString(Name);
580end;
581
582function TGeneralRegistry.ReadBinaryData(const Name: string; var Buffer;
583 BufSize: Integer): Integer;
584begin
585 CheckBackend;
586 Result := Backend.ReadBinaryData(Name, Buffer, BufSize);
587end;
588
589function TGeneralRegistry.ReadBoolDefault(const Name: string;
590 const DefaultValue: Boolean): Boolean;
591begin
592 if ValueExists(Name) then Result := ReadBool(Name)
593 else Result := DefaultValue;
594end;
595
596function TGeneralRegistry.ReadDateTimeDefault(const Name: string;
597 const DefaultValue: TDateTime): TDateTime;
598begin
599 if ValueExists(Name) then Result := ReadDateTime(Name)
600 else Result := DefaultValue;
601end;
602
603function TGeneralRegistry.ReadFloatDefault(const Name: string;
604 const DefaultValue: Double): Double;
605begin
606 if ValueExists(Name) then Result := ReadFloat(Name)
607 else Result := DefaultValue;
608end;
609
610function TGeneralRegistry.ReadIntegerDefault(const Name: string;
611 const DefaultValue: Integer): Integer;
612begin
613 if ValueExists(Name) then Result := ReadInteger(Name)
614 else Result := DefaultValue;
615end;
616
617function TGeneralRegistry.ReadStringDefault(const Name: string;
618 const DefaultValue: string): string;
619begin
620 if ValueExists(Name) then Result := ReadString(Name)
621 else Result := DefaultValue;
622end;
623
624procedure TGeneralRegistry.WriteBool(const Name: string; Value: Boolean);
625begin
626 CheckBackend;
627 Backend.WriteBool(Name, Value);
628end;
629
630procedure TGeneralRegistry.WriteDateTime(const Name: string; Value: TDateTime);
631begin
632 CheckBackend;
633 Backend.WriteDateTime(Name, Value);
634end;
635
636procedure TGeneralRegistry.WriteFloat(const Name: string; Value: Double);
637begin
638 CheckBackend;
639 Backend.WriteFloat(Name, Value);
640end;
641
642procedure TGeneralRegistry.WriteInteger(const Name: string; Value: Integer);
643begin
644 CheckBackend;
645 Backend.WriteInteger(Name, Value);
646end;
647
648procedure TGeneralRegistry.WriteString(const Name: string; Value: string);
649begin
650 CheckBackend;
651 Backend.WriteString(Name, Value);
652end;
653
654procedure TGeneralRegistry.WriteBinaryData(const Name: string; var Buffer;
655 BufSize: Integer);
656begin
657 CheckBackend;
658 Backend.WriteBinaryData(Name, Buffer, BufSize);
659end;
660
661function TGeneralRegistry.HasSubKeys: Boolean;
662begin
663 CheckBackend;
664 Result := Backend.HasSubKeys;
665end;
666
667procedure TGeneralRegistry.GetKeyNames(Strings: TStrings);
668begin
669 CheckBackend;
670 Backend.GetKeyNames(Strings);
671end;
672
673procedure TGeneralRegistry.GetValueNames(Strings: TStrings);
674begin
675 CheckBackend;
676 Backend.GetValueNames(Strings);
677end;
678
679constructor TGeneralRegistry.Create(AOwner: TComponent);
680begin
681 Backend := TWinRegistry.Create;
682 TWinRegistry(Backend).CurrentRoot := HKEY_CURRENT_USER;
683 TWinRegistry(Backend).CurrentKey := 'Software\Company\' +
684 ApplicationName;
685// TWinRegistry(Backend).CurrentKey := 'Software\' + VendorName + '\' +
686// ApplicationName;
687 inherited Create(AOwner);
688end;
689
690destructor TGeneralRegistry.Destroy;
691begin
692 if Assigned(Backend) then Backend.Free;
693 inherited Destroy;
694end;
695
696end.
697
Note: See TracBrowser for help on using the repository browser.