home *** CD-ROM | disk | FTP | other *** search
Wrap
// ô¥ìçâAü[âJâCâoâRâôâ|ü[âlâôâg for Delphi/C++Builder // Common Archivers Component for Delphi/C++Builder // Copyright(C) NORG1964/Masashi Yoneda 1997-2001 // // YZ1è╓ÿAâéâWâàü[âï YZ132.PAS // // v1.32:YZ1.DLL/YYZ32.DLLé╔éµéΘYZ1î`Ä«Åæî╔é╓é╠æ╬ë₧é≡èJÄn // v1.34:TYZ1 é¬É╢ɼé╖éΘâRâ}âôâhâëâCâôé≡ YZ1.DLL 0.20 / YYZ32.DLL 0.08 // ïñÆ╩Ädùlé╔ìçéφé╣é╜ // TYZ1 é¬Ägùpé╖éΘ DLL é╠èOòöâåâjâbâgé⌐éτé╠ò╧ìXé╔æ╬ë₧ // TYZ1 é┼ YZ1.DLL ôαé┼é╠ùßèOæ╬ì⌠é≡Æ╟ë┴ // v1.35:TYZ1.Yz1 é¬ CmdLine ê°Éöé≡î⌐é─éóé╚é⌐é┴é╜òsï∩ìçé╠ÅCÉ│ // ÉV YZ1.DLL ( ûóâèâèü[âX ) é╠ y âIâvâVâçâôé╔æ╬ë₧ // v1.38:DLL é⌐éτé╠âGâôâgâèâ|âCâôâgé╠ĵô╛ò√û@é≡ò╧ìXé╡é╜ // v1.39:YZ1.DLL é╠ âpâXâÅü[âhè╓ÿA API é╓é╠æ╬ë₧é≡Æ╟ë┴ // unit YZ132; // Unitû╝é¬YZ1é╛é╞âGâëü[é╔é╚éΘé╠é┼éΓé▐é╚é¡ interface uses Windows, SysUtils, Classes, Archives; type TYZ1 = class( TArchiver ) protected class procedure LoadDll; override; class procedure FreeDll; override; protected function BuildCmdLine( Cmd,ArchiveFileName:string;Options:TArchiverOptions;Path:String;FileList:array of const;UseResFile:boolean ):String; function FindOpen ( Handle:HWND;ArchiveFileName:string;dwMode:DWORD ):THARC; override; function FindFirst( hArc:THArc;var IndivisualInfo:TIndivisualInfo;FileMask:string ):integer; override; function FindNext ( hArc:THArc;var IndivisualInfo:TIndivisualInfo ):integer; override; function FindClose( hArc:THArc ):integer; override; public function Yz1( Handle:HWND;cmdline:string;var Output:string ):integer; function UnpackFiles ( Handle:HWND;ArchiveFileName:string;Options:TArchiverOptions;DstPath:String;FileList:array of const;UseResFile:boolean;var Output:string ):Integer; override; function PackFiles ( Handle:HWND;ArchiveFileName:string;Options:TArchiverOptions;BaseDir:String;FileList:array of const;UseResFile:boolean;var Output:string ):Integer; override; // function RemoveItems ( Handle:HWND;ArchiveFileName:string;Options:TArchiverOptions;BaseDir:String;FileList:array of const;UseResFile:boolean;var Output:string ):Integer; override; function MakeSfx ( Handle:HWND;ArchiveFileName:string;Options:TArchiverOptions;DstPath:String ;var Output:string ):Integer; override; // function UnpackToMem ( Handle:HWND;ArchiveFileName:string;Options:TArchiverOptions;FileName:string;lpvBuffer:LPVOID;dwSize:DWORD;lpdwWriteSize:LPDWORD ):Integer; override; function CheckArchive ( ArchiveFileName:string;CheckMode:integer;CheckOptions:integer ):DWORD; override; function SetOwnerWindowEx ( Handle:HWND;lpArcProc:LPARCHIVERPROC ):boolean; override; function KillOwnerWindowEx( Handle:HWND ):boolean; override; end; function IsYz1Archive( ArchiveFileName:string ):boolean; const Yz1DllName1: PChar = 'YYZ32.DLL'; Yz1DllName2: PChar = 'YZ1.DLL'; implementation uses Filters; type TYz1DLLSetDefaultPassword = function( hArc:THArc;lpszPassword:PAnsiChar ):integer; stdcall; TYz1DLLPasswordDialog = function( hwndParent:HWND;lpszPassword:PAnsiChar;dwSize:DWORD ):integer; stdcall; TYZ1Dll = class( TArchiverDll ) private protected FHandle: HWND; FSetDefaultPassword: FARPROC; FPasswordDialog: FARPROC; public function OpenArchive( Handle:HWND;ArchiveFileName:string;dwMode:DWORD ):THARC; override; function FindFirst( hArc:THArc;FileMask:string;IndivisualInfo:PIndivisualInfo ):integer; override; function SetDefaultPassword( hArc:THArc;lpszPassword:PAnsiChar ):integer; function EnterPassword( hwndParent:HWND;lpszPassword:PAnsiChar;dwSize:DWORD ):integer; end; //--------------------------------------------------------------------- var FArchiver: TArchiverDLL; function Yz1DllName:string; begin if( Yz1DllName1 <> nil )and( Yz1DllName2 <> nil ) then begin result := Yz1DllName1 + ' é⌐ ' + Yz1DllName2; end else begin if( Yz1DllName1 <> nil ) then result := Yz1DllName1; if( Yz1DllName2 <> nil ) then result := Yz1DllName2; end; end; procedure LoadDll; begin if Assigned( FArchiver ) then exit; if Assigned( Yz1DllName1 ) then begin try FArchiver := TYZ1Dll.Create( 'YZ1 î`Ä«Åæî╔',Yz1DllName1,'Yz1' ); FArchiver.LoadDLL; exit; except FArchiver.Free; FArchiver := nil; end; end; if Assigned( Yz1DllName2 ) then begin try FArchiver := TYZ1Dll.Create( 'YZ1 î`Ä«Åæî╔',Yz1DllName2,'Yz1' ); FArchiver.LoadDLL; exit; except FArchiver.Free; FArchiver := nil; end; end; raise EArchiver.Create( 'Yz1 î`Ä«Åæî╔é≡ê╡éñé╔é═ '+Yz1DllName+' é¬òKùvé┼é╖üB' ); end; procedure FreeDll; begin FArchiver.Free; FArchiver := nil; end; //--------------------------------------------------------------------- class procedure TYZ1.LoadDll; begin YZ132.LoadDll; end; class procedure TYZ1.FreeDll; begin YZ132.FreeDll; end; function TYZ1.UnpackFiles( Handle:HWND;ArchiveFileName:string;Options:TArchiverOptions;DstPath:String;FileList:array of const;UseResFile:boolean;var Output:string ):Integer; begin FCmdLine := BuildCmdLine( 'x',ArchiveFileName,Options,DstPath,FileList,UseResFile ); result := Yz1( Handle,FCmdLine,Output ); end; function TYZ1.PackFiles( Handle:HWND;ArchiveFileName:string;Options:TArchiverOptions;BaseDir:String;FileList:array of const;UseResFile:boolean;var Output:string ):Integer; begin FCmdLine := BuildCmdLine( 'c',ArchiveFileName,Options,BaseDir,FileList,UseResFile ); result := Yz1( Handle,FCmdLine,Output ); end; { function TYZ1.RemoveItems( Handle:HWND;ArchiveFileName:string;Options:TArchiverOptions;BaseDir:String;FileList:array of const;UseResFile:boolean;var Output:string ):Integer; begin FCmdLine := BuildCmdLine( 'd',ArchiveFileName,Options,'',FileList,ruOnRemoveItem in Options.ResFileUsage ); result := Yz1( Handle,FCmdLine,Output ); end; } function TYZ1.MakeSfx( Handle:HWND;ArchiveFileName:string;Options:TArchiverOptions;DstPath:String;var Output:string ):Integer; var SfxDat: array[0..511] of char; SfxName: string; SfxHead: TFileStream; SfxFile: TFileStream; ArcFile: TFileStream; P: PAnsiChar; SfxDecoder: string; dwFileSize: DWORD; begin if Options.gw > 0 then begin SfxDecoder := 'yzw32cui.sfx'; if SearchPath( nil,PChar( SfxDecoder ),nil,SizeOf( SfxDat ),SfxDat,P ) = 0 then begin SfxDecoder := 'yzdec.exe'; if SearchPath( nil,PChar( SfxDecoder ),nil,SizeOf( SfxDat ),SfxDat,P ) = 0 then begin raise EArchiver.Create( 'yz1 Åæî╔é⌐éτé╠Win32Ä⌐î╚ë≡ôÇÅæî╔é╠ì∞ɼé╔é═ yzw32cui.sfx é⌐ yzdec.exe é¬òKùvé┼é╖üB' ); end; end; end else begin SfxDecoder := 'yzdos16.sfx'; if SearchPath( nil,PChar( SfxDecoder ),nil,SizeOf( SfxDat ),SfxDat,P ) = 0 then raise EArchiver.Create( 'yz1 Åæî╔é⌐éτé╠DOSÄ⌐î╚ë≡ôÇÅæî╔é╠ì∞ɼé╔é═ '+SfxDecoder+' é¬òKùvé┼é╖üB' ); end; SfxName := ChangeFileExt( ArchiveFileName,'.exe' ); if DstPath <> '' then begin SfxName := ExtractFileName( SfxName ); SfxName := MakeFileName( DstPath,SfxName ); end; ArcFile := TFileStream.Create( ArchiveFileName,fmOpenRead+fmShareDenyWrite ); SfxFile := TFileStream.Create( SfxName ,fmCreate ); SfxHead := TFileStream.Create( SfxDat ,fmOpenRead+fmShareDenyWrite ); dwFileSize := ArcFile.Size; dwFileSize := (( dwFileSize and $000000FF ) shl 24 ) or (( dwFileSize and $0000FF00 ) shl 8 ) or (( dwFileSize and $00FF0000 ) shr 8 ) or (( dwFileSize and $FF000000 ) shr 24 ); try SfxFile.CopyFrom( SfxHead,0 ); SfxFile.CopyFrom( ArcFile,0 ); SfxFile.WriteBuffer( dwFileSize,sizeof( dwFileSize )); finally ArcFile.Free; SfxFile.Free; SfxHead.Free; end; result := 0; end; function TYZ1.CheckArchive( ArchiveFileName:string;CheckMode:integer;CheckOptions:integer ):DWORD; begin result := FArchiver.CheckArchive( PChar( ArchiveFileName ),CheckMode+CheckOptions ); end; function TYZ1.SetOwnerWindowEx ( Handle:HWND;lpArcProc:LPARCHIVERPROC ):boolean; begin inherited SetOwnerWindowEx( Handle,lpArcProc ); result := FArchiver.SetOwnerWindowEx( Handle,lpArcProc ); end; function TYZ1.KillOwnerWindowEx( Handle:HWND ):boolean; begin result := FArchiver.KillOwnerWindowEx( Handle ); inherited KillOwnerWindowEx( Handle ); end; function TYZ1.Yz1( Handle:HWND;CmdLine:string;var Output:string ):integer; begin try result := FArchiver.ArchiverProc( Handle,PChar( CmdLine ),PAnsiChar( Output ),Length( Output )); except EnableWindow( Handle,True ); // YZ1.DLL é┼ùßèOö¡É╢Ä₧üADisable é╠é▄é▄ïAéΘé▒é╞é¬éáéΘ raise; end; end; function TYZ1.BuildCmdLine( Cmd,ArchiveFileName:string;Options:TArchiverOptions;Path:String;FileList:array of const;UseResFile:boolean ):String; var CmdLine: TCmdOpt; opt_c: integer; opt_y: integer; begin with Options do begin CmdLine := TCmdOpt.Create; opt_c := c; opt_y := aoiUnassigned; case m of 0: opt_y := 2; // éóé┐éóé┐Ä┐ûΓ 1: opt_y := 1; // æSé─ Yes 2: opt_y := 2; // ègÆúÄqé≡ò╧ìXé╡é─ôWèJ - no support 9: opt_y := 0; // æSé─ No // else opt_y := 2; // é╞éΦéáéªé╕æSòöÄ┐ûΓé╡é╞é¡ end; if opt_y = 2 then opt_c := 2; CmdLine.Add( '-+' ); // Åφé╔âîâWâXâgâèé╠É▌ÆΦé≡û│Äïé╖éΘ // CmdLine.AddBolOpt( 'a' ,a > 0 ); // a[0|1|2] æ«É½é╠ì─î╗üB CmdLine.AddIntOpt( 'c' ,opt_c ); // c[0|1] â^âCâÇâXâ^âôâvîƒì╕é≡Å╚ù¬ //// CmdLine.AddIntOpt( 'd' ,d ); // d[0|1] âfâBâîâNâgâèû╝é╠èiö[ // CmdLine.AddIntOpt( 'e' ,e ); // e[0|1] ĽÅæâTâCâYé≡ö╝ò¬é╔é╡é─ê│Åk // CmdLine.AddIntOpt( 'f' ,f ); // f[0|1] âfâBâXâNÄcù╩â`âFâbâNé╠ÆåÄ~ // CmdLine.AddIntOpt( 'h' ,h ); // h[0|1|2|3] âwâbâ_é╠î`Ä«é≡ÄwÆΦ // CmdLine.AddIntOpt( 'i' ,i ); // i[0|1|2] âtâ@âCâïæIæ≡é┼æσò╢ÄÜé╞żò╢ÄÜé≡ïµò╩ // CmdLine.AddIntOpt( 'l' ,l ); // l[0|1|2] ôWèJâìâOé╠âtâ@âCâïû╝é╠ò\Īû@é╠ò╧ìX CmdLine.AddIntOpt( 'y',opt_y ); // m[0|1|2] Ä┐ûΓé╔ yes é╞ë╝ÆΦ CmdLine.AddBolOpt( 'i',( n > 0 )or( CallbackEnabled )); // n[0|1] ôWèJÅ≤ï╡â_âCâAâìâOò\Īé╠ù}Ä~ // CmdLine.AddIntOpt( 'o' ,o ); // o[0|1|2] ïîî`Ä«é┼Åæî╔é≡ì∞ɼ CmdLine.AddIntOpt( 'z' ,p ); // p[0|1|2] æSâpâXû╝é┼ìçÆv // CmdLine.AddBolOpt( 'r' ,r > 0 ); // r[0|1|2] ì─ïAôIîƒì⌡ // CmdLine.AddIntOpt( 's' ,s ); // s[0|1] âXâLâbâvò\Īé╠ù}ɺ // CmdLine.AddIntOpt( 't' ,t ); // t[0|1] Åæî╔é╠ìXÉVô·Ä₧é╠ÄwÆΦ // // CmdLine.AddIntOpt( 'u' ,u ); // u[0|1] âtâ@âCâïé╠ìXÉVüiÉVé╡éóéαé╠üj // CmdLine.AddPath1 ( 'w' ,w ); // w[0|1|<Dirû╝>] ì∞ï╞ùpâfâBâîâNâgâèé╠ÄwÆΦ CmdLine.AddIntOpt( 'x' ,x ); // x[0|1] âfâBâîâNâgâèû╝é≡ùLî°é╔é╖éΘ // CmdLine.AddIntOpt( 'y' ,y ); // y[0|1] æSé─é╠Ä┐ûΓé╔ yes é╞ë╝ÆΦ // CmdLine.AddIntOpt( 'z' ,z ); // z[0|1|2|<ègÆúÄq>] ûóê│Åkâtâ@âCâïé╠ÄwÆΦ ###ègÆúÄqé═âTâ|ü[âgé╡é╚éó### // CmdLine.AddIntOpt( 'jc' ,jc ); // jc[0|1] öjæ╣âwâbâ_é≡û│Äï // CmdLine.AddIntOpt( 'jd' ,jd ); // jd[<âTâCâY>] âfâBâXâNé╠ï≤é½ùeù╩é≡èmöF // CmdLine.AddIntOpt( 'je' ,je ); // je[<âTâCâY>] Huffman âoâbâtâ@é╠æσé½é│é≡ÄwÆΦ // CmdLine.AddIntOpt( 'jf' ,jf ); // jf[0|1] âïü[âgïLìåé╠ìφÅ£ // CmdLine.AddIntOpt( 'jh' ,jh ); // jh[0|1] WindowsNT/95 ÉΩùpé╠â}ü[âNé≡Åæî╔é╔òtë┴ // CmdLine.AddIntOpt( 'ji' ,ji ); // ji[0|1] ÆZéóâtâ@âCâïû╝é┼èiö[ // CmdLine.AddIntOpt( 'l' ,jm ); // jm[0|1|2|3|4] ê│Åkî`Ä«é≡ÄwÆΦ // CmdLine.AddIntOpt( 'jn' ,jn ); // jn[0|1] ÉVïKâtâ@âCâïé╠é▌ // CmdLine.AddStrOpt( 'jo' ,jo ); // jo[<Ä₧ìÅÄwÆΦ>] YYMMDDHHMMSS é╠ô·òtê╚ì~ // CmdLine.AddStrOpt( 'job',job ); // job[<Ä₧ìÅÄwÆΦ>] YYMMDDHHMMSS é╠ô·òtê╚æO // CmdLine.AddIntOpt( 'jp' ,jp ); // jp[0|1] ÉiÆ╗âoü[é≡âvâìâOâîâXüEâoü[é┼ò\Ī // CmdLine.AddIntOpt( 'jr' ,jr ); // jr[0|1] âtâ@âCâïé╠Æué½è╖éª // CmdLine.AddIntOpt( 'jss',jss ); // jss[0|1] ê│Åkâtâ@âCâïâIü[âvâôâGâëü[é≡û│ÄïüBÆ╩ÅφüCê│ÅkÄ₧é╔ê│Åkæ╬Å█âtâ@ // CmdLine.AddIntOpt( 'jw' ,jw ); // jw[0|1|2|3|4] WinSFX/WinSFXM é≡ì∞ɼ // CmdLine.AddFList2( 'jx' ,[jx] ); // jx[<âtâ@âCâïû╝>] Å£èOé╖éΘâtâ@âCâïû╝ // CmdLine.AddIntOpt( 'jyc',jyc ); // jyc[0|1] âfâBâîâNâgâèì∞ɼé╠èmöFé≡Å╚ù¬ // CmdLine.AddIntOpt( 'jyd',jyd ); // jyd[0|1] âtâ@âCâïìφÅ£é╠èmöFé≡Å╚ù¬ // CmdLine.AddIntOpt( 'jyk',jyk ); // jyk[0|1] Ägùpé┼é½éΘâfâBâXâNùeù╩é╠èmöFé╠Å╚ù¬ // CmdLine.AddIntOpt( 'jyn',jyn ); // jyn[0|1] ÉVâtâ@âCâïû╝é╠ùvïüé╠Å╚ù¬ // CmdLine.AddIntOpt( 'jyo',jyo ); // jyo[0|1] è∙æ╢âtâ@âCâïé╓é╠ÅπÅæé½èmöFé╠Å╚ù¬ // CmdLine.AddStrOpt( 'jz' ,jz ); // jz[<âtâ@âCâïû╝>] âtâ@âCâïÆìÄ▀é╠âtâ@âCâïé≡ïƒïï // CmdLine.AddIntOpt( 'ga' ,ga ); // ga[0|1] Åæé½ì₧é▌òsë┬æ«É½é≡û│Äï // CmdLine.AddIntOpt( 'gd' ,gd ); // gd[0|1] ù]ò¬é╚âfü[â^é╠ìφÅ£ // CmdLine.AddIntOpt( 'ge' ,ge ); // ge[0|1] ì┼Åëé╠ègÆúÄqé≡öFÄ» // CmdLine.AddIntOpt( 'gf' ,gf ); // gf[0|1|2] é╖é┼é╔éáéΘâtâ@âCâïé╠ìXÉV // CmdLine.AddIntOpt( 'gj' ,gj ); // gj[0|1] x û╜ù▀é≡ e û╜ù▀é╞ô»ùlé╞î⌐é╚é╖ // CmdLine.AddIntOpt( 'gm' ,gm ); // gm[0|1] âGâëü[âüâbâZü[âWò\Īé╠ù}Ä~ // CmdLine.AddIntOpt( 'gn' ,gn ); // gn[0|1|2] ôWèJâtâ@âCâïé╠ìçîvâTâCâYé≡ 100% é╞é╡é╜ÉiÆ╗âOâëâté╠ò\Ī // CmdLine.AddIntOpt( 'go' ,go ); // go[0|1] â_âCâAâìâOé╠âIü[âiü[âEâBâôâhâEé╠ÄwÆΦ // CmdLine.AddIntOpt( 'gp' ,gp ); // gp[0|1] âEâBâôâhâEé≡ Disable é╔é╡é╚éó // CmdLine.AddStrOpt( 'gr' ,gr ); // gr[<âtâ@âCâïû╝>] ò╧ìXâtâ@âCâïû╝é≡ïƒïï // CmdLine.AddIntOpt( 'gs' ,gs ); // gs[<âTâCâY>] âwâbâ_îƒì⌡âTâCâYé╠ÄwÆΦ // CmdLine.AddIntOpt( 'gu' ,gu ); // gu[0|1] WinSFXüCDosSFX é╔æSé─é╠âtâ@âCâïé≡èiö[ // CmdLine.AddIntOpt( 'gw' ,gw ); // gw[0|1|2|3|4] WinSFX32/WinSFX32M é≡ì∞ɼ CmdLine.Add( UserOptions ); AddFileSpec1( CmdLine,ArchiveFileName,Path ); AddFileSpec2( CmdLine,Options,FileList,UseResFile ); result := cmd + CmdLine.Str; CmdLine.Free; end; end; function TYZ1.FindOpen( Handle:HWND;ArchiveFileName:string;dwMode:DWORD ):THARC; begin result := FArchiver.OpenArchive( Handle,PChar( ExpandFileName( ArchiveFileName )),dwMode ); end; function TYZ1.FindClose( hArc:THArc ):integer; begin result := FArchiver.CloseArchive( hArc ); end; function TYZ1.FindFirst( hArc:THArc;var IndivisualInfo:TIndivisualInfo;FileMask:string ):integer; begin result := FArchiver.FindFirst( hArc,PChar( FileMask ),@IndivisualInfo ); end; function TYZ1.FindNext( hArc:THArc;var IndivisualInfo:TIndivisualInfo ):integer; begin result := FArchiver.FindNext( hArc,@IndivisualInfo ) end; // function IsYz1Archive( ArchiveFileName:string ):boolean; // var // SfxType: integer; // begin // try // LoadDll; // SfxType:= Yz1CheckArchive( PChar( ExpandFileName( ArchiveFileName )),CHECKARCHIVE_SFX+CHECKARCHIVE_ALL ); // result := ( SfxType <> -1 ); // except // result := false; // end; // end; function IsYz1Archive( ArchiveFileName:string ):boolean; var hArc: THARC; begin try LoadDLL; ArchiveFileName := ExpandFileName( ArchiveFileName ); result := false; if not FileExists( ArchiveFileName ) then exit; hArc := FArchiver.OpenArchive( 0,PAnsiChar( ArchiveFileName ),M_REGARDLESS_INIT_FILE+M_ERROR_MESSAGE_OFF ); FArchiver.CloseArchive( hArc ); result := ( hArc <> 0 ); except result := false; end; end; { TYZ1Dll } function TYZ1Dll.OpenArchive( Handle:HWND;ArchiveFileName:string;dwMode:DWORD ):THARC; begin FHandle := Handle; result := inherited OpenArchive( Handle,PAnsiChar( ArchiveFileName ),dwMode ); end; function TYZ1Dll.FindFirst( hArc:THArc;FileMask:string;IndivisualInfo:PIndivisualInfo ):integer; var szPassword: array[0..255] of AnsiChar; i: integer; begin for i := 0 to 3 do begin result := inherited FindFirst( hArc,PAnsiChar( FileMask ),IndivisualInfo ); if result <> ERROR_PASSWORD_FILE then break; if EnterPassword( FHandle,szPassword,sizeof( szPassword )) < 0 then exit; SetDefaultPassword( hArc,szPassword ); end; end; function TYZ1Dll.SetDefaultPassword( hArc:THArc;lpszPassword:PAnsiChar ):integer; begin if GetProcAddr( FSetDefaultPassword,FhDLL,FEntryPrefix+'SetDefaultPassword',false ) = false then begin Result := -1; exit; end; result := TYz1DLLSetDefaultPassword( FSetDefaultPassword )( hArc,lpszPassword ); end; function TYZ1Dll.EnterPassword( hwndParent:HWND;lpszPassword:PAnsiChar;dwSize:DWORD ):integer; begin if GetProcAddr( FPasswordDialog,FhDLL,FEntryPrefix+'PasswordDialog',false ) = false then begin Result := -1; exit; end; result := TYz1DLLPasswordDialog( FPasswordDialog )( hwndParent,lpszPassword,dwSize ); end; end.