Mail Archives: opendos/1997/05/28/10:43:20
I whill tell several wishes about OpenDOS
1. A problem with VSHARE.386 is greater as it looks because the
default locks count of SHARE.EXE is not enough to several applications
(WINWORD 6 etc.) That problem can be fixed by correct SHARE parameters
(e.g. SHARE /L:200) but not every user can configure the system
independently! I think, the best solving is adding to SETUP program a new
feature, 'Windows VSHARE support' that (if "YES") must add the
line 'SHARE /l:...' to AUTOEXEC.BAT file.
2. TASKMGR must have a feature to copy/paste (probably optionally
compatible with Windows clipboard). I use a my utility
(CLIP) but it don't support mouse and the Windows clipboard. It is a
freeware but can have some bugs. Every can use it and make changes in code.
To begin marking and to accept block you must use Enter key. Esc,
Home, End, PgUp, PgDown, arrows supported. The applied source code is
compatible with Borland Pascal 7 but incompatible with Stony Brook.
{(C) P.Ozerski, Institute of Evolutionary Physiology & Biochemistry
of Russian Academy of Science, St.Petersburg.}
{Release 2.0b, 1997}
{uses some tricks developmed by A.Shekhovtzov (Kiev, Ukraine)}
{Must be loaded before TASKMGR,
compatible with:
- HILOAD and Quarterdeck LOADHI;
- different text video modes including some non-standard (card-specific);
can use text .INI-file
}
{Freeware, but no warranty!!! Compiler - TP7/BP7 (real mode), (?)TP6}
{$A+,B-,D-,E-,F-,G-,I-,L-,N-,O-,R-,S-,V-,X-}
{$M 1024,0,0}
uses
DOS,CRT;
type
BufType=array[1..132,1..60]of char;
var
mode:array[0..255]of boolean;
vectorstochange:array[1..3]of pointer;
OldCursorShape:word;
buf:buftype;
intvec:array[0..255]of pointer absolute 0:0;
i,j,x1,y1,x2,y2,__x1,__x2,EndCounter:byte;
returner:(label_left,label_right,label_up,label_down);
menucolor:byte;
currentmode,maxrows,maxcolumns,_maxrows,_maxcolumns:byte;
oldvector9,oldvector60,old1C:procedure;
oldvector9_addr:pointer absolute oldvector9;
oldvector60_addr:pointer absolute oldvector60;
old1c_addr:pointer absolute old1C;
PrefixSeg,EnvSeg,MenuCmd,ArrowsCmd:word;
MenuOK,MenuDone,ArrowsDone,EGAVGA,marking:boolean;
OldXY:word;
var
Old,New,Start:record
case byte of
1:(_X,_Y:byte);
2:(_XY:word)
end;
const
int60H:byte=$60;
EndMode:boolean=false;
Top_Y:byte=0;
Bottom_Y:byte=0;
Left_X:byte=0;
Right_X:byte=0;
_X:byte=1;
_Y:byte=1;
down=True;
up=false;
ALT:boolean=up;
CTRL:boolean=up;
lSHIFT:boolean=up;
rSHIFT:boolean=up;
menu:array[1..7,1..14]of char=(
#218#196#196#196#196#196#196#196#196#196#196#196#196#191,
#179' Copy F5 '#179,
#195#196#196#196#196#196#196#196#196#196#196#196#196#180,
#179' Paste F6 '#179,
#195#196#196#196#196#196#196#196#196#196#196#196#196#180,
#179' Close Esc '#179,
#192#196#196#196#196#196#196#196#196#196#196#196#196#217);
menuInUse:boolean=false;
pasteFlag:boolean=false;
StrCount:byte=0;
StrLen:byte=0;
var
backgr:array[1..7,1..14]of word;
__i,__j:byte;
type
btype=array[1..sizeof(menu)]of record
case byte of
1:(c1,c2:char);
2:(b1,b2:byte);
3:(w:word);
end;
bPtr=^btype;
var
HotAlt,HotCtrl,HotlShift,HotrShift:boolean;
HotKey,Port60H:byte;
Video:Bptr;
VideoSeg:word;
_left,_right,_top,_bottom:byte;
procedure Move( VAR Source, Dest; Count : word );
TYPE
Bytes = array[1..MaxInt] of byte;
VAR
I : word;
begin
FOR I := 1 TO Count DO
Bytes(Dest)[I]:=Bytes(Source)[I];
end;
procedure BufferDS;
begin
end;
procedure PasteProc;interrupt;
const
X:word=0;
KbdStart = $1E;
KbdEnd = $3C;
var
KbdHead : Word absolute $40 : $1A;
KbdTail : Word absolute $40 : $1C;
SaveKbdTail : Word;
__X:char absolute X;
begin
asm
mov ax, cs : word ptr [BufferDS]
mov ds,ax
end;
if PasteFlag and(strcount=0) then
PasteFlag:=false;
if PasteFlag then
begin
if __j>strlen then
X:=7181
else
begin
X:=0;
__X:=buf[__j,__i];
end;
SaveKbdTail := KbdTail;
if KbdTail = KbdEnd then
KbdTail := KbdStart
else
Inc(KbdTail, 2);
if KbdTail = KbdHead then
KbdTail := SaveKbdTail
else
MemW[$40:SaveKbdTail] := X;
if (__i=StrCount)and(__j=StrLen)then
PasteFlag:=false
else if __j<=strLen then
inc(__j)
else
begin
__j:=1;
inc(__i);
end
end;
asm pushf end;
Old1C
end;
procedure MyRes; interrupt;
begin
asm
mov ax, cs : word ptr [BufferDS]
mov ds,ax
pushf
call oldvector9
end;
port60H:=port[$60];
case port60H of
29:Ctrl:=down;
157:Ctrl:=up;
56:ALT:=down;
184:ALT:=up;
42:lShift:=down;
170:lShift:=up;
54:rShift:=down;
182:rShift:=up;
end;
if menuInUse then
exit;
if(port60H=HotKey)and
(alt=HotAlt)and
(ctrl=HotCtrl)and
(lshift=HotlShift)and
(rShift=HotrShift)then
begin
asm
cli
mov AH,$0F
int $10
mov CurrentMode,AL
mov MaxColumns,AH
mov _MaxColumns,AH
dec _MaxColumns
end;
if not Mode[CurrentMode] then
begin
asm
sti
end;
exit;
end;
if EGAVGA then
asm
mov AH,$11
mov AL,$30
xor BH,BH
push BP
push ES
int $10
pop ES
pop BP
inc DL
mov MaxRows,DL
mov _MaxRows,DL
dec _MaxRows
end
else
begin
MaxRows:=25;
_MaxRows:=24;
end;
for i:=1 to 7 do
begin
Video:=ptr(VideoSeg,pred(i)*MaxColumns*2);
for j:=1 to 14 do
begin
backgr[i,j]:=Video^[j].w;
Video^[j].c1:=Menu[i,j];
Video^[j].b2:=MenuColor;
end;
end;
menuInUse:=true;
marking:=false;
asm
mov AX,2002
int $60
sti
end;
end;
end;
procedure _60(_AX,_BX,_CX,_DX,_SI,_DI,_DS,_ES,_BP:Word);interrupt;
procedure Arrows;near;
label
Lab1,UpDown,LeftRight,
__L,__R,__U,__D,
__E,__R_Entry,
__H,__L_Entry,
__PU,__U_Entry,
__PD,__D_Entry;
var
D:record L,H:byte end absolute _DX;
begin
case arrowscmd of
20224:{End}
begin
EndMode:=true;
EndCounter:=0;
while EndCounter<_maxColumns do
asm
mov AH,$3
xor BH,BH
int $10
mov EndCounter,DL
jmp __R_Entry;
__E:
end;
EndMode:=false;
end;
18176:{Home}
begin
EndMode:=true;
EndCounter:=_MaxColumns;
while EndCounter>0 do
asm
mov AH,$3
xor BH,BH
int $10
mov EndCounter,DL
jmp __L_Entry;
__H:
end;
EndMode:=false;
end;
18688:{PgUp}
begin
EndMode:=true;
EndCounter:=_MaxRows;
while EndCounter>0 do
asm
mov AH,$3
xor BH,BH
int $10
mov EndCounter,DH
jmp __U_Entry;
__PU:
end;
EndMode:=false;
end;
20736:{PgDn}
begin
EndMode:=true;
EndCounter:=0;
while EndCounter<_MaxRows do
asm
mov AH,$3
xor BH,BH
int $10
mov EndCounter,DH
jmp __D_Entry;
__PD:
end;
EndMode:=false;
end;
19712:{->}
begin
EndMode:=false;
__R_Entry:
asm
mov AH,$3
xor BH,BH
int $10
mov Old,DX
mov New,DX
cmp DL,_maxcolumns
je lab1
inc DL
cmp DL,_right
jg @1
mov _left,DL
jmp @2
@1: mov _right,DL
@2: mov AH,$2
xor BH,BH
mov New,DX
int $10
end;
if Marking Then
begin
if New._X>right_X then
Right_X:=New._X
else
Left_X:=New._X;
returner:=label_right;
goto LeftRight;
__R:
end;
if EndMode then
Goto __E
end;
19200:{<-}
begin
EndMode:=false;
__L_Entry:
asm
mov AH,$3
xor BH,BH
int $10
mov Old,DX
mov New,DX
cmp DL,0
je lab1
dec DL
cmp DL,_left
jl @1
mov _right,DL
jmp @2
@1: mov _left,DL
@2: mov AH,$2
xor BH,BH
mov New,DX
int $10
end;
if Marking Then
begin
if New._X<left_X then
Left_X:=New._X
else
Right_X:=New._X;
returner:=label_left;
goto LeftRight;
__L:
end;
if EndMode then
Goto __H
end;
18432:{Up}
begin
EndMode:=false;
__U_Entry:
asm
mov AH,$3
xor BH,BH
int $10
mov Old,DX
mov New,DX
cmp DH,0
je lab1
dec DH
cmp DH,_top
jl @1
mov _bottom,DH
jmp @2
@1: mov _top,DH
@2: mov AH,$2
xor BH,BH
mov New,DX
int $10
end;
if Marking then
begin
if New._Y<Top_Y then
Top_Y:=New._Y
else
Bottom_Y:=New._Y;
if New._Y>=Start._Y then
begin
y1:=Succ(New._Y);
y2:=Succ(Old._Y);
end
else
begin
y1:=(New._Y);
y2:=(Old._Y);
end;
returner:=Label_Up;
goto UpDown;
__U:
end;
if EndMode then
Goto __PU
end;
20480:{Down}
begin
EndMode:=false;
__D_Entry:
asm
mov AH,$3
xor BH,BH
int $10
mov Old,DX
mov New,DX
cmp DH,_maxrows
je lab1
inc DH
cmp DH,_bottom
jg @1
mov _top,DH
jmp @2
@1: mov _bottom,DH
@2: mov AH,$2
xor BH,BH
mov New,DX
int $10
end;
if Marking then
begin
if New._Y>Bottom_Y then
Bottom_Y:=New._Y
else
Top_Y:=New._Y;
if New._Y>Start._Y then
begin
y1:=succ(Old._Y);
y2:=succ(New._Y);
end
else
begin
y1:=Old._Y;
y2:=New._Y;
end;
returner:=Label_Down;
goto UpDown;
__D:
end;
if EndMode then
Goto __PD
end;
end;
goto Lab1;
Updown:
for i:=y1 to y2 do
begin
if i<=y1 then
x1:=succ(Old._X)
else
x1:=Start._X;
if (x1<=New._X)or(i=y1) then
begin
__x1:=x1;
__x2:=New._X
end
else
begin
__x1:=New._X;
__x2:=x1
end;
Video:=ptr(VideoSeg,pred(i)*MaxColumns*2);
for j:=succ(__x1) to succ(__x2) do
Video^[j].b2:=$7F-Video^[j].b2;
end;
case returner of
Label_Up:goto __U;
Label_Down:goto __D;
end;
leftRight:
if (New._X>Start._X)or((New._X=Start._X)and(Returner=Label_left)) then
begin
x1:=succ(Old._X);
x2:=succ(New._X);
end
else
begin
x1:=Old._X;
x2:=New._X;
end;
if returner=Label_Right then
asm
mov CL,x1
mov CH,x2
mov x1,CH
mov x2,CL
end;
for i:=Top_Y to Bottom_Y do
begin
Video:=ptr(VideoSeg,i*MaxColumns*2);
for j:=succ(x2) to x1 do
Video^[j].b2:=$7F-Video^[j].b2;
end;
case returner of
Label_Left:goto __L;
Label_Right:goto __R;
end;
Lab1:
end;
begin
asm
mov ax, cs : word ptr [BufferDS]
mov ds,ax
end;
if _AX=2000 then
asm
mov AX,'LC'
mov BX,'PI'
mov _AX,AX
mov _BX,BX
end
else if _AX=2001 then
begin
if (intvec[$60]=@_60)and(intvec[$9]=@myres)and(intvec[$1C]=@pasteProc)then
begin
vectorstochange[1]:=oldvector60_addr;
vectorstochange[2]:=oldvector9_addr;
vectorstochange[3]:=old1C_addr;
_AX:=4002;
_BX:=PrefixSeg;
_CX:=ofs(vectorstochange);
_DX:=seg(vectorstochange);
end
else
_AX:=4000
end
else if _AX=2002 then
begin
repeat
asm
xor AH,AH
int 16H
mov MenuCmd,AX
end;
case MenuCmd of
283,16128,16384:
begin
for i:=1 to 7 do
begin
Video:=ptr(VideoSeg,pred(i)*MaxColumns*2);
for j:=1 to 14 do
Video^[j].w:=backgr[i,j];
end;
if MenuCmd=283{Esc}then
begin
MenuOK:=false;
MenuDone:=true;
end
else if MenuCmd=16384{F6}then
begin
__i:=1;
__j:=1;
PasteFlag:=true;
end
else {F5}
begin
asm
mov AH,$3
xor BH,BH
int $10
mov OldCursorShape,CX
mov OldXY,DX
mov AH,$2
mov BH,$0
xor DX,DX
int $10
mov AH,$1
mov CX,$0505
int $10
end;
MenuOK:=true;
ArrowsDone:=false;
asm
xor AH,AH
mov _left,AH
mov _right,AH
mov _top,AH
mov _bottom,AH
end;
repeat
asm
xor AH,AH
int 16H
mov ArrowsCmd,AX
end;
case ArrowsCmd of
283:{Esc}
begin
MenuOK:=false;
ArrowsDone:=true;
end;
7181:{Enter}
begin
ArrowsDone:=true;
asm
mov AH,$3
xor BH,BH
int $10
mov Start,DX
mov Top_Y,DH
mov Bottom_Y,DH
mov Left_X,DL
mov Right_X,DL
end;
Video:=ptr(VideoSeg,Start._Y*MaxColumns*2);
Video^[succ(Start._X)].b2:=$7F-Video^[succ(Start._X)].b2
end;
else
arrows
end;
until ArrowsDone;
if MenuOK then
begin
ArrowsDone:=false;
repeat
asm
xor AH,AH
int $16
mov ArrowsCmd,AX
end;
marking:=true;
case ArrowsCmd of
283:{Esc}
begin
MenuOK:=false;
ArrowsDone:=true;
end;
7181:{Enter}
begin
strlen:=succ(Right_X-Left_X);
strCount:=succ(Bottom_Y-Top_Y);
for i:=1 to strCount do
begin
Video:=ptr(VideoSeg,(i+Top_Y-1)*MaxColumns*2);
for j:=1 to StrLen do
buf[j,i]:=Video^[j+Left_X].c1;
end;
ArrowsDone:=true;
end;
else
arrows
end;
until ArrowsDone;
for i:=Top_Y to Bottom_Y do
begin
Video:=ptr(VideoSeg,i*MaxColumns*2);
for j:=Left_X to Right_X do
Video^[succ(j)].b2:=$7F-Video^[succ(j)].b2;
end;
end;
MenuDone:=true;
asm
mov AH,$1
mov CX,OldCursorShape
int $10
end
end;
end;
else
MenuDone:=false;
end
until MenuDone;
MenuInUse:=false
end;
end;
procedure DummyProc;
forward;
procedure Keep(ExitCode:byte);
var
ResidSize,NewDS,DataSize:word;
begin
NewDS:=(CSeg+Ofs(DummyProc)DIV 16)+1;
DataSize:=SSeg-DSeg;
ResidSize:=NewDS-PrefixSeg+DataSize;
asm
mov ax,NewDS
mov cs:word ptr[BufferDS],ax
end;
move(MEM[DSeg:0],MEM[NewDS:0],(SSeg-DSeg)*16);
asm
mov ax,[SYSTEM.PREFIXSEG]
mov es,ax
mov es,es:[02CH]
mov ah,49H
int 21H
mov dx,ResidSize
mov ah,31H
mov al,ExitCode
int 21H
end
end;
procedure DummyProc;
begin
end;
var
code:integer;
ID:array[1..4]of char absolute buf;
IniFile:record
t:text;
d:dirstr;
n:namestr;
e:extstr;
end absolute buf;
ModeString:string;
const
keyname:array[1..88]of string[4]=
(
'Esc',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'0',
'-',
'=',
'Bksp',
'Tab',
'Q',
'W',
'E',
'R',
'T',
'Y',
'U',
'I',
'O',
'P',
'[',
']',
#17#196#217,
'CTRL',
'A',
'S',
'D',
'F',
'G',
'H',
'J',
'K',
'L',
';',
'''',
'`',
'(l)'#24,
'\',
'Z',
'X',
'C',
'V',
'B',
'N',
'M',
',',
'.',
'/',
'(r)'#24,
'PrSc',
'lALT',
'SPBR',
'CAPS',
'F1',
'F2',
'F3',
'F4',
'F5',
'F6',
'F7',
'F8',
'F9',
'F10',
'NmlK',
'ScLk',
'HOME',
'UP',
'PgUp',
'-',
'Left',
'Rght',
'g5',
'+',
'END',
'DOWN',
'PgDn',
'INS',
'DEL',
'SysR',
'???',
'???',
'F11',
'F12'
);
procedure UpStr(var _s);near;
var
s:string absolute _s;
ls:byte absolute _s;
i:byte;
begin
for i:=1 to ls do
s[i]:=UpCase(s[i]);
end;
var
section,item,default:string;
function GetIni:string;near;
var
endsection,found:boolean;
s:string;
ps:byte;
begin
with IniFile do
begin
GetIni:=default;
reset(t);
if ioresult=0 then
begin
found:=false;
endsection:=false;
while not(endSection or found ) do
begin
if eof(t) then
endSection:=true
else
begin
readln(t,s);
UpStr(s);
while (s[0]>#0)and(s[1]<#32) do
delete(s,1,1);
ps:=pos(section,s);
if ps=1 then
while not(endSection or found ) do
if eof(t) then
endSection:=true
else
begin
readln(t,s);
UpStr(s);
while (s[0]>#0)and(s[1]<#32) do
delete(s,1,1);
if pos('[',s)=1 then
endSection:=true
else
begin
ps:=pos(item+'=',s);
if ps=1 then
begin
found:=true;
GetIni:=copy(s,length(item)+2,255)
end;
end;
end;
end;
end;
close(t);
end
end
end;
function Val(s:string):longint;near;
var
result:longint;
begin
system.val(s,result,code);
Val:=result;
end;
function STR7(var s:string):string;near;
var
ss:string[7];
begin
ss:=s;
while length(ss)<7 do
ss:=ss+' ';
STR7:=ss
end;
const
ClipAlreadyLoaded:boolean=true;
Unloaded:boolean=false;
var
OldPtr:pointer;
OldRec:record O,S:word end absolute oldPtr;
label
ll1,ll2;
begin
ModeString:=paramstr(1);
ModeString[2]:=UpCase(ModeString[2]);
GetIntVec($60,@Oldvector60);
if (ModeString='/?')or(ModeString='/H') then
begin
write('/U - Uninstall;'#13#10+
'.INI file syntax:'#13#10+
'[KEYS]'#13#10+
'ALT=ON{default}|OFF'#13#10+
'CTRL=ON|OFF{default}'#13#10+
'LEFTSHIFT=ON|OFF{default}'#13#10+
'RIGHTSHIFT=ON|OFF{default}'#13#10+
'HOTKEY=nn{default=$1}'#13#10+
'[COLOR]'#13#10+
'COLOR=nn{default=$07}'#13#10+
'[VIDEOMODES]'#13#10+
'TEXT=n1,n2...{default=0,1,2,3,7}'#13#10#13#10+
'Hit Ente');
writeln('r to hot key codes list');
readln;
for j:=1 to 88 do
begin
write(j:0,': ',STR7(keyname[j]));
if j mod 4 =0 then
writeln;
end;
halt
end
else if (ModeString='/U') then
begin
if (@Oldvector60<>nil)and(@Oldvector60<>ptr($F000,$E3D4)) then
begin
asm
mov AX,2000
int $60
cmp AX,'LC'
jne ll1
cmp BX,'PI'
jne ll1
mov AX,2001
int $60
cmp AX,4002
jne ll2
mov PrefixSeg,BX
mov oldRec.O,CX
mov oldRec.S,DX
end;
for i:=1 to 3 do
begin
case i of
1:
j:=$60;
2:
j:=$9;
3:
j:=$1C;
end;
setintvec(j,pointer(OldPtr^));
inc(OldRec.O,4)
end;
EnvSeg:=MemW[PrefixSeg:$2C];
asm
push ES
mov AH,$49
mov ES,PrefixSeg
int $21
mov AH,$49
mov ES,EnvSeg
int $21
pop ES
mov Unloaded,true
jmp ll2
ll1: mov ClipAlreadyLoaded,false
ll2:
end
end
else
ClipAlreadyLoaded:=false;
if not ClipAlreadyLoaded then
writeln('CLIP not loaded')
else
begin
if Unloaded then
writeln('CLIP is removed from memory')
else
writeln('CLIP cannot be removed from memory');
end;
halt(2)
end;
EGAVGA:=true;
asm
mov AX,$1A00
int $10
cmp AL,$1A
je @1
mov EGAVGA,false
@1:
mov AH,$0F
int $10
mov CurrentMode,AL
end;
if currentmode=7 then
VideoSeg:=$B000
else
VideoSeg:=$B800;
PrefixSeg:=System.PrefixSeg;
if(@Oldvector60<>nil)and(@Oldvector60<>ptr($F000,$E3D4))then
begin
asm
mov AX,2000
int $60
mov word ptr[buf],AX
mov word ptr[buf+2],BX
end;
if ID='CLIP' then
begin
writeln('CLIP already loaded');
halt(1)
end;
end;
with IniFile do
begin
fsplit(paramstr(0),D,N,E);
assign(t,D+N+'.INI');
end;
Section:='[KEYS]';
Item:='ALT';
Default:='ON';
HotALT:=GetIni='ON';
Section:='[KEYS]';
Item:='CTRL';
Default:='OFF';
HotCTRL:=GetIni='ON';
Section:='[KEYS]';
Item:='LEFTSHIFT';
Default:='OFF';
HotlSHIFT:=GetIni='ON';
Section:='[KEYS]';
Item:='RIGHTSHIFT';
Default:='OFF';
HotrSHIFT:=GetIni='ON';
Section:='[KEYS]';
Item:='HOTKEY';
Default:='1';
HotKey:=Val(GetIni);
Section:='[COLOR]';
Item:='COLOR';
Default:='7';
MenuColor:=Val(GetIni);
Section:='[VIDEOMODES]';
Item:='TEXT';
Default:='0,1,2,3,7';
ModeString:=GetIni+',';
fillchar(mode,sizeof(mode),char(false));
Mode[0]:=true;
Mode[1]:=true;
Mode[2]:=true;
Mode[3]:=true;
Mode[7]:=true;
code:=0;
while (code=0)and(modestring[0]>#1)do
begin
Mode[val(copy(Modestring,1,pred(pos(',',modestring))))]:=true;
delete(ModeString,1,pos(',',modestring));
end;
writeln('CLIP R2.0, utility to copy/paste in DOS text mode');
write('Hot Key: ');
if HotAlt then
write('ALT+');
if HotCtrl then
write('CTRL+');
if HotlShift then
write('Left SHIFT+');
if HotrShift then
write('Right SHIFT+');
if (HotKey in [1..88])and(KeyName[HotKey]<>'???') then
writeln(KeyName[HotKey])
else
writeln('Unknown key #',Hotkey:0);
fillchar(buf,sizeof(buf),0);
SetIntVec($60,@_60);
GetIntVec($9,@Oldvector9);
SetIntVec($9,Addr(MyRes));
GetIntVec($1C,@Old1C);
SetIntVec($1C,Addr(PasteProc));
SwapVectors;
Keep(0);
end.
--
Pavel V. Ozerski | Inst. of Evolutionary Physiology & Biochemistry,
office +7 (812)552-6870(291)| Russian Academy of Sciences,
FAX +7 (812)552-3012 | Thorez pr. 44, St.Petersburg, 194223, Russia
home +7 (812)528-5576 | E-mail: pavel AT insect DOT ief DOT spb DOT su
- Raw text -