You are here

Launcher Not Using Right Reg File

20 posts / 0 new
Last post
Devo
Offline
Last seen: 4 months 1 week ago
Joined: 2007-09-04 14:55
Launcher Not Using Right Reg File

I've been working on a Winamp launcher to apply a reg key for the pro registration. I previously posted about this here (https://portableapps.com/node/12246), but decided to bring this up in this forum because it is more about development now. I've been using the PuttyPortable source and changing it so that I can use it with winamp. The only problem I have now it that the launcher will not use the registry entry in the \Data\settings folder. I've placed a reg entry in there containing the pro registration, but the launcher backs that reg up as a .reg.old file and creates a new blank one that it uses. This is the first time I've ever tried to do anything like this, so I have no idea how to fix this. What do I need to do? I appreciate any help.

ZachHudock
ZachHudock's picture
Offline
Last seen: 3 weeks 6 days ago
Developer
Joined: 2006-12-06 18:07
Can you add your source code

Can you add your source code into your post here? please remember to enclose the source in <pre> </pre> tags so that it remains properly formatted and does not distort the web-page.

The developer formerly known as ZGitRDun8705

Devo
Offline
Last seen: 4 months 1 week ago
Joined: 2007-09-04 14:55
Yeah, here is the source. I

Yeah, here is the source. I know the problem occurs in the Registry Backup section, but I'm not really sure what everything does, so I don't know how to fix it.

!define NAME "WinampPortable"
!define PORTABLEAPPNAME "Winamp Portable"
!define APPNAME "Winamp"
!define VER "5.52.0.0"
!define WEBSITE "http://www.winamp.com"
!define DEFAULTEXE "winamp.exe"
!define DEFAULTAPPDIR "winamp"
!define DEFAULTSETTINGSDIR "settings"

;=== Program Details
Name "${PORTABLEAPPNAME}"
OutFile "..\..\${NAME}.exe"
Caption "${PORTABLEAPPNAME}"
VIProductVersion "${VER}"
VIAddVersionKey ProductName "${PORTABLEAPPNAME}"
VIAddVersionKey Comments "Allows ${APPNAME} to be run from a removable drive.  For additional details, visit ${WEBSITE}"
VIAddVersionKey CompanyName ""
VIAddVersionKey LegalCopyright ""
VIAddVersionKey FileDescription "${PORTABLEAPPNAME}"
VIAddVersionKey FileVersion "${VER}"
VIAddVersionKey ProductVersion "${VER}"
VIAddVersionKey InternalName "${PORTABLEAPPNAME}"
VIAddVersionKey LegalTrademarks ""
VIAddVersionKey OriginalFilename "${NAME}.exe"
;VIAddVersionKey PrivateBuild ""
;VIAddVersionKey SpecialBuild ""

;=== Runtime Switches
CRCCheck On
WindowIcon Off
SilentInstall Silent
AutoCloseWindow True
RequestExecutionLevel user

; Best Compression
SetCompress Auto
SetCompressor /SOLID lzma
SetCompressorDictSize 32
SetDatablockOptimize On

;=== Include
!include "GetParameters.nsh"
!include "Registry.nsh"
!include "ReplaceInFile.nsh"
!include "StrRep.nsh"
!include "MUI.nsh"

;=== Program Icon
Icon "..\..\App\AppInfo\appicon.ico"

;=== Icon & Stye ===
!define MUI_ICON "..\..\App\AppInfo\appicon.ico"

;=== Languages
!insertmacro MUI_LANGUAGE "English"

LangString LauncherFileNotFound ${LANG_ENGLISH} "${PORTABLEAPPNAME} cannot be started. You may wish to re-install to fix this issue. (ERROR: $MISSINGFILEORPATH could not be found)"
LangString LauncherAlreadyRunning ${LANG_ENGLISH} "Another instance of ${APPNAME} is already running. Please close other instances of ${APPNAME} before launching ${PORTABLEAPPNAME}."
LangString LauncherAskCopyLocal ${LANG_ENGLISH} "${PORTABLEAPPNAME} appears to be running from a location that is read-only. Would you like to temporarily copy it to the local hard drive and run it from there?$\n$\nPrivacy Note: If you say Yes, your personal data within ${PORTABLEAPPNAME} will be temporarily copied to a local drive. Although this copy of your data will be deleted when you close ${PORTABLEAPPNAME}, it may be possible for someone else to access your data later."
LangString LauncherNoReadOnly ${LANG_ENGLISH} "${PORTABLEAPPNAME} can not run directly from a read-only location and will now close."


Var PROGRAMDIRECTORY
Var SETTINGSDIRECTORY
Var ADDITIONALPARAMETERS
Var EXECSTRING
Var PROGRAMEXECUTABLE
Var INIPATH
Var SECONDARYLAUNCH
Var DISABLESPLASHSCREEN
Var FAILEDTORESTOREKEY
Var MISSINGFILEORPATH


Section "Main"
	;=== Check if already running
	System::Call 'kernel32::CreateMutexA(i 0, i 0, t "${NAME}") i .r1 ?e'
	Pop $0
	StrCmp $0 0 CheckINI
		StrCpy $SECONDARYLAUNCH "true"

	CheckINI:
		;=== Find the INI file, if there is one
		IfFileExists "$EXEDIR\${NAME}.ini" "" NoINI
			StrCpy "$INIPATH" "$EXEDIR"
			Goto ReadINI

	ReadINI:
		;=== Read the parameters from the INI file
		ReadINIStr $0 "$INIPATH\${NAME}.ini" "${NAME}" "${APPNAME}Directory"
		StrCpy "$PROGRAMDIRECTORY" "$EXEDIR\$0"
		ReadINIStr $0 "$INIPATH\${NAME}.ini" "${NAME}" "SettingsDirectory"
		StrCpy "$SETTINGSDIRECTORY" "$EXEDIR\$0"
	

		;=== Check that the above required parameters are present
		IfErrors NoINI
		ReadINIStr $ADDITIONALPARAMETERS "$INIPATH\${NAME}.ini" "${NAME}" "AdditionalParameters"
		ReadINIStr $DISABLESPLASHSCREEN "$INIPATH\${NAME}.ini" "${NAME}" "DisableSplashScreen"

	;CleanUpAnyErrors:
		;=== Any missing unrequired INI entries will be an empty string, ignore associated errors
		ClearErrors

		;=== Correct PROGRAMEXECUTABLE if blank
		StrCmp $PROGRAMEXECUTABLE "" "" EndINI
			StrCpy "$PROGRAMEXECUTABLE" "${DEFAULTEXE}"
			Goto EndINI

	NoINI:
		;=== No INI file, so we'll use the defaults
		StrCpy "$ADDITIONALPARAMETERS" ""
		StrCpy "$PROGRAMEXECUTABLE" "${DEFAULTEXE}"

		IfFileExists "$EXEDIR\App\${DEFAULTAPPDIR}\${DEFAULTEXE}" "" NoProgramEXE
			StrCpy "$PROGRAMDIRECTORY" "$EXEDIR\App\${DEFAULTAPPDIR}"
			StrCpy "$SETTINGSDIRECTORY" "$EXEDIR\Data\${DEFAULTSETTINGSDIR}"
			GoTo EndINI

	EndINI:
		IfFileExists "$PROGRAMDIRECTORY\$PROGRAMEXECUTABLE" FoundProgramEXE

	NoProgramEXE:
		;=== Program executable not where expected
		StrCpy $MISSINGFILEORPATH $PROGRAMEXECUTABLE
		MessageBox MB_OK|MB_ICONEXCLAMATION `$(LauncherFileNotFound)`
		Abort
		
	FoundProgramEXE:
		;=== Check if running
		StrCmp $SECONDARYLAUNCH "true" GetPassedParameters
		FindProcDLL::FindProc "winamp.exe"
		StrCmp $R0 "1" WarnAnotherInstance DisplaySplash

	WarnAnotherInstance:
		MessageBox MB_OK|MB_ICONEXCLAMATION `$(LauncherAlreadyRunning)`
		Abort
	
	DisplaySplash:
		StrCmp $DISABLESPLASHSCREEN "true" GetPassedParameters
			;=== Show the splash screen while processing registry entries
			InitPluginsDir
			File /oname=$PLUGINSDIR\splash.jpg "${NAME}.jpg"
			newadvsplash::show /NOUNLOAD 1200 0 0 -1 /L $PLUGINSDIR\splash.jpg
	
	GetPassedParameters:
		;=== Get any passed parameters
		Call GetParameters
		Pop $0
		StrCmp "'$0'" "''" "" LaunchProgramParameters

		;=== No parameters
		StrCpy $EXECSTRING `"$PROGRAMDIRECTORY\$PROGRAMEXECUTABLE"`
		Goto AdditionalParameters

	LaunchProgramParameters:
		StrCpy $EXECSTRING `"$PROGRAMDIRECTORY\$PROGRAMEXECUTABLE" $0`

	AdditionalParameters:
		StrCmp $ADDITIONALPARAMETERS "" SettingsDirectory

		;=== Additional Parameters
		StrCpy $EXECSTRING `$EXECSTRING $ADDITIONALPARAMETERS`
	
	SettingsDirectory:
		;=== Set the settings directory if we have a path
		IfFileExists "$SETTINGSDIRECTORY\*.*" "" RegistryBackup
			CreateDirectory $SETTINGSDIRECTORY
	
	RegistryBackup:
		StrCmp $SECONDARYLAUNCH "true" LaunchAndExit
		;=== Backup the registry
		${registry::KeyExists} "HKEY_LOCAL_MACHINE\SOFTWARE\Nullsoft-BackupByWinampPortable" $R0
		StrCmp $R0 "0" RestoreSettings
		${registry::KeyExists} "HKEY_LOCAL_MACHINE\SOFTWARE\Nullsoft" $R0
		StrCmp $R0 "-1" RestoreSettings
		${registry::MoveKey} "HKEY_LOCAL_MACHINE\SOFTWARE\Nullsoft" "HKEY_LOCAL_MACHINE\SOFTWARE\Nullsoft-BackupByWinampPortable" $R0
		Sleep 100

	RestoreSettings:
		IfFileExists "SETTINGSDIRECTORY\winamp.reg" "" SetRandomSeedPath
			
		;=== Get last drive letter
		ReadINIStr $0 "$SETTINGSDIRECTORY\winamp.reg" "HKEY_LOCAL_MACHINE\SOFTWARE\Nullsoft\Winamp" `"RandSeedFile"`
		StrCpy $1 $0 1 ;last drive letter
		StrCpy $2 $EXEDIR 1 ;current drive letter
		StrCmp $2 $1 RestoreTheKey
		StrCpy $3 `"PublicKeyFile"="$1:\\`
		StrCpy $4 `"PublicKeyFile"="$2:\\`
		;MessageBox MB_OK|MB_ICONINFORMATION `$3 *** $4`
		${ReplaceInFile} "$SETTINGSDIRECTORY\winamp.reg" $3 $4
		
	RestoreTheKey:
		IfFileExists "$WINDIR\system32\reg.exe" "" RestoreTheKey9x
			nsExec::ExecToStack `"$WINDIR\system32\reg.exe" import "$SETTINGSDIRECTORY\winamp.reg"`
			Pop $R0
			StrCmp $R0 '0' SetRandomSeedPath ;successfully restored key
	RestoreTheKey9x:
		${registry::RestoreKey} "$SETTINGSDIRECTORY\winamp.reg" $R0
		Sleep 2000
		StrCmp $R0 '0' SetRandomSeedPath ;successfully restored key
		StrCpy $FAILEDTORESTOREKEY "true"
		MessageBox MB_OK|MB_ICONINFORMATION `${PORTABLEAPPNAME}'s settings could not be loaded into the registry.  The account you are logged in with most likely does not have the ability to alter the registry.  ${PORTABLEAPPNAME} should still run correctly, but the pro registration will be used.`

	
	SetRandomSeedPath:
		Sleep 100
		${registry::Write} "HKEY_LOCAL_MACHINE\SOFTWARE\Nullsoft\Winamp" "RandSeedFile" "$SETTINGSDIRECTORY\WINAMP.RND" "REG_SZ" $0
		;Sleep 1000
		Sleep 100
		ExecWait $EXECSTRING
		
	CheckRunning:
		Sleep 1000
		FindProcDLL::FindProc "${DEFAULTEXE}"                  
		StrCmp $R0 "1" CheckRunning
		
		StrCmp $FAILEDTORESTOREKEY "true" SetOriginalKeyBack
		CreateDirectory $SETTINGSDIRECTORY
		${registry::SaveKey} "HKEY_LOCAL_MACHINE\SOFTWARE\Nullsoft\Winamp" "$SETTINGSDIRECTORY\winamp.reg" "" $0
		Sleep 100
	
	SetOriginalKeyBack:
		${registry::DeleteKey} "HKEY_LOCAL_MACHINE\SOFTWARE\Nullsoft" $R0
		Sleep 100
		${registry::KeyExists} "HKEY_LOCAL_MACHINE\SOFTWARE\Nullsoft-BackupByWinampPortable" $R0
		StrCmp $R0 "-1" TheEnd
		${registry::MoveKey} "HKEY_LOCAL_MACHINE\SOFTWARE\Nullsoft-BackupByWinampPortable" "HKEY_LOCAL_MACHINE\SOFTWARE\Nullsoft" $R0
		Sleep 100
		Goto TheEnd
		
	LaunchAndExit:
		Exec $EXECSTRING
		
	TheEnd:
		${registry::Unload}
		newadvsplash::stop /WAIT
SectionEnd

Thanks for your help.

ZachHudock
ZachHudock's picture
Offline
Last seen: 3 weeks 6 days ago
Developer
Joined: 2006-12-06 18:07
I can't tell from the quick

I can't tell from the quick look I just took, but the fact that the key is in HKLM may have something to do with it. I'll take a deeper look tonight, and I'm sure someone else will have a response by then too.

The developer formerly known as ZGitRDun8705

Devo
Offline
Last seen: 4 months 1 week ago
Joined: 2007-09-04 14:55
I guess what I don't

I guess what I don't understand is that it has no problem writing a key to the registry, it just doesn't use the key that is supplied. It backs it up and creates a new one.

ZachHudock
ZachHudock's picture
Offline
Last seen: 3 weeks 6 days ago
Developer
Joined: 2006-12-06 18:07
Yeah...I couldn't tell from

Yeah...I couldn't tell from my quick look, I'll look later tonight again though. Hopefully we'll figure this out.

Though if HKLM is used, this won't really be portable anyway, because HKLM requires admin rights if i remember correctly

The developer formerly known as ZGitRDun8705

Devo
Offline
Last seen: 4 months 1 week ago
Joined: 2007-09-04 14:55
Thanks

Yeah, I know about the admin rights. If that is the case, then you'll just have to run winamp without the pro registration, which isn't really a big deal. I am using a computer with admin rights, and the correct registry isn't placed in the registry. Thank you for looking at this, it'll be a huge help.

Devo
Offline
Last seen: 4 months 1 week ago
Joined: 2007-09-04 14:55
Did you or anybody else get

Did you or anybody else get a chance to look at this?

ZachHudock
ZachHudock's picture
Offline
Last seen: 3 weeks 6 days ago
Developer
Joined: 2006-12-06 18:07
No i didn't get a chance to.

No i didn't get a chance to. sorry. i'll email myself now so i remember to look tonight lol.

The developer formerly known as ZGitRDun8705

Devo
Offline
Last seen: 4 months 1 week ago
Joined: 2007-09-04 14:55
Thanks, I know it's probably

Thanks, I know it's probably not that important, but I just want to get it done so I can finally start using winamp 'truly' portably.

Devo
Offline
Last seen: 4 months 1 week ago
Joined: 2007-09-04 14:55
I also have another

I also have another question, hopefully this isn't too involved. I noticed that the in the firefox launcher you can change the name of the exe and the file name in the ini file and it will use that information to launch the program. What would I have to do to implement this in this launcher? Or is this something that is too hard? I just thought it would be a good idea and it's will also help me learn. Thanks

Devo
Offline
Last seen: 4 months 1 week ago
Joined: 2007-09-04 14:55
I'm really not trying to

I'm really not trying to bump this thread, I've just been trying to figure this out, looking at the documentation on the website and looking through other installers and it's driving me nuts. Does anybody know how to fix this?

ZachHudock
ZachHudock's picture
Offline
Last seen: 3 weeks 6 days ago
Developer
Joined: 2006-12-06 18:07
I haven't been able to

I haven't been able to figure it out, your code looks fine as far as i can tell.

The developer formerly known as ZGitRDun8705

Devo
Offline
Last seen: 4 months 1 week ago
Joined: 2007-09-04 14:55
The problem seems to be

The problem seems to be that the launcher never uses the reg file supplied. It always creates a new reg file with random data. The name of the reg entry is RandSeedFile. It should only create this when no entry is found in the \Data\settings folder. Something is messed up somewhere, I just can't find it. It also overwirtes the reg entry in the settings folder with the random data it created when the launcher closes. Hopefully somebody can figure this, preferably John since he's the one that wrote the launcher I adapted.

ZachHudock
ZachHudock's picture
Offline
Last seen: 3 weeks 6 days ago
Developer
Joined: 2006-12-06 18:07
what are StrCpy $3

what are

StrCpy $3 `"PublicKeyFile"="$1:\\`
StrCpy $4 `"PublicKeyFile"="$2:\\`

these lines for?

The developer formerly known as ZGitRDun8705

Devo
Offline
Last seen: 4 months 1 week ago
Joined: 2007-09-04 14:55
Don't know

I honestly don't know, I just modified John's launcher for PuttyPortable. Like I said before, I have very little knowledge of programming, I'm trying to figure things out as I go. I'll try removing them and see if that helps.

ZachHudock
ZachHudock's picture
Offline
Last seen: 3 weeks 6 days ago
Developer
Joined: 2006-12-06 18:07
I don't have a copy of

I don't have a copy of winamp pro available to test this with. Does winamp create entries is HKCU as well, or does it only use HKLM? If other keys are created in HKCU, you will need to add support for that in as well.

The developer formerly known as ZGitRDun8705

Devo
Offline
Last seen: 4 months 1 week ago
Joined: 2007-09-04 14:55
You first have to

You first have to "portablize" winamp. Information on doing that can be found here (http://forums.winamp.com/showthread.php?threadid=279827). This just makes sure that nothing that requires the registry is installed and an ini file is used to save the settings. After doing that it seems that the pro registration is the only thing that is saved to the registry. I attached the regshot log showing what is created when the program is run.


----------------------------------
Keys added:2
----------------------------------
HKLM\SOFTWARE\Nullsoft
HKLM\SOFTWARE\Nullsoft\Winamp

----------------------------------
Values added:2
----------------------------------
HKU\S-1-5-21-1816858842-627311984-9522986-4248\Software\Microsoft\Windows\CurrentVersion\Explorer\UserAssist\{75048700-EF1F-11D0-9888-006097DEACF9}\Count\HRZR_EHACNGU:P:\Qbphzragf naq Frggvatf\QQibenx.TERRYRL\Zl Qbphzragf\Fubegphgf\JvanzcCbegnoyrFbhepr\Ncc\jvanzc\jvanzc.rkr: 6D 00 00 00 06 00 00 00 90 FA B7 23 12 90 C8 01
HKU\S-1-5-21-1816858842-627311984-9522986-4248\Software\Microsoft\Windows\ShellNoRoam\MUICache\C:\Documents and Settings\DDvorak.GREELEY\My Documents\Shortcuts\WinampPortableSource\App\winamp\winamp.exe: "Winamp"

----------------------------------
Values modified:8
----------------------------------
HKLM\SOFTWARE\McAfee\VSCore\On Access Scanner\McShield\szLastScanned: "C:\WINDOWS\Prefetch\CMD.EXE-087B4001.pf"
HKLM\SOFTWARE\McAfee\VSCore\On Access Scanner\McShield\szLastScanned: "C:\WINDOWS\system32\perfh009.dat"
HKLM\SOFTWARE\McAfee\VSCore\On Access Scanner\McShield\dwFilesScanned: 0x000012BD
HKLM\SOFTWARE\McAfee\VSCore\On Access Scanner\McShield\dwFilesScanned: 0x000012DF
HKLM\SOFTWARE\Microsoft\Cryptography\RNG\Seed: E5 0C 12 61 A1 9C 4D 31 BD 08 8F 39 05 4E 00 81 5F 9C 57 4B A9 8A D7 3B 00 B3 5C 3B 58 B8 DE F3 BB F3 23 43 48 D9 A9 ED BA 92 03 7C 87 4A 39 22 E3 D7 CA 28 E1 0B AE AB 4A 6A 77 EF BC 43 51 67 4A 14 85 32 8E 57 72 93 5E C9 33 12 05 F8 1F 3F
HKLM\SOFTWARE\Microsoft\Cryptography\RNG\Seed: 52 98 96 08 7C D4 D5 B1 3B F9 E0 7D 6E D3 FE DC 14 7D 92 DB 44 AD BD AA 69 FB D8 8F 00 A6 67 C0 08 53 0F 5C 8E 06 D1 1B 17 64 F2 2C F6 C7 FD 28 3C 8E 37 C2 A9 C6 3C 86 1B D3 F2 15 75 10 67 26 AD E1 60 63 6E 30 8B D7 CE 2F 6A CD 76 CD 95 12
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Prefetcher\TracesProcessed: 0x0000004E
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Prefetcher\TracesProcessed: 0x0000004F
HKLM\SYSTEM\ControlSet001\Control\ServiceCurrent\: 0x00000013
HKLM\SYSTEM\ControlSet001\Control\ServiceCurrent\: 0x00000014
HKLM\SYSTEM\CurrentControlSet\Control\ServiceCurrent\: 0x00000013
HKLM\SYSTEM\CurrentControlSet\Control\ServiceCurrent\: 0x00000014
HKU\S-1-5-21-1816858842-627311984-9522986-4248\Software\Microsoft\Windows\CurrentVersion\Explorer\UserAssist\{75048700-EF1F-11D0-9888-006097DEACF9}\Count\HRZR_EHACNGU: 6D 00 00 00 AB 13 00 00 D0 06 A2 8A 10 90 C8 01
HKU\S-1-5-21-1816858842-627311984-9522986-4248\Software\Microsoft\Windows\CurrentVersion\Explorer\UserAssist\{75048700-EF1F-11D0-9888-006097DEACF9}\Count\HRZR_EHACNGU: 6D 00 00 00 AC 13 00 00 90 FA B7 23 12 90 C8 01
HKU\S-1-5-21-1816858842-627311984-9522986-4248\Software\Microsoft\Windows\CurrentVersion\Shell Extensions\Cached\{4A681BEC-7727-49BD-B695-79F8354CD2E5} {E8025004-1C42-11D2-BE2C-00A0C9A83DA1} 0x401: 00 00 00 00 31 00 38 00 A9 D2 D1 19 12 90 C8 01
HKU\S-1-5-21-1816858842-627311984-9522986-4248\Software\Microsoft\Windows\CurrentVersion\Shell Extensions\Cached\{4A681BEC-7727-49BD-B695-79F8354CD2E5} {E8025004-1C42-11D2-BE2C-00A0C9A83DA1} 0x401: 00 00 00 00 31 00 38 00 69 6C A7 23 12 90 C8 01

----------------------------------
Total changes:12
----------------------------------

So it looks like there are really only two entries.

Edit:
I also removed those lines you mentioned above, but there was no change. I really have no idea what they were for.

wraithdu
Offline
Last seen: 9 years 7 months ago
Developer
Joined: 2007-06-27 20:22
Two problems

First, here -

SettingsDirectory:
	;=== Set the settings directory if we have a path
	IfFileExists "$SETTINGSDIRECTORY\*.*" "" RegistryBackup
		CreateDirectory $SETTINGSDIRECTORY

Should be -

SettingsDirectory:
	;=== Set the settings directory if we have a path
	IfFileExists "$SETTINGSDIRECTORY\*.*" RegistryBackup
		CreateDirectory $SETTINGSDIRECTORY

You need to create the path if it doesn't exist.

And second -

RestoreSettings:
	IfFileExists "SETTINGSDIRECTORY\winamp.reg" "" SetRandomSeedPath

Should be -

RestoreSettings:
	IfFileExists "$SETTINGSDIRECTORY\winamp.reg" "" SetRandomSeedPath

You missed the $ before your variable. See if it works now...

Devo
Offline
Last seen: 4 months 1 week ago
Joined: 2007-09-04 14:55
Got It

Unfortunately that didn't fix anything. I just went ahead and took the 7-zip launcher and modified it. It works like a charm now. The registry entry is correctly handled, everything is cleaned up, and it even allows the user to change the name of the exe to run in the ini.

I also compiled the launcher into an installable exe and included instructions on portablizing the full version of winamp. If people want it I can send it to them the launcher.

Seeing as this was the first time I've ever tried to write a program, I'd like to thank you and Zach for being patient with me.

Thanks again.

Log in or register to post comments