F
flyingwater007
Unregistered / Unconfirmed
GUEST, unregistred user!
我找你找了很久~~-_-b,可以表现振幅的控件倒是有几个,但都满足不了要求,我想取得模拟振幅变化的一个数列,谁有有这方面的资料发扬下共享精神,先行谢过。下面是一段江先生的代码,里面有个取振幅的函数getpeak,小生愚笨,死活调试不出振幅,在那个判断处总是跳出,伤了~大虾们给提点建议
http://delphi.sharpplus.com/Recommend/rcAudioMixer.htm
unit Unit2;
//Written by David Jiang(江天送)
//july 25th. 1999
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls,
Forms, Dialogs,StdCtrls, ComCtrls, mmsystem, Buttons, ExtCtrls;
type Tvolume=record
left,right:word;
end;
type
TForm2 = class(TForm)
Lines: TComboBox;
Controls: TComboBox;
Label1: TLabel;
lmute: TLabel;
lmeter: TLabel;
LVolume: TTrackBar;
Rvolume: TTrackBar;
cmute: TCheckBox;
CheckBox1: TCheckBox;
About: TSpeedButton;
BExit: TSpeedButton;
RProgressBar: TProgressBar;
Timer1: TTimer;
procedure FormCreate(Sender: TObject);
procedure getlinecontrol;
procedure LinesChange(Sender: TObject);
procedure ControlsChange(Sender: TObject);
procedure LVolumeChange(Sender: TObject);
procedure cmuteClick(Sender: TObject);
procedure RvolumeChange(Sender: TObject);
procedure AboutClick(Sender: TObject);
procedure BExitClick(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
procedure FormClose(Sender: TObject;
var
Action: TCloseAction);
private
{ Private declarations }
procedure mmixer(var msg:Tmessage);
public
{ Public declarations }
end;
function getvolume(controlmixercontrol;var
volume:Tvolume):boolean;
function setvolume(controlmixercontrol;
volume:Tvolume):boolean;
function setmute(controlmixercontrol;
mute:integer):boolean;
function getmute(controlmixercontrol;var
mute:integer):boolean;
function getpeak(controlmixercontrol;var
peak:integer):boolean;
procedure Fillstruct(controlmixercontrol;var
Cdetails:Tmixercontroldetails);
var
Form2: TForm2;
fmixerhandle:hmixer;
//混音器的句柄
mcontrols:array of array of array of PMixerControl;
line:array of Tstringlist;
peaknum:integer;
//meter mcontrols的位置
implementation
{$R *.DFM}
procedure Tform2.mmixer(var msg:Tmessage);
var
volume:Tvolume;
mute:integer;
begin
if msg.Msg=MM_MIXM_CONTROL_CHANGE then
begin
if mcontrolS[lines.itemindex][controls.itemindex]
[0].dwcontrolID=msg.LParam then
if getvolume(mcontrolS[lines.itemindex]
[controls.itemindex][0],volume) then
begin
Rvolume.Position :=-volume.right;
Lvolume.Position :=-volume.left;
end;
if mcontrolS[lines.itemindex][controls.itemindex]
[1].dwcontrolid=msg.LParam then
if getmute(mcontrolS[lines.itemindex]
[controls.itemindex][1],mute) then
cmute.Checked:=mute=1;
end;
end;
procedure TForm2.FormCreate(Sender: TObject);
begin
getlinecontrol;
lines.ItemIndex :=0;
controls.Items:=line[lines.ItemIndex];
controls.ItemIndex :=0;
controls.OnChange (sender);
end;
procedure Tform2.getlinecontrol;
var
mixerID:integer;
//混音器的ID
FMixerCaps:TMixerCaps;
n,j,k,i:integer;
ml,ml2:TMIXERLINE;
MLC:TMixerLineControls;
PMixerControl;
begin
if mixerGetNumDevs=0 then
exit;
//如没有混合器装置,退出
fmixerhandle:=0;
mixerID:=0;
mixerOpen (@FMixerHandle,mixerID,AllocateHWnd(mmixer),
0,CALLBACK_WINDOW OR MIXER_OBJECTF_MIXER);
//打开混音器
mixerGetDevCaps (mixerID,@FMixerCaps,SizeOf (TMixerCaps));
//返回混音器的兼容性
setlength(line,fmixercaps.cDestinations);
setlength(mcontrols,fmixercaps.cDestinations );
for i:=0 to fmixercaps.cDestinations-1do
begin
ml.dwDestination:=i;
ml.cbStruct :=sizeof(tMIXERLINE);
mixerGetLineInfo(fmixerhandle,@ml,
MIXER_GETLINEINFOF_DESTINATION);
//取得混音器的Destinations
line:=tstringlist.Create ;
setlength(mcontrols,ml.cconnections);
n:=0;
if ml.cControls>1 then
begin
n:=1;
setlength(mcontrols,ml.cconnections+1);
MLC.cbStruct:=SizeOf(MLC);
MLC.dwLineID:=ml.dwLineID;
MLC.cControls:=ml.cControls;
MLC.cbmxctrl:=SizeOf(TMixerControl);
GetMem (P,SizeOf(TMixerControl)*ml.cControls);
MLC.pamxctrl:=P;
MixerGetLineControls(fMixerHandle,@MLC,
MIXER_GETLINECONTROLSF_ALL);
setlength(mcontrols[0],ml.cControls);
line.Add(p^.szname);
//Master Volume
For k:=0 to ml.cControls-1do
begin
mcontrols[0][k]:=p;
mcontrols[0][0].Metrics.dwReserved[k+1]:=1;
inc(p);
end;
end;
lines.Items.Add(ml.szName);
ML2.cbStruct:=SizeOf(TMixerLine);
ML2.dwDestination:=ml.dwDestination ;
for j:=0 to ml.cConnections -1do
begin
ML2.dwSource:=j;
MixerGetLineInfo (fmixerHandle,@ML2,
MIXER_GETLINEINFOF_SOURCE);
MLC.cbStruct:=SizeOf(MLC);
MLC.dwLineID:=ml2.dwLineID;
MLC.cControls:=ml2.cControls;
MLC.cbmxctrl:=SizeOf(TMixerControl);
GetMem (P,SizeOf(TMixerControl)*ml2.cControls);
MLC.pamxctrl:=P;
MixerGetLineControls(fMixerHandle,@MLC,
MIXER_GETLINECONTROLSF_ALL);
setlength(mcontrols[j+n],ml2.cControls);
For k:=0 to ml2.cControls-1do
begin
if p.dwControlType=MIXERCONTROL_CONTROLTYPE_VOLUME
then
line.add(p^.szName);
mcontrols[j+n][k]:=p;
mcontrols[j+n][0].Metrics.dwReserved[k+1]:=1;
inc(p);
end;
//取得混音器线路的控制器
end;
end;
end;
procedure Fillstruct(controlmixercontrol;var
Cdetails:Tmixercontroldetails);
begin
cdetails.cbStruct:=sizeof(cdetails);
cdetails.dwControlID:=control.dwControlID ;
cdetails.cbDetails:=sizeof(integer);
cdetails.hwndOwner :=0;
end;
function getpeak(controlmixercontrol;var
peak:integer):boolean;
var
details:TMIXERCONTROLDETAILSSIGNED;
cdetails:TMIXERCONTROLDETAILS;
begin
result:=false;
if control.dwControlType <>
MIXERCONTROL_CONTROLTYPE_PEAKMETER then
exit;
cdetails.cChannels :=1;
cdetails.paDetails:=@details;
fillstruct(control,cdetails);
result:=MIXERGETCONTROLDETAILS(fmixerhandle,
@cdetails,MIXER_GETCONTROLDETAILSF_VALUE)=0;
peak:=abs(details.LValue) div 180;
end;
function setvolume(controlmixercontrol;
volume:Tvolume):boolean;
var
details:array [0..30] of Integer;
cdetails:TMIXERCONTROLDETAILS;
begin
fillstruct(control,cdetails);
cdetails.cChannels :=2;
cdetails.paDetails:=@details;
details[0]:=volume.left;
details[1]:=volume.right;
result:=MIXERSETCONTROLDETAILS(fmixerhandle,
@cdetails,MIXER_GETCONTROLDETAILSF_VALUE)=0;
end;
function getvolume(controlmixercontrol;var
volume:Tvolume):boolean;
var
details:array [0..30] of Integer;
cdetails:TMIXERCONTROLDETAILS;
begin
fillstruct(control,cdetails);
cdetails.cChannels :=2;
cdetails.paDetails:=@details;
result:=MIXERGETCONTROLDETAILS(fmixerhandle,
@cdetails,MIXER_GETCONTROLDETAILSF_VALUE)=0;
volume.left:=details[0];
volume.right:=details[1];
end;
function setmute(controlmixercontrol;
mute:integer):boolean;
var
cdetails:Tmixercontroldetails;
details:array [0..30] of Integer;
begin
fillstruct(control,cdetails);
cdetails.cChannels :=1;
cdetails.paDetails:=@details;
details[0]:=mute;
result:=MIXERSETCONTROLDETAILS(fmixerhandle,
@cdetails,MIXER_GETCONTROLDETAILSF_VALUE)=0;
end;
function getmute(controlmixercontrol;var
mute:integer):boolean;
var
cdetails:Tmixercontroldetails;
details:array [0..30] of Integer;
begin
fillstruct(control,cdetails);
cdetails.cChannels :=1;
cdetails.cMultipleItems:=0;
cdetails.paDetails:=@details;
result:=MIXERGETCONTROLDETAILS(fmixerhandle,
@cdetails,MIXER_GETCONTROLDETAILSF_VALUE)=0;
mute:=details[0];
end;
procedure TForm2.LinesChange(Sender: TObject);
begin
controls.Items:=line[lines.ItemIndex];
if controls.ItemIndex =-1 then
controls.ItemIndex :=0;
end;
procedure TForm2.ControlsChange(Sender: TObject);
var
mute,k,j:integer;
volume:Tvolume;
begin
lmute.Visible :=false;
lmeter.Visible :=false;
k:=lines.ItemIndex;j:=controls.ItemIndex;
IF mcontrols[k][j][0].Metrics.dwReserved[2]=1 then
begin
lmute.Visible:=mcontrols[k][j][1].dwcontroltype
=MIXERCONTROL_CONTROLTYPE_MUTE;
lmeter.Visible:=mcontrols[k][j][1].dwcontroltype
=MIXERCONTROL_CONTROLTYPE_PEAKMETER;
if lmeter.Visible then
peaknum:=1;
end;
cmute.Enabled :=lmute.Visible ;
IF mcontrols[k][j][0].Metrics.dwReserved[3]=1 then
begin
lmeter.Visible:=mcontrols[k][j][2].dwcontroltype
=MIXERCONTROL_CONTROLTYPE_PEAKMETER;
if lmeter.Visible then
peaknum:=2;
end;
if getvolume(mcontrols[k][j][0],volume) then
begin
Rvolume.Position :=-volume.right;
Lvolume.Position :=-volume.left;
end;
if getmute(mcontrols[k][j][1],mute) then
cmute.Checked :=mute=1;
RProgressbar.Visible :=lmeter.Visible;;
timer1.Enabled:=lmeter.Visible;
end;
procedure TForm2.LVolumeChange(Sender: TObject);
var volume:tvolume;
begin
if checkbox1.Checked then
Rvolume.Position :=Lvolume.Position ;
volume.right :=-Rvolume.Position;
volume.left:=-Lvolume.Position ;
setvolume(mcontrolS[lines.itemindex][controls.itemindex][0],
volume);
end;
procedure TForm2.cmuteClick(Sender: TObject);
var mute:integer;
begin
if cmute.checked then
mute:=1 else
mute:=0;
setmute(mcontrolS[lines.itemindex][controls.itemindex][1],mute);
end;
procedure TForm2.RvolumeChange(Sender: TObject);
begin
if checkbox1.Checked then
Lvolume.Position :=Rvolume.Position ;
Lvolume.OnChange (sender);
end;
procedure TForm2.AboutClick(Sender: TObject);
begin
showmessage('Mixer Demo version 1.0 '+chr(13)
+'Written by David Jiang');
end;
procedure TForm2.BExitClick(Sender: TObject);
begin
close;
end;
procedure TForm2.Timer1Timer(Sender: TObject);
var peak:integer;
begin
IF mcontrols[lines.itemindex][controls.itemindex]
[0].Metrics.dwReserved[peaknum+1]=1 then
if getpeak(mcontrols[lines.itemindex][controls.itemindex]
[peaknum],peak) then
Rprogressbar.Position :=peak;
end;
procedure TForm2.FormClose(Sender: TObject;
var Action: TCloseAction);
begin
mixerclose(fmixerhandle);
end;
end.
http://delphi.sharpplus.com/Recommend/rcAudioMixer.htm
unit Unit2;
//Written by David Jiang(江天送)
//july 25th. 1999
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls,
Forms, Dialogs,StdCtrls, ComCtrls, mmsystem, Buttons, ExtCtrls;
type Tvolume=record
left,right:word;
end;
type
TForm2 = class(TForm)
Lines: TComboBox;
Controls: TComboBox;
Label1: TLabel;
lmute: TLabel;
lmeter: TLabel;
LVolume: TTrackBar;
Rvolume: TTrackBar;
cmute: TCheckBox;
CheckBox1: TCheckBox;
About: TSpeedButton;
BExit: TSpeedButton;
RProgressBar: TProgressBar;
Timer1: TTimer;
procedure FormCreate(Sender: TObject);
procedure getlinecontrol;
procedure LinesChange(Sender: TObject);
procedure ControlsChange(Sender: TObject);
procedure LVolumeChange(Sender: TObject);
procedure cmuteClick(Sender: TObject);
procedure RvolumeChange(Sender: TObject);
procedure AboutClick(Sender: TObject);
procedure BExitClick(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
procedure FormClose(Sender: TObject;
var
Action: TCloseAction);
private
{ Private declarations }
procedure mmixer(var msg:Tmessage);
public
{ Public declarations }
end;
function getvolume(controlmixercontrol;var
volume:Tvolume):boolean;
function setvolume(controlmixercontrol;
volume:Tvolume):boolean;
function setmute(controlmixercontrol;
mute:integer):boolean;
function getmute(controlmixercontrol;var
mute:integer):boolean;
function getpeak(controlmixercontrol;var
peak:integer):boolean;
procedure Fillstruct(controlmixercontrol;var
Cdetails:Tmixercontroldetails);
var
Form2: TForm2;
fmixerhandle:hmixer;
//混音器的句柄
mcontrols:array of array of array of PMixerControl;
line:array of Tstringlist;
peaknum:integer;
//meter mcontrols的位置
implementation
{$R *.DFM}
procedure Tform2.mmixer(var msg:Tmessage);
var
volume:Tvolume;
mute:integer;
begin
if msg.Msg=MM_MIXM_CONTROL_CHANGE then
begin
if mcontrolS[lines.itemindex][controls.itemindex]
[0].dwcontrolID=msg.LParam then
if getvolume(mcontrolS[lines.itemindex]
[controls.itemindex][0],volume) then
begin
Rvolume.Position :=-volume.right;
Lvolume.Position :=-volume.left;
end;
if mcontrolS[lines.itemindex][controls.itemindex]
[1].dwcontrolid=msg.LParam then
if getmute(mcontrolS[lines.itemindex]
[controls.itemindex][1],mute) then
cmute.Checked:=mute=1;
end;
end;
procedure TForm2.FormCreate(Sender: TObject);
begin
getlinecontrol;
lines.ItemIndex :=0;
controls.Items:=line[lines.ItemIndex];
controls.ItemIndex :=0;
controls.OnChange (sender);
end;
procedure Tform2.getlinecontrol;
var
mixerID:integer;
//混音器的ID
FMixerCaps:TMixerCaps;
n,j,k,i:integer;
ml,ml2:TMIXERLINE;
MLC:TMixerLineControls;
PMixerControl;
begin
if mixerGetNumDevs=0 then
exit;
//如没有混合器装置,退出
fmixerhandle:=0;
mixerID:=0;
mixerOpen (@FMixerHandle,mixerID,AllocateHWnd(mmixer),
0,CALLBACK_WINDOW OR MIXER_OBJECTF_MIXER);
//打开混音器
mixerGetDevCaps (mixerID,@FMixerCaps,SizeOf (TMixerCaps));
//返回混音器的兼容性
setlength(line,fmixercaps.cDestinations);
setlength(mcontrols,fmixercaps.cDestinations );
for i:=0 to fmixercaps.cDestinations-1do
begin
ml.dwDestination:=i;
ml.cbStruct :=sizeof(tMIXERLINE);
mixerGetLineInfo(fmixerhandle,@ml,
MIXER_GETLINEINFOF_DESTINATION);
//取得混音器的Destinations
line:=tstringlist.Create ;
setlength(mcontrols,ml.cconnections);
n:=0;
if ml.cControls>1 then
begin
n:=1;
setlength(mcontrols,ml.cconnections+1);
MLC.cbStruct:=SizeOf(MLC);
MLC.dwLineID:=ml.dwLineID;
MLC.cControls:=ml.cControls;
MLC.cbmxctrl:=SizeOf(TMixerControl);
GetMem (P,SizeOf(TMixerControl)*ml.cControls);
MLC.pamxctrl:=P;
MixerGetLineControls(fMixerHandle,@MLC,
MIXER_GETLINECONTROLSF_ALL);
setlength(mcontrols[0],ml.cControls);
line.Add(p^.szname);
//Master Volume
For k:=0 to ml.cControls-1do
begin
mcontrols[0][k]:=p;
mcontrols[0][0].Metrics.dwReserved[k+1]:=1;
inc(p);
end;
end;
lines.Items.Add(ml.szName);
ML2.cbStruct:=SizeOf(TMixerLine);
ML2.dwDestination:=ml.dwDestination ;
for j:=0 to ml.cConnections -1do
begin
ML2.dwSource:=j;
MixerGetLineInfo (fmixerHandle,@ML2,
MIXER_GETLINEINFOF_SOURCE);
MLC.cbStruct:=SizeOf(MLC);
MLC.dwLineID:=ml2.dwLineID;
MLC.cControls:=ml2.cControls;
MLC.cbmxctrl:=SizeOf(TMixerControl);
GetMem (P,SizeOf(TMixerControl)*ml2.cControls);
MLC.pamxctrl:=P;
MixerGetLineControls(fMixerHandle,@MLC,
MIXER_GETLINECONTROLSF_ALL);
setlength(mcontrols[j+n],ml2.cControls);
For k:=0 to ml2.cControls-1do
begin
if p.dwControlType=MIXERCONTROL_CONTROLTYPE_VOLUME
then
line.add(p^.szName);
mcontrols[j+n][k]:=p;
mcontrols[j+n][0].Metrics.dwReserved[k+1]:=1;
inc(p);
end;
//取得混音器线路的控制器
end;
end;
end;
procedure Fillstruct(controlmixercontrol;var
Cdetails:Tmixercontroldetails);
begin
cdetails.cbStruct:=sizeof(cdetails);
cdetails.dwControlID:=control.dwControlID ;
cdetails.cbDetails:=sizeof(integer);
cdetails.hwndOwner :=0;
end;
function getpeak(controlmixercontrol;var
peak:integer):boolean;
var
details:TMIXERCONTROLDETAILSSIGNED;
cdetails:TMIXERCONTROLDETAILS;
begin
result:=false;
if control.dwControlType <>
MIXERCONTROL_CONTROLTYPE_PEAKMETER then
exit;
cdetails.cChannels :=1;
cdetails.paDetails:=@details;
fillstruct(control,cdetails);
result:=MIXERGETCONTROLDETAILS(fmixerhandle,
@cdetails,MIXER_GETCONTROLDETAILSF_VALUE)=0;
peak:=abs(details.LValue) div 180;
end;
function setvolume(controlmixercontrol;
volume:Tvolume):boolean;
var
details:array [0..30] of Integer;
cdetails:TMIXERCONTROLDETAILS;
begin
fillstruct(control,cdetails);
cdetails.cChannels :=2;
cdetails.paDetails:=@details;
details[0]:=volume.left;
details[1]:=volume.right;
result:=MIXERSETCONTROLDETAILS(fmixerhandle,
@cdetails,MIXER_GETCONTROLDETAILSF_VALUE)=0;
end;
function getvolume(controlmixercontrol;var
volume:Tvolume):boolean;
var
details:array [0..30] of Integer;
cdetails:TMIXERCONTROLDETAILS;
begin
fillstruct(control,cdetails);
cdetails.cChannels :=2;
cdetails.paDetails:=@details;
result:=MIXERGETCONTROLDETAILS(fmixerhandle,
@cdetails,MIXER_GETCONTROLDETAILSF_VALUE)=0;
volume.left:=details[0];
volume.right:=details[1];
end;
function setmute(controlmixercontrol;
mute:integer):boolean;
var
cdetails:Tmixercontroldetails;
details:array [0..30] of Integer;
begin
fillstruct(control,cdetails);
cdetails.cChannels :=1;
cdetails.paDetails:=@details;
details[0]:=mute;
result:=MIXERSETCONTROLDETAILS(fmixerhandle,
@cdetails,MIXER_GETCONTROLDETAILSF_VALUE)=0;
end;
function getmute(controlmixercontrol;var
mute:integer):boolean;
var
cdetails:Tmixercontroldetails;
details:array [0..30] of Integer;
begin
fillstruct(control,cdetails);
cdetails.cChannels :=1;
cdetails.cMultipleItems:=0;
cdetails.paDetails:=@details;
result:=MIXERGETCONTROLDETAILS(fmixerhandle,
@cdetails,MIXER_GETCONTROLDETAILSF_VALUE)=0;
mute:=details[0];
end;
procedure TForm2.LinesChange(Sender: TObject);
begin
controls.Items:=line[lines.ItemIndex];
if controls.ItemIndex =-1 then
controls.ItemIndex :=0;
end;
procedure TForm2.ControlsChange(Sender: TObject);
var
mute,k,j:integer;
volume:Tvolume;
begin
lmute.Visible :=false;
lmeter.Visible :=false;
k:=lines.ItemIndex;j:=controls.ItemIndex;
IF mcontrols[k][j][0].Metrics.dwReserved[2]=1 then
begin
lmute.Visible:=mcontrols[k][j][1].dwcontroltype
=MIXERCONTROL_CONTROLTYPE_MUTE;
lmeter.Visible:=mcontrols[k][j][1].dwcontroltype
=MIXERCONTROL_CONTROLTYPE_PEAKMETER;
if lmeter.Visible then
peaknum:=1;
end;
cmute.Enabled :=lmute.Visible ;
IF mcontrols[k][j][0].Metrics.dwReserved[3]=1 then
begin
lmeter.Visible:=mcontrols[k][j][2].dwcontroltype
=MIXERCONTROL_CONTROLTYPE_PEAKMETER;
if lmeter.Visible then
peaknum:=2;
end;
if getvolume(mcontrols[k][j][0],volume) then
begin
Rvolume.Position :=-volume.right;
Lvolume.Position :=-volume.left;
end;
if getmute(mcontrols[k][j][1],mute) then
cmute.Checked :=mute=1;
RProgressbar.Visible :=lmeter.Visible;;
timer1.Enabled:=lmeter.Visible;
end;
procedure TForm2.LVolumeChange(Sender: TObject);
var volume:tvolume;
begin
if checkbox1.Checked then
Rvolume.Position :=Lvolume.Position ;
volume.right :=-Rvolume.Position;
volume.left:=-Lvolume.Position ;
setvolume(mcontrolS[lines.itemindex][controls.itemindex][0],
volume);
end;
procedure TForm2.cmuteClick(Sender: TObject);
var mute:integer;
begin
if cmute.checked then
mute:=1 else
mute:=0;
setmute(mcontrolS[lines.itemindex][controls.itemindex][1],mute);
end;
procedure TForm2.RvolumeChange(Sender: TObject);
begin
if checkbox1.Checked then
Lvolume.Position :=Rvolume.Position ;
Lvolume.OnChange (sender);
end;
procedure TForm2.AboutClick(Sender: TObject);
begin
showmessage('Mixer Demo version 1.0 '+chr(13)
+'Written by David Jiang');
end;
procedure TForm2.BExitClick(Sender: TObject);
begin
close;
end;
procedure TForm2.Timer1Timer(Sender: TObject);
var peak:integer;
begin
IF mcontrols[lines.itemindex][controls.itemindex]
[0].Metrics.dwReserved[peaknum+1]=1 then
if getpeak(mcontrols[lines.itemindex][controls.itemindex]
[peaknum],peak) then
Rprogressbar.Position :=peak;
end;
procedure TForm2.FormClose(Sender: TObject;
var Action: TCloseAction);
begin
mixerclose(fmixerhandle);
end;
end.