Timer Script - Choose from list

I can’t seem to figure out what I’m doing wrong here. I’m sure it’s obvious I just need a second set of eyes. I’m trying to set up a timer script that will be part of a much larger script but for now the timer script is isolated and all it does it delay X amount of time. If someone could tell me what I’m doing wrong or even give me a better way to do it, it would be much appreciated. At the moment, the dialog at the end always says “Run Time = 0 Seconds” because ScriptTime isn’t being set to the number of seconds like I want it to.

set ScriptTime to (choose from list {"3 Hours", "5 Hours", "7 Hours", "10 Hours"})

if ScriptTime is "3 Hours" then set ScriptTime to "10800"
if ScriptTime is "5 Hours" then set ScriptTime to "18000"
if ScriptTime is "7 Hours" then set ScriptTime to "25200"
if ScriptTime is "10 Hours" then set ScriptTime to "36000"

set ScriptStart to current date

delay ScriptTime

set ScriptStop to current date

display dialog "Run Time = " & (ScriptStop - ScriptStart) & " seconds."

Model: MacBook Air
Browser: Safari 536.30.1
Operating System: Mac OS X (10.8)

Choose from list returns a list of selected items. So I think the problem is in your comparison.

so it should be:

if ScriptTime is {"3 Hours"} then set ScriptTime to "10800"

or

if item 1 of  ScriptTime is "3 Hours" then set ScriptTime to "10800"

I think that will solve your problem. I first though that sending an string as an argument to the delay command would be a problem but it seems that delay coerce the string perfectly to an integer by itself.

Hello I had some trouble getting through, so I wrote this post before DJ Bazzie Wazzie.

I take a different approach to solving the problem, I coerce the chosen item to text. (I have also tossed in a test for false, so that the script quit’s if the user redecides.

There were just one error and that was that the choose from list, returns a list, and that this list aren’t coerced to text when you compare with the different values.

I also changed your multiple if-tests into one new one, that is nested, so we bail out the second we have had a hit.

set ScriptTime to (choose from list {"3 Hours", "5 Hours", "7 Hours", "10 Hours"})
if ScriptTime is false then error number -128
set ScriptTime to ScriptTime as text
if ScriptTime is "3 Hours" then
	set ScriptTime to "10800"
else if ScriptTime is "5 Hours" then
	set ScriptTime to "18000"
else if ScriptTime is "7 Hours" then
	set ScriptTime to "25200"
else if ScriptTime is "10 Hours" then
	set ScriptTime to "36000"
end if

set ScriptStart to current date

delay ScriptTime

set ScriptStop to current date

display dialog "Run Time = " & (ScriptStop - ScriptStart) & " seconds."

Edit

I just want to comment a little bit on the way you coded your if-tests: This is really ok to do, if you do it because a long statement consistsing of ands and other composite logic statements. In this particular case it is better with an if then else if construct. A fine word for this is cyclomacy, and the theory is that the lesser branches you have in a program/handler the easier it is to go back and change it. Now you would object to the way I make your hander brutally quit, but I think that is the exception to the rule, since this is a fatal step. I also think the rule should be bent, when strictly following the rule leads to introducing a more complicated logic and control variables to make the correct thing happen.

Below is a contrived example, that fails anyway, since you can’t have “if clusters” without an endif in Applescript,
but I have shown how such a “if cluster” would have been implemented in C.


set temperature to "hot"
set wind to "only slight"
set working_day to "day off"
# example 1 using and
if temperature is "hot" and wind is "only slight" and working_day is "day_off" then goto_theBeach()
# example 2 which is a failure in Applescript since you can't do it
# without an endif, but it still illustrates my point
#
# In C this would look like:
# if (hot_temp)
# if (only_slight_wind)
# if (day_off)
# goto_theBeach()
#
# This "logic break down" can't be performed in Applescript, so there
# you would end up with something like this.
if temperature is "hot" then
	if wind is "only slight" then
		if working_day is "day_off" then
			goto_theBeach()
		end if
	end if
end if

on goto_theBeach()
	set a to "b"
end goto_theBeach

Thank you both for the prompt replies. I ended up following DJ Bazzie Wazzie’s advice, using his first idea, which worked flawlessly. I do see your point though, McUsrII, about nesting if/thens. I will probably end up changing that in the full script. I really just wanted to get that darn timer working. :smiley:

I incorporated all your suggestions into my larger script. Here’s what I have so far…


display dialog "Max CPU will increase the CPU usage to near 100%. This is an effective way to troubleshoot issues that occur under heavy CPU usage. While Max CPU is running, the system may become unresponsive."

set CPUCores to (do shell script "system_profiler SPHardwareDataType | grep \"Total Number of Cores\" | tail -c 2")
set VirtualCores to (CPUCores * 2)

set ScriptTime to (choose from list {"3 Hours", "5 Hours", "7 Hours", "10 Hours"} with title "Set time for Max CPU to run")

if ScriptTime is false then error number -128
set ScriptTime to ScriptTime as text
if ScriptTime is "3 Hours" then
	set ScriptTime to "10800"
else if ScriptTime is "5 Hours" then
	set ScriptTime to "18000"
else if ScriptTime is "7 Hours" then
	set ScriptTime to "25200"
else if ScriptTime is "10 Hours" then
	set ScriptTime to "36000"
end if

set ScriptStart to hours of (current date)

repeat VirtualCores times
	do shell script "yes > /dev/null 2>&1 &"
end repeat

delay ScriptTime
do shell script "killall yes"

set ScriptStop to hours of (current date)
set RunTime to (ScriptStop - ScriptStart)
display dialog "Max CPU ran for " & RunTime & " Hours"

Basically this script will pick a set number of hours and run the yes command as a shell script in the background as many times as are equal to the number of virtual cores the computer has. Or at least that’s my hope. I have tested it on my MacBook with Activity Monitor open and it works perfectly.

What’s the point, you ask? Well, where I work we frequently have people coming in with their computers saying they have issues like overheating or crashing during high CPU usage. My hope is that this script will be able to simulate this and re-create issues.

Hi,

you could simplify the if - else if chain


set ScriptTime to ScriptTime as text
if ScriptTime is "3 Hours" then
	set ScriptTime to "10800"
else if ScriptTime is "5 Hours" then
	set ScriptTime to "18000"
else if ScriptTime is "7 Hours" then
	set ScriptTime to "25200"
else if ScriptTime is "10 Hours" then
	set ScriptTime to "36000"
end if

with


set ScriptTime to (((word 1 of item 1 of ScriptTime) as integer) * hours) as text

Hello.

I see your problem. I just think there must be a zillion of reasons for the cpu-usage to grow so large, flash, maybe safari, maybe mdls is updating, maybe too many finder windows open, and some file copying is taking place.

How about educating your users, to have Activity Monitor open, and the process list sorted on CPU-usage, so you can see which process(es) are causing the cpu-usage, that leads to the crash?. Just an idea. You can also educate them on pushing the “red” button" to kill that process. :slight_smile:

I guess you have some way to log stuff, but when all cores are busy, then it can be hard to get a process list with cpu times. So, if you made the users email you, with the name of the cpu-hog they just killed, then you should gather statistics. When your users machines are put on the table, you should cease the opportunity to clean hardware caches and look for dyld conflicts, if there are no other good explanation as to why their cpu-usage gets that high.

It is natural that other processes may break, when the cpu closes in on maximum cpu percentage.

Stefan,
Very nice.:slight_smile:

Hello.

I also think that, less lines to debug, and reusing the text from the question. :slight_smile:

And in practice, even the explicit coercion to integer could be cut, as an automatic one would be attempted for the multiplication.


set ScriptTime to ((word 1 of item 1 of ScriptTime) * hours) as text

good to know, thanks.

I assumed the common operator rule, that the class of the result is the class of the leftmost operand

That’s the important one to know, of course. :slight_smile:


"Hello " & {"world"}
--> "Hello world"

-- But:
{"Hello "} & "world"
--> {"Hello ", "world"}

More accurately, it should be "the type of operation performed depends on the class of the leftmost operand:

2000000 > "5" -- The leftmost operand is a number, so numeric comparison.
--> true

"2000000" < 5 -- The leftmost operand is text, so lexical comparison.
--> true

With the mathematical operators ‘*’, ‘+’, and ‘-’, it’s a bit more complicated:

3 * 4 -- Two integers, so integer multiplication.
--> 12

3.0 * 4 -- One of the operands is a real, so real multiplication.
--> 12.0

3 * 4.0 -- Ditto.
--> 12.0

"3" * "4" -- Both texts represent integers, so coercion thereto and integer multiplication.
--> 12

"3.0" * "4.0" -- Both texts represent whole-number reals, but neither _is_ a real, so coercion to integer and integer multiplication.
--> 12

"3.5" * "4.0" -- One of the texts can't be coerced to integer without changing its numeric value, so coercion to real and real multiplication.
--> 14.0

‘div’ always returns an integer (unless the result’s too big to be one) and ‘/’ always returns a real.

Fortunately, it’s all automatic and one only occasionally has to think about what’s going on. :wink:

The sample with boolean below, is totally contrived, and I see no practical benefit of it, maybe someone else will.

This coerces automatically, the text into a boolean, the and operator is the piece of magic.

set boolTxtVal to "true"
if true and boolTxtVal then
	log "true"
end if

The or operator also instigates the coercion:

set boolTxtVal to "true"
if false or boolTxtVal then
	log "true"
end if

“is” doesn’t work:

set boolTxtVal to "true"
if true is boolTxtVal then
	log "true"
end if

“not” neither:

set boolTxtVal to "true"
if not boolTxtVal then
	log "true"
end if

But a manual coercion works great: (for completeness)

set boolTxtVal to "true"
if boolTxtVal as boolean then
	log "true"
end if

You get the same results, if you swap 1 for “true” and 0 for “false”. Personally, I don’t mind seeing a “superfluos” coercion, as it tends to make the intent clearer, but it actually increases the text size of the code, when saved as run only, the one with the explicit coercion was 2 bytes larger.