Web Design
Pascal

 

 

cpm-z80z180

Turbo Pascal 3.0

Listing of SPACE.PAS


1: 0 FUNCTION Freier_Diskettenplatz(Laufwerk:byte):integer;
2: 0 (* fuer CP/M + bzw. CP/M 3.0 und hoeher *)
3: 0 TYPE DMA_Puffer=RECORD

4: 1 Anzahl_der_Records_low:integer;

5: 1 Anzahl_der_Records_high:byte;

6: 1 Fueller:ARRAY[0..124] OF byte;

7: 1 END;

8: 0 VAR p:^DMA_Puffer;

9: 0 BEGIN

10: 1 new(p);

11: 1 bdos(26,ord(p));

12: 1 IF Laufwerk=O THEN Laufwerk:=bdos(25)+1;

13: 1 bdos(46,Laufwerk-1);

14: 1 Freier_Diskettenplatz:=p^.Anzahl_der_Records_low SHR 3
15: 1 +p^.Anzahl_der_Records_high SHL 13;
16: 1 dispose(p);

17: 1 END;

18: 0


19: 0 BEGIN

20: 1 write(Freier_Diskettenplatz(0));

21: 1 END.





8251 (z.B. TA-PC)

function ZeichenVorhanden:boolean;


begin

ZeichenVorhanden:=BIT(1,PORT[$41])


end;




funktion DarfSenden:boolean;


begin

DarfSenden:=BIT(0,PORT[$41])


end;




Z80-SIO (z.B. BONDWELL 14)

function ZeichenVorhanden:boolean;


begin

ZeichenVorhanden:=BIT(2,PORT[$41])


end;




function DarfSenden:boolean;


begin

DarfSenden:=BIT(0,PORT[$41])


end;





function ZeichenVorhanden:boolean;


begin

ZeichenVorhanden:=MEM[xyz]>0


end;

 
Listing of RS232.INC

1: 0 (****************************************************************************)

2: 0 (* Schnittstellen-Status *)

3: 0 (****************************************************************************)

4: 0

5: 0 FUNCTION BIT(Stelle,Zahl:byte):boolean;

6: 0 BEGIN

7: 1 BIT:=(Zahl AND (1 SHL Stelle))>0

8: 1 END;

9: 0

10: 0 FUNCTION ZeichenVorhanden : boolean; (*Computerabhaengig*)

11: 0 BEGIN

12: 1 ZeichenVorhanden:=(muss erst impementiert werden)

13: 1 END;

14: 0

15: 0 FUNCTION DarfSenden : boolean; (*Computerabhaengig*)

16: 0 BEGIN

17: 1 DarfSenden:=(muss erst implementiert werden)

18: 1 END;

 

Listing of MINIMOD.PAS

1: 0 (****************************************************************************)

2: 0 (* MINIMOD - einfache Datenfernuebertragung *)

3: 0 (****************************************************************************)

4. 0

5: 0 PROGRAM minimod;

6: 0

7: 0 CONST (*Initialier te Variable*)

8: 0 autolinefeed : boolean = true;

9: 0 echo : boolean = false;

10: 0 printer : boolean = false;

11: 0

12: 0 CONST (*kann bei Bedarf vergroesert werden*)

13: 0 UpLoadKap = 10000;

14: 0

15: 0 VAR ein, aus, c : char;

16: 0

17: 0 TYPE Pufferinhalt = char;

18: 0

19: 0 ($1 PUFFER.BIB)

20: 0 ($1 RS232.INC)

21: 0

22: 0 PROCEDURE Optionen; (*Gibt Options-Menue aus*)

23: 0 BEGIN

24: 1 lowvideo;

25: 1 writeln;

26: 1 writeln('^E = Echo umschalten');

27: 1 writeln('^A = AutoLF umschalten');

28: 1 writeln('^L = Drucker umschalten');

29: 1 writeln('^D = Download (File senden)');

30: 1 writeln('^U = Upload (File empfangen)');

31: 1 writeln('^S = Statusanzeige');

32: 1 IF NOT PufferLeer THEN writeln('^R = Pufferloeschen');

33: 1 writeln('^Z = Programmende');

34: 1 writelnCAP = ^12 senden');

35: 1 normvideo

36: 1 END;

37: 0

38: 0 PROCEDURE SchreibStatus; (*Gibt den Zustand der Flags aus*)

39: 0 CONST Status : ARRAY [boolean] OF STRING[3] = ('aus','ein');

40: 0 BEGIN

41: 1 writeln;

42: 1 writeln('Echo : ',Status[echo]);

43: 1 writeln('CRLF : ',Status[autolinefeed]);

44: 1 writeln('LST : ',Status[printer]);

45: 1 IF PufferLeer

46: 1 THEN writeln('Puffer leer')

47: 1 ELSE writeln('Zeichen in Puffer');

48: 1 writeln

49: 1 END;

50: 0

51: 0 PROCEDURE SendeZeichen(c : char); (*Schreibt ein Zeichen in den Sendepufer*)

52: 0 BEGIN

53: 1 SchreibInPuffer(c);

54: 1 IF c=#13

55: 1 THEN IF autolinefeed

56: 1 THEN SchreibInPuffer(#10);

57: 1 END;

58: 0

59: 0 PROCEDURE SchickeZeichen; (*Schickt ein Zeichen ber RS232, falls Sendepuffer nicht leer*)

60: 0 VAR c : char;

61: 0 BEGIN

62: 1 IF DarfSenden THEN

63: 1 IF NOT PufferLeer THEN

64: 1 BEGIN

65: 2 HolVonPuffer(c);

66: 2 write(AUX,c);

67: 2 IF echo THEN write(c);

68: 2 IF printer THEN write(LST,c);

69: 2 END

70: 1 END;

71: 0

72: 0 PROCEDURE upload; (*Schreibt alle empfangenen Zeichen in einen Puffer, der

73: 0 anschliessend abgespeichert werden kann*)

74: 0 VAR f : FILE; fn : STRING[14];

75: 0 z : integer;

76: 0 p : ARRAY[0..UpLoadKap] OF char;

77: 0 BEGIN

78: 1 fillchar(p,sizeof(p),AZ);

79: 1 writeln('Einlesen laeuft ! Ende mit ^Q');

80: 1 z:=0; lowvideo;

81: 1 REPEAT

82: 2 IF ZeichenVorhanden

83: 2 THEN BEGIN read(aux,ein); p[z]:=ein; write(ein); z:=succ(z) END;

84: 2 IF keypressed THEN

85: 2 BEGIN

86: 3 read(kbd,aus);

87: 3 CASE aus OF

88: 4 ^E : echo:=NOT echo;

89: 4 ^Q ;

90: 4 ^A : autolinefeed:=NOT autolinefeed;

91: 4 ^B : SchreibStatus

92: 4 ELSE SendeZeichen(aus)

93: 4 END (*case*)

94: 3 END;

95: 2 SchickeZeichen;

96: 2 UNTIL (aus=^Q) OR (z>UpLoadKap);

97: 1 normvideo;

98: 1 write('Name des Files (RETURN = nicht abspeichern) : '); readln(fn);

99: 1 IF fn<>" THEN

100: 1 BEGIN

101: 2 assign(f,fn);

102: 2 rewrite(f);

103: 2 blockwrite(f,p,(z MOD 128)+1);

104: 2 close(f);

105: 2 writeln('Abspeichern beendet.')

106: 2 END

107: 1 END;

108: 0

109: 0 PROCEDURE download; (*Sendet Diskettenf i le*)

110: 0 VAR f : text; fn : STRING[14]; c : char;

111: 0 BEGIN

112: 1 write('Name des zu sendenden Files : '); readln(fn);

113: 1 assign(f,fn);

114: 1 {$1-} reset(f)

115: 1 IF IOResult<>0

116: 1 THEN writeln('File existiert nicht!')

117: 1 ELSE WHILE NOT eof(f) DO

118: 1 BEGIN

119: 2 WHILE PufferVoll AND (NOT KeyPressed) DO SchickeZeichen;

120: 2 IF KeyPressed

121: 2 THEN BEGIN read(kbd,c); IF c="Z THEN exit END

122: 2 ELSE IF NOT PufferVoll

123: 2 THEN BEGIN read(f,c); SchreibInPuffer(c) END

124: 2 END;

125: 1 close(f)

126: 1 END;

127: 0

128: 0 BEGIN (*Hauptprogramm*)

129: 1 ClrScr; writeln('MINIMOD'); writeln;

130: 1 InitPuffer;

131: 1 REPEAT

132: 2 IF ZeichenVorhanden THEN

133: 2 BEGIN read(aux,ein); write(ein); IF printer THEN write(LST,ein) END;

134: 2 IF keypressed THEN

135: 2 BEGIN

136: 3 read(kbd,aus);

137: 3 IF aus=^P THEN

138: 3 BEGIN

139: 4 Optionen;

140: 4 read(kbd,aus);

141.- 4 CASE aus OF

142: 5 ^U : upload;

143: 5 ^D : download;

144: 5 ^L : printer:=NOT(printer);

145: 5 ^E : echo:=NOT echo;

146: 5 ^A : autolinefeed:=NOT autolinefeed;

147: 5 ^S : SchreibStatus;

148: 5 ^R : WHILE NOT PufferLeer DO HolVonPuffer(ein);

149: 5 ^Z halt

150: 5 ELSE SendeZeichen(aus)

151: 5 END

152: 4 END ELSE SendeZeichen(aus)

153.- 3 END;

154: 2 SchickeZeichen (*sendet ein Zeichen aus dem Puffer*)

155: 2 UNTIL false (*Endlos•Schleife*)

156: 1 END.

 

Listing of COMHEX.PAS



1: 0 {****************************************************************************}

2: 0 {* Programm zu Erzeugung von Intel-Hex-Files aus COM-Dateien *}

3: 0 {****************************************************************************}

4: 0

5: 0 PROGRAM ComHex; {konvertiert Com-Files in Intel-Hex-Files}

6: 0

7: 0 CONST HexZiffer : ARRAY[0..15] OF char = '0123456789ABCDEF';

8: 0 MaxPuffer = 64;

9: 0

10: 0 TYPE HexZahl = STRING[4];

11: 0

12: 0 VAR FileName : STRING[14];

13: 0 ComFile : FILE;

14: 0 HexFile : text;

15: 0 Size : integer;

16: 0 CheckSum : integer;

17: 0 Puffer : ARRAY[0..8191] OF byte;

18: 0 TextPuf : ARRAY[1..MaxPuffer,0..3] OF STRING[75];

19: 0 Seite : integer;

20: 0 max,low : integer;

21: 0

22: 0 FUNCTION HexByte(x:integer) : HexZahl;

23: 0 BEGIN

24: 1 HexByte:=HexZifferl(lo(x) SHR 4)]+HexZiffer[(lo(x) AND 15)]

25: 1 END;

26: 0

27: 0 FUNCTION HexWord(x:integer) : HexZahl;

28: 0 BEGIN

29: 1 HexWord:=HexByte(Hi(x))+HexByte(lo(x))

30: 1 END;

31: 0

32: 0 PROCEDURE SchreibSeite(Nummer : integer);

33: 0 VAR i,j,b : integer; line : STRING[75];

34: 0 BEGIN

35: 1 FOR i:=0 TO 3 DO BEGIN

36: 2 line:='20'+HexWord($80+((Nummer SHL 7)+(i SHL 5)))+'00';

37: 2 CheckSum:=32+((Nummer+1) SHR 1)+(i SHL 5)+((nummer+1) AND 1) SHL 7;

38: 2 FOR j:=0 TO 31 DO BEGIN b:=Puffer[((Seite-low-1) SHL 7)+(i SHL 5)+j];

39: 3 line:=line+HexByte(b);

40: 3 CheckSum:=CheckSum+b; END;

41: 2 TextPuf[Seite-low,i]:=':'+line+HexByte(256-1o(CheckSum));

42: 2 END;

43: 1 END;

44: 0

45: 0 PROCEDURE SchreibPuffer(x:integer);

46: 0 VAR i,j : integer;

47: 0 BEGIN

48: 1 FOR i:=1 TO x DO FOR j:=0 TO 3 DO writeln(HexFile,TextPuf[i,j])

49: 1 END;

50: 0

51: 0 BEGIN {Hauptprogramm}

52: 1 write('Name des Programms : '); readln(FileName);

53: 1 IF pos('.',FileName)<>0

54: 1 THEN FileName:=copy(FileName,l,pos('.',FileName)-1);

55: 1 assign(ComFile,FileName+'.COM'); {$1-} reset(ComFile) {$1+};

56: 1 IF IOresult=0 THEN

57: 1 BEGIN

58: 2 assign(HexFile,FileName+'.HEX'); rewrite(HexFile);

59: 2 Size:=FileSize(ComFile);

60: 2 max:=MaxPuffer; low:=0;

61: 2 WHILE low<Size DO

62: 2 BEGIN

63: 3 IF Size-low<max THEN max:=Size-low; writeln(low:5,Size:5,max:5);

64: 3 blockread(ComFile,Puffer,max);

65: 3 FOR Seite:=1+low TO low+max DO SchreibSeite(Seite);

66: 3 SchreibPuffer(max);

67: 3 low:=low+max

68: 3 END;

69: 2 close(ComFile); writeln(HexFile,':0000000000'); close(HexFile)

70: 2 END

71: 1 END.

 



Listing of COMSEND.PAS



1: 0 {****************************************************************************}

2: 0 {* COMSEND *}

3: 0 (****************************************************************************)

4: 0 PROGRAM COMSEND;

5: 0

6: 0 {Arbeitet zusammen mit COMREC zum Ueberspielen von COM- und anderen Files

7: 0 Uebertraegt die Daten nibbleweise und ist deshalb auch bei

8: 0 7-BIT-Uebertragung einsetzbar.}

9: 0

10: 0 VAR fname        : STRING[14];

11: 0       comfile       : FILE;

12: 0       aus            : char;

13: 0 PufferZeiger,

14: 0 FileGroesse,

15: 0 BlockZaehler : integer;

16: 0 Puffer : ARRAY[0-16383] OF Byte;

17: 0 i,j : Byte;

18: 0 LONibble,

19: 0 HINibble : 32..47;

20: 0

21: 0 BEGIN

22: 1

23: 1 write('Name des zu sendenden Files : '); read(fname);

24: 1 {$I-} assign(comfile,fname); reset(comfile) {$1+};

25: 1 IF IOresult<>0 THEN

26: 1 BEGIN writeln('File existiert nicht!'); halt END;

27: 1

28: 1 ClrScr;

D9: 1 writeln('Gesendet wird : ',fname);

30: 1 FileGroesse:=FileSize(comfile);

31: 1 writeln('Filegroesse : ',FileGroesse,' CP/M-Sektoren');

32: 1 write(aux,chr(32+FileGroesse DIV 64)); read(aux,aus);

33: 1 write(aux,chr(32+FileGroesse MOD 64)); read(aux,aus);

34: 1 gotoxy(5,5); write('wird uebertragen.');

35: 1 BlockZaehler:=1;

36: 1 WHILE FileGroesse>0 DO BEGIN

37: 2 IF FileGroesse>=128 THEN PufferZeiger:=128

38: 2 ELSE PufferZeiger:=FileGroesse MOD 128;

39: 2 FileGroesse:=FileGroesse-PufferZeiger;

40: 2 Blockread(comfile,Puffer,PufferZeiger);

41: 2 FOR j:=0 TO PufferZeiger-1 DO

42: 2 BEGIN

43: 3 gotoxy(1,5); write(BlockZaehler:3);

44: 3 FOR i:=0 TO 127 DO

45: 3 BEGIN

46: 4 LONibble:=32 OR Puffer[(j SHL 7)+i] AND 15;

47: 4 HINibble:=32 OR Puffer[(j SHL 7)+i] SHR 4;

48: 4 write(aux,chr(HINibble),chr(LONibble))

49: 4 END;

50: 3 read(aux,aus); BlockZaehler:=succ(BlockZaehler)

51: 3 END

52: 2 END;

53: 1 close(comfile);

54: 1 gotoxy(1,6); writeln('Uebertragung beendet')

55: 1 END.

 

 

Listing of COMREC.PAS



1: 0 (****************************************************************************)

2: 0 (* COMREC *}

3: 0 (****************************************************************************)

4: 0 PROGRAM COMREC;

5: 0

6: 0 {Ein Programm zum Ueberspielen von COM- und anderen Dateien

7: 0 Arbeitet nibbleweise und funktioniert daher auch bei

8: 0 7-Bit-Uebertragung. Baudrate ist nicht kritisch.}

9: 0

10: 0 VAR fname : STRING[14];

11: 0 comfile : FILE;

12: 0 BlockZaehler,

13: 0 FileGroesse : integer;

14: 0 Puffer : ARRAY[0..16383] OF Byte;

15: 0 ein : char;

16: 0 count : Byte;

17: 0 Block : ARRAY[0..255] OF char;

18: 0

19: 0 PRDCEDURE liesBlock;

20: 0 VAR i : Byte;

21: 0 BEGIN

22: 1 FOR i:=0 TO 255 DO read(aux,Block[i])

23: 1 END;

24: 0

25: 0 PROCEDURE SchreibInPuffer;

26: 0 VAR i : Byte;

27: 0 BEGIN

28: 1 FOR i:=0 TO 127 DO Puffer[(((BlockZaehler-1) AND 127) SHL 7)+i]:=

29: 1 ((ord(Block[i SHL 1]) AND 15) SHL 4) OR (ord(Block[(i SHL 1)+1]) AND

30: 1 END;

31: 0

32: 0

33: 0 BEGIN

34: 1 ClrScr;

35: 1 write('Name des Files : '); readln(fname);

36: 1 assign(comfile,fname);

37: 1 ($I-} reset(comfile) {$1+};

38: 1 IF IOresult=0 THEN

39: 1 BEGIN write('File existiert bereits! Loeschen (J/N) ? ');

40: 2 REPEAT read(kbd,ein) UNTIL ein IN ['j','J','n','N'];

41: 2 IF ein IN ['n','N'] THEN halt

42: 2 END;

43: 1 rewrite(comfile);

44: 1 writeln('Fertig zur Uebernahme.');

45: 1 read(aux,ein); FileGroesse:=(ord(ein)-32)*64; write(aux,ein);

46: 1 read(aux,ein); FileGroesse:=FileGroesse+ord(ein)-32;

47: 1 write(aux,ein);

48: 1 write('Filegroesse : ',FileGroesse,' CP/M-Sektoren');

49: 1 gotoxy(5,5); write('wird uebertragen.');

50: 1 FOR BlockZaehler:=1 TO FileGroesse DO BEGIN

51: 2 gotoxy(1,5); write(BlockZaehler:3);

52: 2 liesBlock;

53: 2 SchreibinPuffer;

54: 2 IF BlockZaehler MOD 128 = 0 THEN BlockWrite(comfile,Puffer,128);

55: 2 write(aux,ein)

56: 2 END;

57: 1 BlockWrite(comfile,Puffer,FileGroesse MOD 128);

58: 1 close(comfile);

59: 1 gotoxy(1,6); writeln('Uebertragung beendet.');

60: 1 END.

 

 

Listing of CPM-80.BIB

1: 0 (**************************************************************************************** *)

2: 0 (* Bibliotheks-Modul CPM-80.BIB *)

3: 0 (* Wichtige Betriebssystem-Prozeduren fuer CPM-80 *)

4: 0 (* Laufwerkscode : 0=Bezugslaufwerk, 1=A:, 2=B ... *)

5: 0 (* c SpeicherEinheit (real) fuer MemAvail und MaxAvail *)

6: 0 (* p DiskReset setzt Disketensystem zurueck *)

7: 0 (* p DiskAnmelden(d) definiert d als Bezugslaufwerk *)

8: 0 (* f Aktlaufwerk gibt Bezugslaufwerk zurueck *)

9: 0 (* f ErsterEintrag(FCB,DMA):byte sucht ersten Directory-Eintrag, der auf *)

10: 0 (* den File-Control-Block passt. Ergebnis in DMA, falls Wert<>255 *)

11: 0 (* f NaechsterEintrag:byte sucht naechsten passenden Eintrag *)

12: 0 (****************************************************************************)

13: 0

14: 0 CONST SpeicherEinheit 1.0; (wird gebraucht fuer MemAvail etc.)

15: 0

16: 0 PROCEDURE DiskReset;

17: 0 BEGIN

18: 1 BDOS(13)


19: 1 END;

20: 0

21: 0 PROCEDURE DiskAnmelden(drive:byte);

22: 0 BEGIN


23: 1 IF drive>0 THEN BDOS(14,(drive-1) AND 15)

24: 1 END;

25: 0

26: 0 FUNCTION AktLaufwerk : byte;

27: 0 BEGIN

28: 1 AktLaufwerk:=BDOS(25)+1

29: 1 END;

30: 0

31: 0 FUNCTION ErsterEintrag(VAR FCB; VAR DMA) : byte;

32: 0 BEGIN

33: 1 BDOS(26,addr(DMA));

34: 1 ErsterEintrag:=BDOS(17,addr(FCB))

35: 1 END;

36: 0

37: 0 FUNCTION NaechsterEintrag : byte;

38: 0 BEGIN

39: 1 NaechsterEintrag:=BDOS(18)

40: 1 END;

 

 

Listing of PUFFER.BIB

1: 0 (****************************************************************************)

2: 0 (* Bibliotheks-Modul PUFFER.BIB *)

3: 0 (* Listenoperationen fuer Puffer-Listen *)

4: 0 (* Setzt das Vorhandensein des Typs 'Pufferinhalt' varaus *)

5: 0 (* (t Puffer definiert einer FIFO-Speicherstruktur) *)

6: 0 (* (t PufferEintrag) *)

7: 0 (* (v PufferAnfang, PufferEnde : Puffer) *)

8: 0 (* f PufferVoll : boolean wird wahr, wenn Puffer ueberlauft *)

9: 0 (* v PufferLeer : boolean wird wahr, wenn kein Element im Puffer *)

10: 0 (* p InitPuffer initialister PufferAnfang- und Ende sowie Pufferleer *)

11: 0 (* p SchreibInPuffer(E : Pufferinhalt) prueft nicht auf Ueberlauf *)

12: 0 (* p HolVonPuffer(var E : Pufferinhalt) E undefiniert, falls PufferLeer *)

13: 0 (* Alle drei Prozeduren veraendern PufferVoll und PufferLeer *)

14: 0

15: 0

16: 0 TYPE Puffer = APufferEintrag;

17: 0 PufferEintrag = RECORD

18: 1 Eintrag : Pufferinhalt;

19: 1 Naechster : Puffer

20: 1 END;

21: 0

22: 0 VAR PufferAnfang,

23: 0 PufferEnde : Puffer;

24: 0 PufferLeer : boolean;

25: 0

26: 0 FUNCTION PufferVoll : boolean;

27: 0 CONST MemEinheit = 16.0; (*1.0 bei CP/M-80*)

28: 0 VAR PufferAvail : real;

29: 0 BEGIN

30: 1 IF MemAvail<0

31: 1 THEN PufferAvail:=MemEinheit*(65536.0+MemAvail)

32: 1 ELSE PufferAvail:=MemEinheit*MemAvail;

33: 1 Puf ferVoll:=Puf ferAvail<SizeOf(Puf ferEintrag)

34: 1 END;

35: 0

36: 0 PROCEDURE InitPuffer;

37: 0 BEGIN

38: 1 PufferAnfang:=NIL; PufferEnde:=NIL; PufferLeer:=true;

39: 1 END;

40: 0

41: 0 PROCEDURE SchreibInPuffer(E : Pufferinhalt);

42: 0 VAR p : Puffer;

43: 0 BEGIN

44: 1 IF NOT PufferVoll THEN

45: 1 BEGIN

46: 2 new(p); PufferLeer:=false;

47: 2 WITH p^ DO BEGIN Eintrag:=E; Naechster:=NIL END;

48: 2 IF PufferEnde<>NIL

49: 2 THEN PufferEnde^.Naechster=p

50: 2 ELSE IF PufferAnfang<>NIL THEN PufferAnfangA.Naechster:=p

51: 2 ELSE PufferAnfang:=p;

52: 2 PufferEnde:=p

53: 2 END

54: 1 END;

55: 0

56: 0 PROCEDURE HolVonPuffer(VAR E : Pufferinhalt);

57: 0 VAR p : Puffer;

58: 0 BEGIN

59: 1 IF PufferAnfang=NIL

60: 1 THEN PufferLeer:=true

61: 1 ELSE BEGIN

62: 2 p:=PufferAnfang; E:=p^.Eintrag; PufferAnfang:=p^.Naechster;

63: 2 dispose(p); PufferLeer:=PufferAnfang=NIL;

64: 2 IF PufferLeer THEN PufferEnde:=NIL

65: 2 END

66: 1 END;



 

[index] [Assembler] [Pascal] [TTL] [Z180] [Computer] [Terminal] [Software] [ZFEST2006] [ZFEST2007] [ZFEST2008] [Kontakt]