Pass variable between applets

Thanks to Yvan Koenig and KniazidisR for helping with duplicating files http://macscripter.net/viewtopic.php?pid=47049#p47049. As they both mentioned in that post the code would not work if run more than once. I actually use that code to duplicate two files, and my main code is designed to delete both duplicated files once the main code is completed. The trick here is my main code is designed to be able to be run multiple times and it renames these duplicated files by appending an incremented numerical value to the end of the filename. So the first time the main code is run it appends a “1” to the end of the filenames, the second time the main code is run it appends a “2” to the end of the filenames, etc.

My main code is made up of three applets; MainOpenEndive.app, OpenEndive_0#.app, and DeleteOpenEndive_0#.app.

MainOpenEndive.app duplicates and renames a 4D Client app and a “template” applet for OpenEndive_0#.app. Then it renames and incremently numbers those apps EndiveName1.app and OpenEndive_01.app (the first time main applet is executed). It then launches OpenEndive_01.app.

OpenEndive_01.app executes the main code for running the 4d Client “EndiveName1.app”. At the end of the applet it deletes the EndiveName1.app once it is no longer running. Then it calls the third applet “DeleteOpenEndive_0#.app”

DeleteOpenEndive_0#.app only function is to delete the OpenEndive_01.app.

My problem is I need to pass to the third applet each time it is executed the correct numerical value for the applet to be deleted. The EndiveName# apps will be quit by the user out of sequence. i.e., app1, app2, app3 are all running, but the user quits app2 first. Now the DeleteOpenEndive_0# applet needs to now which file to delete.

Here’s the code for each of the three applets. In the second applet OpenEndive_0#.app, deleting EndiveName#.app works fine. So I’m trying to declare and set the variable “newFileNameB” to align with the numerical value of EndiveName#.app that it is trying to pass the variable.

How do I pass the variable “newFileNameB” to the third applet? Or does anyone have a better suggestion of how to accomplish this?

Main_OpenEndive (1st Applet to execute)

--duplicate template OpenClient files
set testPath to POSIX file "Applications/Endive Clients/zOpen Clients/GenericEndive.app"
tell application "Finder"
	set fileref to duplicate (testPath as alias)
	log fileref as string
end tell

set testPath to POSIX file "Applications/Endive Clients/zOpen Clients/OpenEndive_Multi.app"
tell application "Finder"
	set fileref to duplicate (testPath as alias)
	log fileref as string
end tell

--Rename duplicated template OpenClient files
tell application "Finder"
	activate
	set name of application file "GenericEndive copy.app" of folder "zOpen Clients" of folder "Endive Clients" of folder "Applications" of startup disk to "EndiveName.app"
	set name of application file "OpenEndive_Multi copy.app" of folder "zOpen Clients" of folder "Endive Clients" of folder "Applications" of startup disk to "OpenEndive_0.app"
end tell

--Set OpenEndive_0 to next value
property baseFileNameA : "OpenEndive_0"
set targetDir to POSIX file "/Applications/Endive Clients/zOpen Clients/"
tell application "Finder"
	set fileCountA to count of (files in folder targetDir whose name contains baseFileNameA)
end tell
set newFileNameA to "OpenEndive_0" & fileCountA & ".app"
tell application "System Events"
	set name of file "/Applications/Endive Clients/zOpen Clients/OpenEndive_0.app" to "/Applications/Endive Clients/zOpen Clients/" & newFileNameA
end tell

--Set EndiveName to next value
property baseFileNameB : "EndiveName"
set targetDir to POSIX file "/Applications/Endive Clients/zOpen Clients/"
tell application "Finder"
	set fileCountB to count of (files in folder targetDir whose name contains baseFileNameB)
end tell
set newFileNameB to "EndiveName" & fileCountB & ".app"
tell application "System Events"
	set name of file "/Applications/Endive Clients/zOpen Clients/EndiveName.app" to "/Applications/Endive Clients/zOpen Clients/" & newFileNameB
end tell

--Launch OpenEndive_0#
tell application "Finder"
	activate
	open application file newFileNameA of folder "zOpen Clients" of folder "Endive Clients" of folder "Applications" of startup disk
end tell

OpenEndive_0# (2nd Applet to execute)

--Check for number of existing file
global newFileNameB  --attempting to declare global variable "newFileNameB" for use by the 3rd Applet

property baseFileNameA : "EndiveName"
set targetDir to POSIX file "/Applications/Endive Clients/zOpen Clients/"
tell application "Finder"
	set fileCountA to count of (files in folder targetDir whose name contains baseFileNameA)
end tell
set newFileNameA to "EndiveName" & fileCountA & ".app"

set appnA to newFileNameA

--Open EndiveName#
tell application "Finder"
	activate
	open application file newFileNameA of folder "zOpen Clients" of folder "Endive Clients" of folder "Applications" of startup disk
end tell

--Check if EndiveName# is still running
repeat
	if application appnA is not running then exit repeat
	delay 5
end repeat

--Delete EndiveName# after quiting Endive
set myFile to "/Applications/Endive Clients/zOpen Clients/" & newFileNameA
try
	do shell script "rm -rf " & quoted form of myFile
end try

--Launch DeleteOpenEndive_0#
tell application "Finder"
	set newFileNameB to "OpenEndive_0" & fileCountA & ".app"  --attempting to set the value of global variable "newFileNameB"
	activate
	open application file "DeleteOpenEndive_0#.app" of folder "zOpen Clients" of folder "Endive Clients" of folder "Applications" of startup disk
end tell

DeleteOpenEndive_0# (3rd Applet to execute) Need to pass the value of variable “newFileNameB” from 2nd Applet

--set newFileNameB to "OpenEndive_0#.app"
set myFile to "/Applications/Endive Clients/zOpen Clients/" & newFileNameB
try
	do shell script "rm -rf " & quoted form of myFile
end try

I do not quite understand the essence of your workflow, but I can say one thing: you can pass a variable between applets through the clipboard.

At the end of the 2nd applet, add:

set the clipboard to ""
set the clipboard to newFileNameB

and at the beginning of the 3rd:

set newFileNameB to ""
repeat until newFileNameB = ""
	set newFileNameB to the clipboard as text
	delay 0.1
end repeat

NOTE: You say “As they both mentioned in that post the code would not work if run more than once.”

No, the last code I provide in https://macscripter.net/viewtopic.php?id=47049 may run multiple times

Hi.

If the second applet, instead of the third, is allowed to know the path to the file you want to delete, you could possibly call the third applet with an alias to the file:

End of second applet:

--Launch DeleteOpenEndive_0#
set newFileNameB to "OpenEndive_0" & fileCountA & ".app" --attempting to set the value of global variable "newFileNameB"
set myFile to ("/Applications/Endive Clients/zOpen Clients/" & newFileNameB) as POSIX file

tell application "Finder"
	-- The Finder's 'open' command can do this:
	open {myFile} using application file "DeleteOpenEndive_0#.app" of folder "zOpen Clients" of folder "Endive Clients" of folder "Applications" of startup disk
end tell

Third applet:

on open {myFile} -- Assuming the parameter's a one-item list.
	try
		do shell script "rm -rf " & quoted form of POSIX path of myFile
	end try
end open

I haven’t examined your scripts in detail, but there may be simpler ways of doing things than using three applets.

I approximately see what you are trying to do - you want to run multiple instances of the same application. At the same time, you want to delete instances that have completed work.

For this you use 3 separate applets. But as I see it, this can be done with 1 script, which should be saved as single stay-open applet:


on initialize()
	-- Your Main_OpenEndive code goes here
end initialize

on run
	my initialize()
end run

on idle
	-- Your  OpenEndive code goes here
	return 5 -- 5 seconds interval as you set
end idle

on quit {}
	continue quit
end quit

on deleteFile()
	-- Your DeleteOpenEndive code goes here
end deleteFile

Note: you can put now global variables and properties at the top of the script. If you want. On deleteFile handler you will call from on idle handler with my deleteFile()

I really like the idea of running it all in one script. There is a section of the second applet I excluded from the first post (wasn’t sure it was related to the issue) where the user selects a 4D Server to connect to. When I insert this into the single script solution the GetIndex code won’t compile. Not sure what is missing to include this portion in the single script solution. Here’s the added code that is inserted just before the “Open EndiveName#” code in the second script.

	--Open EndiveIPAddress.txt and get Job names and numbers
	set theData to "/Applications/Endive Clients/Utilities/EndiveIPAddress.txt" as string
	
	tell application "Microsoft Excel"
		open theData
		set lastCell to first row index of (find column 1 what "" look in values look at whole)
		set Names to the value of the range ("A2:A" & (lastCell - 1))
		set Addresses to the value of the range ("B2:B" & (lastCell - 1))
		close active workbook without saving
	end tell
	
	--Create the list of job names and numbers / This portion won't compile
	to getIndex of i from l
		repeat with n from 1 to count l
			if l's item n is i then return n
		end repeat
		0
	end getIndex
	
	--Display list and get selected IP Address
	set theChoice to (choose from list Names)
	if (theChoice is false) then error number -128
	
	set theItem to item 1 of theChoice
	set theIPItem to getIndex of theItem from Names
	set IPAddress to item theIPItem of Addresses
	
	--Update Endive launch with selected Ip Address
	tell application "TextWrangler"
		set theFile to "/Applications/Endive Clients/zOpen Clients/" & newFileNameA & "/Contents/Database/EnginedServer.4Dlink"
		open theFile
		replace "xxx.xxx.xxx.xxx" using IPAddress searching in text 1 of front document options {starting at top:false, wrap around:true, backwards:true, case sensitive:true, match words:true, extend selection:false}
		tell front document
			save
		end tell
	end tell
	tell application "TextWrangler"
		quit
	end tell

to getIndex of i from l
       repeat with n from 1 to count l
           if l's item n is i then return n
       end repeat
       0
   end getIndex

Hi.
You have included this handler inside the other handler (inside on idle handler?).
You can’t do this. You can do this only inside on run handler. In your case, this handler should be separated. As i do with on deleteFile handler. Or, write following code without this handler:


--Open EndiveIPAddress.txt and get Job names and numbers
set theData to "/Applications/Endive Clients/Utilities/EndiveIPAddress.txt" as string
tell application "Microsoft Excel"
	open theData
	set lastCell to first row index of (find column 1 what "" look in values look at whole)
	set Names to the value of the range ("A2:A" & (lastCell - 1))
	set Addresses to the value of the range ("B2:B" & (lastCell - 1))
	close active workbook without saving
end tell

-- Display list and select from it
set theChoice to (choose from list Names)
if (theChoice is false) then error number -128

-- Get IP address
set theItem to item 1 of theChoice
repeat with theIPItem from 1 to count of Names
	if Names's item theIPItem is theItem then exit repeat
end repeat
set IPAddress to item theIPItem of Addresses

--Update Endive launch with selected Ip Address
tell application "TextWrangler"
	set theFile to "/Applications/Endive Clients/zOpen Clients/" & newFileNameA & "/Contents/Database/EnginedServer.4Dlink"
	open theFile
	replace "xxx.xxx.xxx.xxx" using IPAddress searching in text 1 of front document options {starting at top:false, wrap around:true, backwards:true, case sensitive:true, match words:true, extend selection:false}
	tell front document to save
	quit
end tell

Thanks! With the single script I don’t need the deleteFile handler any longer; there’s no second app to delete.

I tried the script as you wrote, but on run it went into a loop; it just kept initializing and would never go to the “idle” code. So I moved the “on run” to the beginning of the code and placed the “idle” command inside the “on run” script. Now it works, but I’m not able to “re-run” the code while it is running to select the next client app.

Did I miss something again? Sorry.

on idle is special handler. You should not call it from on run handler. Provide here whole code you tried. I will see it tomorrow.

it just kept initializing and would never go to the “idle” code

You saved the code with structure I provide as stay-open application? Or you saved it as simpe application?

Here’s the entire script I tried. I saved it as a Stay Open Application.


property baseFileNameB : "EndiveName"

on initialize()
	
	--duplicate template OpenClient files
	set testPath to POSIX file "Applications/Endive Clients/zOpen Clients/GenericEndive.app"
	tell application "Finder"
		set fileref to duplicate (testPath as alias)
		log fileref as string
	end tell
	
	--Rename duplicated template OpenClient files
	tell application "Finder"
		activate
		set name of application file "GenericEndive copy.app" of folder "zOpen Clients" of folder "Endive Clients" of folder "Applications" of startup disk to "EndiveName.app"
	end tell
	
	--Set EndiveName to next value
	set targetDir to POSIX file "/Applications/Endive Clients/zOpen Clients/"
	tell application "Finder"
		set fileCountB to count of (files in folder targetDir whose name contains baseFileNameB)
	end tell
	set newFileNameB to "EndiveName" & fileCountB & ".app"
	tell application "System Events"
		set name of file "/Applications/Endive Clients/zOpen Clients/EndiveName.app" to "/Applications/Endive Clients/zOpen Clients/" & newFileNameB
	end tell
	
end initialize

on idle
	
	set appnB to newFileNameB
	
	delay 6
	
	--Open EndiveIPAddress.txt and get Job names and numbers
	set theData to "/Applications/Endive Clients/Utilities/EndiveIPAddress.txt" as string
	tell application "Microsoft Excel"
		open theData
		set lastCell to first row index of (find column 1 what "" look in values look at whole)
		set Names to the value of the range ("A2:A" & (lastCell - 1))
		set Addresses to the value of the range ("B2:B" & (lastCell - 1))
		close active workbook without saving
	end tell
	
	-- Display list and select from it
	set theChoice to (choose from list Names)
	if (theChoice is false) then error number -128
	
	-- Get IP address
	set theItem to item 1 of theChoice
	repeat with theIPItem from 1 to count of Names
		if Names's item theIPItem is theItem then exit repeat
	end repeat
	set IPAddress to item theIPItem of Addresses
	
	--Update Endive launch with selected Ip Address
	tell application "TextWrangler"
		set theFile to "/Applications/Endive Clients/zOpen Clients/" & newFileNameB & "/Contents/Database/EnginedServer.4Dlink"
		open theFile
		replace "xxx.xxx.xxx.xxx" using IPAddress searching in text 1 of front document options {starting at top:false, wrap around:true, backwards:true, case sensitive:true, match words:true, extend selection:false}
		tell front document to save
		quit
	end tell
	
	--Open EndiveName(#)
	tell application "Finder"
		activate
		open application file newFileNameB of folder "zOpen Clients" of folder "Endive Clients" of folder "Applications" of startup disk
	end tell
	
	--delay "exit" to ensure Endive has opened and is stable
	delay 20
	
	--Check if EndiveName() is still running
	repeat
		if application appnB is not running then exit repeat
		delay 5
	end repeat
	
	--Delete EndiveName() after quiting Endive
	set myFile to "/Applications/Endive Clients/zOpen Clients/" & newFileNameB
	try
		do shell script "rm -rf " & quoted form of myFile
	end try
		
	return 5 -- 5 seconds interval as you set
end idle

on quit {}
	continue quit
end quit

on run
	my initialize()
	idle
	quit {}
end run

I will go step by step.

  1. on initialize() handler.

No need here check for existent duplicate. This handler runs only once when you start appication, so you can set the name directly to EndiveName1.app.
No need convert posix file to alias. Provide directly the alias. Remember to replace YourDiskName with real disk name.
I added global variable newFileNameB. You set other variable to this variable in on idle{} handler. But without doing this variable global, on idle{} handler can’t access it.

As continue. You should go thru all the process for the first selected IP in this handler


global templateFile
global newFileNameB
property baseFileNameB : "EndiveName"

on initialize()
	set templateFile to alias ((path to applications folder as text) & ¬
		"Endive Clients:zOpen Clients:GenericEndive.app")
	tell application "Finder"
		-- duplicate template OpenClient files
		set newFile to duplicate templateFile
		log newFile as string
		-- Rename duplicated template OpenClient files
		set name of newFile to "EndiveName1.app"
	end tell
	set newFileNameB to "EndiveName1.app"
	
	-- Open EndiveIPAddress.txt and get Job names and numbers
	set theData to "/Applications/Endive Clients/Utilities/EndiveIPAddress.txt"
	tell application "Microsoft Excel"
		open theData
		set lastCell to first row index of (find column 1 what "" look in values look at whole)
		set Names to the value of the range ("A2:A" & (lastCell - 1))
		set Addresses to the value of the range ("B2:B" & (lastCell - 1))
		close active workbook without saving
	end tell
	
	-- Get IP address
	set theItem to item 1 of theChoice
	repeat with theIPItem from 1 to count of Names
		if Names's item theIPItem is theItem then exit repeat
	end repeat
	set IPAddress to item theIPItem of Addresses
	
	-- Update Endive launch with selected Ip Address
	tell application "TextWrangler"
		set theFile to "/Applications/Endive Clients/zOpen Clients/EndiveName1.app/Contents/Database/EnginedServer.4Dlink"
		open theFile
		replace "xxx.xxx.xxx.xxx" using IPAddress searching in text 1 of front document options {starting at top:false, wrap around:true, backwards:true, case sensitive:true, match words:true, extend selection:false}
		tell front document to save
		quit
	end tell
	
	-- Open EndiveName1
	tell application "Finder" to open newFile
end initialize
---------------------------------------------------------------------------------------
on run {}
	my initialize()
end run
------------------------------------------------------------------
on idle {}
	-- Count all old created instances
	set targetDir to POSIX file "/Applications/Endive Clients/zOpen Clients/"
	tell application "Finder"
		set fileCountB to count of (files in folder targetDir whose name contains baseFileNameB)
	end tell
	
	if fileCountB > 0 then
		repeat with i from 1 to fileCountB
			if application ("EndiveName" & i as string) is not running then
				set myFile to "/Applications/Endive Clients/zOpen Clients/" & ("EndiveName" & i as string) & ".app"
				try
					do shell script "rm -rf " & quoted form of myFile
				end try
			end if
		end repeat
		tell application "Finder"
			set fileCountB to count of (files in folder targetDir whose name contains baseFileNameB)
		end tell
		set newFileNameB to "EndiveName" & (fileCountB as string) & ".app"
	else
		set newFileNameB to "EndiveName1.app"
	end if
	
	tell application "Finder"
		-- duplicate template OpenClient files
		set newFile to duplicate templateFile
		log newFile as string
		-- Rename duplicated template OpenClient files
		set name of newFile to newFileNameB
	end tell
	
	-- Open EndiveIPAddress.txt and get Job names and numbers
	set theData to "/Applications/Endive Clients/Utilities/EndiveIPAddress.txt"
	tell application "Microsoft Excel"
		open theData
		set lastCell to first row index of (find column 1 what "" look in values look at whole)
		set Names to the value of the range ("A2:A" & (lastCell - 1))
		set Addresses to the value of the range ("B2:B" & (lastCell - 1))
		close active workbook without saving
	end tell
	
	-- Get IP address
	set theItem to item 1 of theChoice
	repeat with theIPItem from 1 to count of Names
		if Names's item theIPItem is theItem then exit repeat
	end repeat
	set IPAddress to item theIPItem of Addresses
	
	-- Update Endive launch with selected Ip Address
	tell application "TextWrangler"
		set theFile to "/Applications/Endive Clients/zOpen Clients/" & newFileNameB & "/Contents/Database/EnginedServer.4Dlink"
		open theFile
		replace "xxx.xxx.xxx.xxx" using IPAddress searching in text 1 of front document options {starting at top:false, wrap around:true, backwards:true, case sensitive:true, match words:true, extend selection:false}
		tell front document to save
		quit
	end tell
	
	-- Open EndiveName1
	tell application "Finder" to open newFile
	
	return 5
end idle
------------------------------------------------------------------
on quit {}
	continue quit
end quit

on run {} and on quit {} no need other stuff, so we go to

  1. on idle {} handler.. Here, to continue, I need to know from you if the contents of file “/Applications/Endive Clients/Utilities/EndiveIPAddress.txt” is updated in real time.

UPDATE: I ended with on idle {} handler too. But I don’t have Endive Clients software, and can’t test

@KniazidisR

Like you I can’t test but I tried to make a bit of cleaning in pathnames definitions.


global newFileNameB
property baseFileNameB : "EndiveName"

on initialize()
	set targetDir1 to (path to applications folder as text) & "Endive Clients:"
	set posixBeg to POSIX path of targetDir1
	set templateFile to alias (targetDir1 & "zOpen Clients:GenericEndive.app")
	tell application "Finder"
		-- duplicate template OpenClient files
		set newFile to duplicate templateFile
		log newFile as string
		-- Rename duplicated template OpenClient files
		set name of newFile to "EndiveName1.app"
	end tell
	set newFileNameB to "EndiveName1.app"
	
	-- Open EndiveIPAddress.txt and get Job names and numbers
	
	set theData to posixBeg & "Utilities/EndiveIPAddress.txt"
	
	tell application "Microsoft Excel"
		open theData
		set lastCell to first row index of (find column 1 what "" look in values look at whole)
		set Names to the value of the range ("A2:A" & (lastCell - 1))
		set Addresses to the value of the range ("B2:B" & (lastCell - 1))
		close active workbook without saving
	end tell
	
	-- Get IP address
	set theItem to item 1 of theChoice
	repeat with theIPItem from 1 to count of Names
		if Names's item theIPItem is theItem then exit repeat
	end repeat
	set IPAddress to item theIPItem of Addresses
	
	-- Update Endive launch with selected Ip Address
	tell application "TextWrangler"
		set theFile to posixBeg & "zOpen Clients/EndiveName1.app/Contents/Database/EnginedServer.4Dlink"
		open theFile
		replace "xxx.xxx.xxx.xxx" using IPAddress searching in text 1 of front document options {starting at top:false, wrap around:true, backwards:true, case sensitive:true, match words:true, extend selection:false}
		tell front document to save
		quit
	end tell
	
	-- Open EndiveName1
	tell application "Finder" to open newFile
end initialize
---------------------------------------------------------------------------------------
on run {}
	my initialize()
end run
------------------------------------------------------------------
on idle {}
	-- Count all old created instances
	set targetDir1 to (path to applications folder as text) & "Endive Clients:"
	set posixTarget1 to POSIX path of targetDir1
	set targetDir to targetDir1 & "zOpen Clients:zOpen Clients:"
	set posixTarget to POSIX path of targetDir
	tell application "Finder"
		set fileCountB to count of (files in folder targetDir whose name contains baseFileNameB)
	end tell
	
	if fileCountB > 0 then
		repeat with i from 1 to fileCountB
			if application ("EndiveName" & i) is not running then
				tell application "System Events" to delete disk (posixTarget & ("EndiveName" & i) & ".app")
			end if
		end repeat
		tell application "Finder"
			set fileCountB to count of (files in folder targetDir whose name contains baseFileNameB)
		end tell
		set newFileNameB to "EndiveName" & (fileCountB as string) & ".app"
	else
		set newFileNameB to "EndiveName1.app"
	end if
	
	set templateFile to alias (targetDir & "GenericEndive.app")
	tell application "Finder"
		-- duplicate template OpenClient files
		set newFile to duplicate templateFile
		log newFile as string
		-- Rename duplicated template OpenClient files
		set name of newFile to newFileNameB
	end tell
	
	-- Open EndiveIPAddress.txt and get Job names and numbers
	set theData to posixTarget1 & "Utilities/EndiveIPAddress.txt"
	
	tell application "Microsoft Excel"
		open theData
		set lastCell to first row index of (find column 1 what "" look in values look at whole)
		set Names to the value of the range ("A2:A" & (lastCell - 1))
		set Addresses to the value of the range ("B2:B" & (lastCell - 1))
		close active workbook without saving
	end tell
	
	-- Get IP address
	set theItem to item 1 of theChoice
	repeat with theIPItem from 1 to count of Names
		if Names's item theIPItem is theItem then exit repeat
	end repeat
	set IPAddress to item theIPItem of Addresses
	
	-- Update Endive launch with selected Ip Address
	tell application "TextWrangler"
		set theFile to posixTarget & newFileNameB & "/Contents/Database/EnginedServer.4Dlink"
		open theFile
		replace "xxx.xxx.xxx.xxx" using IPAddress searching in text 1 of front document options {starting at top:false, wrap around:true, backwards:true, case sensitive:true, match words:true, extend selection:false}
		tell front document to save
		quit
	end tell
	
	-- Open EndiveName1
	tell application "Finder" to open newFile
	
	return 5
end idle
------------------------------------------------------------------
on quit {}
	continue quit
end quit

I wish to add that it would be a good idea to replace the dying TextWrangler by BBEdit 12 whose free version give a bit more power than its ancestor.

Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) lundi 2 septembre 2019 10:26:29

This version is better since it does not contain fragments of repeated code.


global templateFile, Names, Addresses
property baseFileNameB : "EndiveName"
property targetDir : "/Applications/Endive Clients/zOpen Clients/"
property theData : "/Applications/Endive Clients/Utilities/EndiveIPAddress.txt"
----------------------------------------------------------------------------------------------------------------------------
on initialize()
	set templateFile to alias ((path to applications folder as text) & ¬
		"Endive Clients:zOpen Clients:GenericEndive.app")
	set newFile to my duplicateFile("EndiveName1.app")
	my getNamesAndAddresses()
	set IPAddress to my getSelectionAndIPAddress()
	my updateEndiveLaunch(IPAddress, "EndiveName1.app")
	-- Open EndiveName1
	tell application "Finder" to open newFile
end initialize
----------------------------------------------------------------------------------------------------------------------------
on run {}
	my initialize()
end run
----------------------------------------------------------------------------------------------------------------------------
on idle {}
	tell application "Finder" to set fileCountB to count of ¬
		(files in folder targetDir whose name contains baseFileNameB)
	if fileCountB > 0 then
		repeat with i from fileCountB to 1 by step - 1 -- edited
			if application ("EndiveName" & i) is not running then
				set myFile to targetDir & "EndiveName" & i & ".app"
				set newFileNameB to "EndiveName" & i & ".app" -- edited
				do shell script "rm -rf " & quoted form of myFile
			end if
		end repeat
	else
		set newFileNameB to "EndiveName1.app"
	end if
	set newFile to my duplicateFile(newFileNameB)
	-- remove next code line, if database (txt file) is not updated in real time
	my getNamesAndAddresses()
	set IPAddress to my getSelectionAndIPAddress()
	my updateEndiveLaunch(IPAddress, newFileNameB)
	-- Open EndiveName1
	tell application "Finder" to open newFile
	return 5
end idle
----------------------------------------------------------------------------------------------------------------------------
on quit {}
	continue quit
end quit
----------------------------------------------------------------------------------------------------------------------------
on duplicateFile(newFileNameB)
	tell application "Finder"
		-- duplicate template OpenClient files
		set newFile to duplicate templateFile
		log newFile as string
		-- Rename duplicated template OpenClient files
		set name of newFile to newFileNameB
	end tell
	return newFile
end duplicateFile
-----------------------------------------------------------------
on getSelectionAndIPAddress()
	-- Display list and get selected IP Address
	set theChoice to (choose from list Names)
	if (theChoice is false) then error number -128
	-- Get IP address
	set theItem to item 1 of theChoice
	repeat with theIPItem from 1 to count of Names
		if Names's item theIPItem is theItem then exit repeat
	end repeat
	set IPAddress to item theIPItem of Addresses
	return IPAddress
end getSelectionAndIPAddress
----------------------------------------------------------------------------------------------------------------------------
on updateEndiveLaunch(IPAddress, newFileNameB)
	-- Update Endive launch with selected Ip Address
	tell application "TextWrangler"
		set theFile to targetDir & newFileNameB & "/Contents/Database/EnginedServer.4Dlink"
		open theFile
		replace "xxx.xxx.xxx.xxx" using IPAddress searching in text 1 of front document ¬
			options {starting at top:false, wrap around:true, backwards:true, case sensitive:true, match words:true, extend selection:false}
		tell front document to save
		quit
	end tell
end updateEndiveLaunch
---------------------------------------------------------------------------------------------
on getNamesAndAddresses()
	-- Open EndiveIPAddress.txt and get Job names and numbers
	tell application "Microsoft Excel"
		open theData
		set lastCell to first row index of (find column 1 what "" look in values look at whole)
		set Names to the value of the range ("A2:A" & (lastCell - 1))
		set Addresses to the value of the range ("B2:B" & (lastCell - 1))
		close active workbook without saving
	end tell
end getNamesAndAddresses

NOTE: if your database (txt file) is not updated in real time, then you can get Names and Addresses only once (in the on unitialize() handler).

I found one error in the on idle{} handler. Now this error (was wrong setting newFileNameB) is fixed. Is this command, which fixes the problem: set newFileNameB to “EndiveName” & i & “.app”

It came to me a better solution for the applet is to use the Server Name as the name of the file(s) in lieu of numerically incrementing the file names. Below is the revised single script which is leaner and works well. But I still need to be able to launch this script multiple times and choose a different server each time. My stop gap is to keep multiple copies of the applet with different names, but that sort of defeats the entire purpose of the script.

Looking at the solution you provided, how does the user “re-launch” the applet to restart the server selection? I’m not sure I understand idle handlers, but appears it just repeats itself every x seconds which is not the solution I need. I need to be able to “re-launch” and re-select servers if needed at anytime while the applet is running.

The database is essentially static; it rarely changes.

global newFileName

--duplicate template GenericEndive
set testPath to POSIX file "Applications/Endive Clients/zOpen Clients/GenericEndive.app"
tell application "Finder"
	set fileref to duplicate (testPath as alias)
	log fileref as string
end tell

--Open EndiveIPAddress.txt and get Job names and numbers
set theData to "/Applications/Endive Clients/Utilities/EndiveIPAddress.txt" as string

tell application "Microsoft Excel"
	open theData
	set lastCell to first row index of (find column 1 what "" look in values look at whole)
	set Names to the value of the range ("A2:A" & (lastCell - 1))
	set Addresses to the value of the range ("B2:B" & (lastCell - 1))
	close active workbook without saving
end tell

--Create the list of job names and numbers
to getIndex of i from l
	repeat with n from 1 to count l
		if l's item n is i then return n
	end repeat
	0
end getIndex

--Display list and get selected IP Address and Server Name
set theChoice to (choose from list Names)
if (theChoice is false) then error number -128

set theItem to item 1 of theChoice
set theIPItem to getIndex of theItem from Names
set ServerName to item theIPItem of Names
set IPAddress to item theIPItem of Addresses

--Set "GenericEndive copy" to match ServerName
--property baseFileName : "GenericEndive copy"
set targetDir to POSIX file "/Applications/Endive Clients/zOpen Clients/"
set newFileName to ServerName & ".app"
tell application "System Events"
	set name of file "/Applications/Endive Clients/zOpen Clients/GenericEndive copy.app" to "/Applications/Endive Clients/zOpen Clients/" & newFileName
end tell

set appn to newFileName

--Update Endive launch with selected Ip Address
tell application "TextWrangler"
	set theFile to "/Applications/Endive Clients/zOpen Clients/" & newFileName & "/Contents/Database/EnginedServer.4Dlink"
	open theFile
	replace "xxx.xxx.xxx.xxx" using IPAddress searching in text 1 of front document options {starting at top:false, wrap around:true, backwards:true, case sensitive:true, match words:true, extend selection:false}
	tell front document
		save
	end tell
end tell
tell application "TextWrangler"
	quit
end tell

--Open ServerName
tell application "Finder"
	activate
	open application file newFileName of folder "zOpen Clients" of folder "Endive Clients" of folder "Applications" of startup disk
end tell

--delay "exit" to ensure Endive has opened and is stable
delay 20

--Check if EndiveName() is still running
repeat
	if application appn is not running then exit repeat
	delay 5
end repeat

--Delete EndiveName() after quiting Endive
set myFile to "/Applications/Endive Clients/zOpen Clients/" & newFileName
try
	do shell script "rm -rf " & quoted form of myFile
end try

--set newFileNameA to "OpenEndive_0" & fileCountB & ".app"
--set the clipboard to ""
--set the clipboard to newFileNameA

------Launch Delete OpenEndive_0#
--tell application "Finder"
--	activate
--	open application file "DeleteOpenEndive_0#.app" of folder "zScripts" of folder "Endive Clients" of folder "Applications" of startup disk
--end tell

Your incrementing the file names way was and remains wrong. And I will explain why. Suppose you have already launched 3 instances of the application: EndiveName1, EndiveName2 and EndiveName3. Let’s say EndiveName1 has completed its work. You delete it and count the number of remaining applications. It will be number 2. Increasing this number by 1 you get an instance of the application called EndiveName3, which you try to run. But one instance of EndiveName3 already exists and it is still executing, so you get an error. For this reason, in my script, the new instance takes the name of the removed application EndiveName1, rather than the incremented name EndiveName3.

The user doesn’t “re-launch” the applet to restart the server selection. The idle handler “re-launchs”
itself by delay you specified (you have 5 seconds. Put bigger delay if want real work)

I have not this software on my machine, and can’t debug all the code for you for this reason. I simply rewrote the selection fragment from your script. I do not know the subtleties of the choice on your server.

The idle handler is the handler which performs repeated jobs, so you can’t reselect and start new apps without it. It doesn’t just repeat itself every x seconds. Each time it will create for you what you indicate. It is only necessary to correctly tell it what to do with the new execution. You simple applet does 1 job sequence once and terminates. And while it runs you can’t interrupt it to perform some special job and then continue it.

You can give the user a chance so that he can make a selection when he wants:


on idle {}
	tell application "Finder" to set fileCountB to count of ¬
		(files in folder targetDir whose name contains baseFileNameB)
	if fileCountB > 0 then
		repeat with i from fileCountB to 1 by step - 1 -- edited
			if application ("EndiveName" & i) is not running then
				set myFile to targetDir & "EndiveName" & i & ".app"
				set newFileNameB to "EndiveName" & i & ".app" -- edited
				do shell script "rm -rf " & quoted form of myFile
			end if
		end repeat
	else
		set newFileNameB to "EndiveName1.app"
	end if
	
	display dialog "Would you like to make a new selection?" buttons {"OK"} giving up after 3
	
	if gave up of result is false then
		set newFile to my duplicateFile(newFileNameB)
		set IPAddress to my getSelectionAndIPAddress()
		my updateEndiveLaunch(IPAddress, newFileNameB)
		-- Open EndiveName1
		tell application "Finder" to open newFile
	end if
	return 60 -- edit interval as you want
end idle

This seems to require a “main” script, which the user employs as required to set each process going, and a stay-open “watcher” script, which deletes the clone app files from the “zOpen Clients” folder as they expire.

In the system I’ve been trying, the “watcher” script maintains its own list of paths to the clone files. It should be faster to test against this list than to get the files from the folder each time and, since paths are only added to the list on instructions from the main script, any clone that’s just been created but isn’t yet running is unlikely to be deleted in error. If the watcher finds it has no more paths to watch, it quits automatically. The main script starts it up again when needed. The watcher should be saved as a stay-open application in your “zOpen Clients” folder under the name “EndiveWatcher.app”. It uses System Events, so you may have to give it permission the first couple of times it does anything:

(* Save as a stay-open application in your "zOpen Clients" folder. *)

property GenericEndiveName : "GenericEndive.app"
property watcherName : "EndiveWatcher.app"

property watchedAppPaths : missing value
property firstIdle : missing value

on run
	-- When starting up, initialise watchedAppPaths to the paths of any possible Endive app clone files already in this script's containing folder.
	-- The first idle will follow immediately, dealing with any paths whose associated apps are no longer running.
	set myPath to (path to me as text)
	tell application "System Events" to set my watchedAppPaths to path of files of container of file myPath whose ((kind is "Application") and not ((path is myPath) or (name is GenericEndiveName) or (name is watcherName)))
	set firstIdle to true
end run

on idle
	-- Check each path in watchedAppPaths. If the associated app's no longer running, zap both the file in the folder and the path in the list.
	repeat with i from 1 to (count watchedAppPaths)
		set thisPath to item i of my watchedAppPaths
		if not (application thisPath's running) then
			do shell script ("rm -rf " & quoted form of POSIX path of thisPath)
			set item i of my watchedAppPaths to missing value
		end if
	end repeat
	if (my watchedAppPaths contains missing value) then set my watchedAppPaths to my watchedAppPaths's text
	-- If there are no clone apps left, and this isn't the first idle after starting, quit.
	if ((my watchedAppPaths is {}) and (not firstIdle)) then quit
	set firstIdle to false
	
	return 5
end idle

on addApp(newAppPath)
	-- Add a new path to watchAppPaths on instructions from the main script.
	if (newAppPath does not end with ":") then set newAppPath to newAppPath & ":"
	set end of my watchedAppPaths to newAppPath
end addApp

on quit
	-- Whatever the reason for quitting, reduce watchAppPaths to a small value.
	set my watchedAppPaths to missing value
	continue quit
end quit

The main script does everything else. It can go anywhere, but assumes that the watcher script and the “GenericEndive.app” template are in your “zOpen Clients” location. The names of the clone apps may be used again as they become free.

I haven’t been able to test the code which sets the IP address (in the setServer() handler below) since I don’t have Excel and am not sure what form a “.4Dlink” file takes, but it seems to work as far as creating, naming, running, and deleting the clones is concerned. I would point out that TextWrangler is no longer supported by its developers, but BBEdit now stays in evaluation mode indefinitely unless upgraded and can be used like that for free with the developers’ blessing. The AppleScript code should be the same as for TextWrangler — except of course for the name of the application.

property zOpenClientsPath : "/Applications/Endive Clients/zOpen Clients/"
property ExcelDataPath : "/Applications/Endive Clients/Utilities/EndiveIPAddress.txt"

property GenericEndiveName : "GenericEndive.app"
property watcherName : "EndiveWatcher.app"

main()

on main()
	set zOpenClientsFolder to zOpenClientsPath as POSIX file as alias
	
	-- Make sure the stay-open watcher application's running.
	set watcherPath to ((zOpenClientsFolder as text) & watcherName & ":")
	tell application watcherPath
		if (not running) then run
	end tell
	
	-- Find an untaken name to use for the next GenericEndive.app clone.
	tell application "Finder" to set existingZClientNames to name of zOpenClientsFolder's application files
	set n to 1
	set EndiveAppName to "EndiveName" & n & ".app"
	repeat while (existingZClientNames contains EndiveAppName)
		set n to n + 1
		set EndiveAppName to "EndiveName" & n & ".app"
	end repeat
	
	-- Duplicate GenericEndive.app, rename the duplicate, and get the HFS path to it.
	tell application "Finder" to set name of (duplicate application file GenericEndiveName of zOpenClientsFolder) to EndiveAppName
	set EndiveAppPath to ((zOpenClientsFolder as text) & EndiveAppName & ":")
	
	-- Set up the server "database" in the duplicate's bundle.
	setServer(EndiveAppPath)
	
	-- Set the duplicate app going.
	tell application EndiveAppPath to activate
	
	-- Add its HFS path to the watcher application's list of watched-app paths.
	tell application watcherPath to addApp(EndiveAppPath)
end main

on setServer(EndiveAppPath)
	-- This Excel code is presumed to work.
	tell application "Microsoft Excel"
		open ExcelDataPath
		set lastCell to first row index of (find column 1 what "" look in values look at whole)
		set Names to the value of the range ("A2:A" & (lastCell - 1))
		set Addresses to the value of the range ("B2:B" & (lastCell - 1))
		close active workbook without saving
	end tell
	
	--Display list and get selected IP Address
	set theChoice to (choose from list Names)
	if (theChoice is false) then error number -128
	
	set theItem to item 1 of theChoice
	repeat with i from 1 to (count theNames)
		if (item i of theNames is theItem) then
			set IPAddress to item i of Addresses
			exit repeat
		end if
	end repeat
	
	-- Update Endive launch with selected Ip Address. It's assumed there'll be a .4Dlink file at the assumed location in the cloned app bundle.
	-- NB. TextWrangler's 32-bit and no longer supported by its developers, but BBEdit can now be used in evaluation mode indefinitely for free.
	tell application "TextWrangler"
		open file (EndiveAppPath & ":Contents:Database:EnginedServer.4Dlink")
		replace "xxx.xxx.xxx.xxx" using IPAddress searching in text 1 of front document options {starting at top:false, wrap around:true, backwards:true, case sensitive:true, match words:true, extend selection:false}
		tell front document to save
		quit
	end tell
	
	-- If the "4Dlink" file's a plain text file, the following might save having to use TextWrangler or BBEdit.
	(*
	set astid to AppleScript's text item delimiters
	set AppleScript's text item delimiters to "xxx.xxx.xxx.xxx"
	set fRef to (open for access file (EndiveAppPath & ":Contents:Database:EnginedServer.4Dlink") with write permission)
	try
		set dbText to (read fRef)
		set dbText to dbText's text items
		set AppleScript's text item delimiters to IPAddress
		set dbText to dbText as text
		set eof fRef to 0
		write dbText as string to fRef
		close access fRef
	on error
		close access fRef
		set AppleScript's text item delimiters to astid
		display dialog ("Can't write to database file “" & EndiveAppPath & ":Contents:Database:EnginedServer.4Dlink" & "”") buttons {"Delete copied app"} default button 1 with icon stop
		tell application "Finder" to delete file endivepath
	end try
	 *)
end setServer

Sorry I didn’t reply sooner. I tried Nigel’s solution but the “watcher” script stops execution and doesn’t “idle”. I’m using the code exactly as Nigel wrote. When I debug the code the list of watchedAppPaths is 0. I do have it saved as a “stay open” app and that is working. The suggested “main” script works great, it’s just the watcher app won’t idle.

Not sure what I did wrong.

I was using the wrong base path. Re ran the debugger and the watchAppPaths is populated with the correct apps names, but each name has a “:” appended to the end of the name. Not sure where this is being added in the code.

I was able to get rid of the added “:” at the end of the appPath names, but the watcher app still isn’t watching. If I quit the watcher app and relaunch it, it correctly deletes the apps that aren’t running. So the code works, it just isn’t “watching”.