--
--  DASAppDelegate.applescript
--  itunes-concatenator
--
--  Created by David Schlachter on 2014-08-26.
--  Copyright (c) 2014 Red Eft Software. All rights reserved.
--

-- via http://macscripter.net/viewtopic.php?pid=173787 ; apparently needed for using arrays

script DASAppDelegate
	property parent : class "NSObject"

    global these_files, these_times, these_titles, the_index, the_pipes, theCounter, cmdPrefix

	-- IBOutlets
	property window : missing value
    property trackTable : missing value
    property catName : missing value
    property catArtist : missing value
    property catAlbum : missing value
    property catComposer : missing value
    property catGenre : missing value
    property catTrack : missing value
    property catTracks : missing value
    property catDisc : missing value
    property catDiscs : missing value

    -- Again, per macscripter, we'll set up bindings for the options
    property pcatName : ""
    property pcatArtist : ""
    property pcatAlbum : ""
    property pcatComposer : ""
    property pcatGenre : ""
    property pcatTrack : ""
    property pcatTracks : ""
    property pcatDisc : ""
    property pcatDiscs : ""

    -- Empty strings for each file name and location
    property pEachName : ""
    property pEachLocation : ""

    property these_titles : {}
    property these_files : {}
    property these_times: {}
    property the_index: {}
    property the_pipes: {}

    property theCounter : ""
    property cmdPrefix : "if [[ -r /etc/profile ]];then . /etc/profile;fi;if [[ -r ~/.bashrc ]];then . ~/.bashrc;fi;if [[ -r ~/.bash_profile ]];then . ~/.bash_profile;fi;"

    on awakeFromNib()
        --
        -- Check for FFMPEG and MP4v2
        --
        -- (This works, but it's ugly!)
        --
        --
        try
            do shell script cmdPrefix & " if [ -x \"`/usr/bin/which ffmpeg`\" ];then exit 0;else exit 1;fi"
        on error number error_number
            display dialog "You must install FFMPEG and MP4v2 to continue. \n\nYou may have to install Xcode Command Line Tools and Homebrew first. If you continue, we'll attempt to install them for you if they are not already present. \n\nIf you have already installed FFMPEG and MP4v2, ensure that they are in your bash path." buttons {"Quit","Install"} default button 2
            If button returned of result is "Install" then
                try
                    tell application "Terminal"
                        -- TODO: This should be cleaner -- Terminal in front, only one window, focus back to the cat'er afterwards
                        set newTab to do script cmdPrefix & "if [[ -x `which brew` ]];then brew install ffmpeg;else /usr/bin/ruby -e \"$(/usr/bin/curl -fsSL https://raw.github.com/Homebrew/homebrew/go/install)\";brew install ffmpeg mp4v2;fi"
                        delay 4
                        repeat
                            delay 0.1
                            if not busy of newTab then exit repeat
                        end repeat
                    end tell
                     -- TODO: This needs a better test, i.e., check if ffmpeg is actually accessible on the path
                    display dialog "FFMPEG was successfully installed"
                    -- TODO: This should actually work! (Bring us back to the foreground)
                    activate current application
                on error number error_number
                    display dialog "FFMPEG did not successfully install"
                end try
            end If
            If button returned of result is "Quit" then
                -- Fix!
                current application's NSApp's terminate()
            end If
        end try
    end awakeFromNib

    on btnGetTracks_(sender)
        -- Code to add iTunes tracks to our list
        -- via http://dougscripts.com/itunes/itinfo/info02.php and http://www.randomsequence.com/articles/applescript-to-send-selected-itunes-tracks-using-mail/
        tell application "iTunes"
            set these_titles to {}
            set these_times to {}
            set these_files to {}
            set the_index to {}
            if selection is not {} then -- there ARE tracks selected...
                set mySelection to selection
                set i to 1
                repeat with aTrack in mySelection
                    if class of aTrack is file track then
                        set end of these_titles to ((name of aTrack) as string)
                        set end of these_times to ((time of aTrack) as string)
                        set end of these_files to (posix path of (get location of aTrack))
                        set end of the_index to (count of these_titles)
                        -- Get metadata from the first track
                        if i is 1 then
                            set pcatArtist to ((artist of aTrack) as string)
                            set pcatAlbum to ((album of aTrack) as string)
                            set pcatComposer to ((composer of aTrack) as string)
                            set pcatGenre to ((genre of aTrack) as string)
                            set pcatDisc to ((disc number of aTrack) as string)
                            set pcatDiscs to ((disc count of aTrack) as string)
                        end if
                        set i to (i + 1)
                    end if
                end repeat
            end if
        end tell
        -- via http://stackoverflow.com/questions/25537750/setstringvalue-with-applescript-list
        set olddelimeters to AppleScript's text item delimiters
        set AppleScript's text item delimiters to "\n"
        set disp_titles to these_titles as string
        trackTable's setStringValue_(disp_titles)
        set AppleScript's text item delimiters to olddelimeters
    end btnGetTracks_

    on btnConcatenate_(sender)
        set the_pipes to {}
        repeat with theIndex in the_index
            -- TODO: Needs error checking!
            -- TODO: We need to check what kind of audio files we have, then adjust accordingly
            do shell script (cmdPrefix & "ffmpeg -i \"" & (item theIndex of these_files as text) & "\" -c copy -bsf:v h264_mp4toannexb -f mpegts /private/tmp/concat" & theIndex & ".ts 2> /dev/null" as text)
            log ("Processed file number" & theIndex) as text
            set end of the_pipes to ("/private/tmp/concat" & theIndex & ".ts" as text)
        end repeat
        -- Run the actual concatenation command in ffmpeg (for mp4/AAC files only!)
        -- via https://trac.ffmpeg.org/wiki/How%20to%20concatenate%20(join,%20merge)%20media%20files
        set olddelimeters to AppleScript's text item delimiters
        set AppleScript's text item delimiters to "|"
        set disp_thepipes to the_pipes as string
        do shell script (cmdPrefix & "ffmpeg -f mpegts -i \"concat:" & (disp_thepipes as text) & "\" -c copy -bsf:a aac_adtstoasc /private/tmp/cat.mp4")
        set AppleScript's text item delimiters to olddelimeters
        -- Log some debugging information
        log (pcatArtist as string)
        log (pcatAlbum as string)
        log (pcatComposer as string)
        log (pcatGenre as string)
        log (pcatDisc as string)
        log (pcatDiscs as string)
        -- Now let's create the chapter file
        repeat with theIndex in the_index
            if theIndex < 2 then
                do shell script ("/bin/echo \"00:00:00.000 " & (item theIndex of these_titles as text) & "\" > /private/tmp/cat.chapters.txt" as text)
                set theCounter to (do shell script (cmdPrefix & "ffprobe -loglevel panic -show_streams /private/tmp/concat" & (theIndex as text) & ".ts | egrep -m 1 'duration=[0-9]+\\.' | sed 's/duration=\\([0-9]*[0-9]\\)\\.[0-9]*/\\1/'" as text) as string)
            else
                set theDateStamp to do shell script (cmdPrefix & "t="& (theCounter as text) & ";((sec=t%60, t/=60, min=t%60, hrs=t/60));timestamp=$(printf \"%02d:%02d:%02d\" $hrs $min $sec);/bin/echo $timestamp" as text)
                do shell script ("/bin/echo \"" & (theDateStamp as text) & ".000 " & (item theIndex of these_titles as text) & "\" >> /private/tmp/cat.chapters.txt" as text)
                log ("Before the addition, theCounter is " & theCounter) as text
                set theCounter to do shell script (cmdPrefix & "t=" & theCounter & ";t=`echo $t\"+\\`ffprobe -loglevel panic -show_streams /private/tmp/concat" & (theIndex as text) & ".ts | egrep -m 1 'duration=[0-9]+\\.' | sed 's/duration=\\([0-9]*[0-9]\\)\\.[0-9]*/\\1/'\\`\" | bc`;echo $t" as text)
                log ("After the addition, theCounter is " & theCounter) as text
            end if
        end repeat
        -- Chapterize cat.mp4
        do shell script (cmdPrefix & "mp4chaps -i /private/tmp/cat.mp4" as text)
        -- Clean up
        do shell script "/bin/rm /private/tmp/concat* /private/tmp/cat.chapters.txt /private/tmp/cat.mp4"
        set theCounter to ""
    end btnConcatenate_

	on applicationWillFinishLaunching_(aNotification)
		-- Insert code here to initialize your application before any files are opened
	end applicationWillFinishLaunching_

	on applicationShouldTerminate_(sender)
		-- Insert code here to do any housekeeping before your application quits
		return current application's NSTerminateNow
	end applicationShouldTerminate_

end script

--
--  DASAppDelegate.applescript
--  itunes-concatenator
--
--  Created by David Schlachter on 2014-08-26.
--  Copyright (c) 2014 Red Eft Software. All rights reserved.
--

-- via http://macscripter.net/viewtopic.php?pid=173787 ; apparently needed for using arrays

script DASAppDelegate
	property parent : class "NSObject"

    global these_files, these_times, these_titles, the_index, the_pipes, theCounter, cmdPrefix

	-- IBOutlets
	property window : missing value
    property trackTable : missing value
    property catName : missing value
    property catArtist : missing value
    property catAlbum : missing value
    property catComposer : missing value
    property catGenre : missing value
    property catTrack : missing value
    property catTracks : missing value
    property catDisc : missing value
    property catDiscs : missing value

    -- Again, per macscripter, we'll set up bindings for the options
    property pcatName : ""
    property pcatArtist : ""
    property pcatAlbum : ""
    property pcatComposer : ""
    property pcatGenre : ""
    property pcatTrack : ""
    property pcatTracks : ""
    property pcatDisc : ""
    property pcatDiscs : ""

    -- Empty strings for each file name and location
    property pEachName : ""
    property pEachLocation : ""

    property these_titles : {}
    property these_files : {}
    property these_times: {}
    property the_index: {}
    property the_pipes: {}

    property theCounter : ""
    property cmdPrefix : "if [[ -r /etc/profile ]];then . /etc/profile;fi;if [[ -r ~/.bashrc ]];then . ~/.bashrc;fi;if [[ -r ~/.bash_profile ]];then . ~/.bash_profile;fi;"

    on awakeFromNib()
        --
        -- Check for FFMPEG and MP4v2
        --
        -- (This works, but it's ugly!)
        --
        --
        try
            do shell script cmdPrefix & " if [ -x \"`/usr/bin/which ffmpeg`\" ];then exit 0;else exit 1;fi"
        on error number error_number
            display dialog "You must install FFMPEG and MP4v2 to continue. \n\nYou may have to install Xcode Command Line Tools and Homebrew first. If you continue, we'll attempt to install them for you if they are not already present. \n\nIf you have already installed FFMPEG and MP4v2, ensure that they are in your bash path." buttons {"Quit","Install"} default button 2
            If button returned of result is "Install" then
                try
                    tell application "Terminal"
                        -- TODO: This should be cleaner -- Terminal in front, only one window, focus back to the cat'er afterwards
                        set newTab to do script cmdPrefix & "if [[ -x `which brew` ]];then brew install ffmpeg;else /usr/bin/ruby -e \"$(/usr/bin/curl -fsSL https://raw.github.com/Homebrew/homebrew/go/install)\";brew install ffmpeg mp4v2;fi"
                        delay 4
                        repeat
                            delay 0.1
                            if not busy of newTab then exit repeat
                        end repeat
                    end tell
                     -- TODO: This needs a better test, i.e., check if ffmpeg is actually accessible on the path
                    display dialog "FFMPEG was successfully installed"
                    -- TODO: This should actually work! (Bring us back to the foreground)
                    activate current application
                on error number error_number
                    display dialog "FFMPEG did not successfully install"
                end try
            end If
            If button returned of result is "Quit" then
                -- Fix!
                current application's NSApp's terminate()
            end If
        end try
    end awakeFromNib

    on btnGetTracks_(sender)
        -- Code to add iTunes tracks to our list
        -- via http://dougscripts.com/itunes/itinfo/info02.php and http://www.randomsequence.com/articles/applescript-to-send-selected-itunes-tracks-using-mail/
        tell application "iTunes"
            set these_titles to {}
            set these_times to {}
            set these_files to {}
            set the_index to {}
            if selection is not {} then -- there ARE tracks selected...
                set mySelection to selection
                set i to 1
                repeat with aTrack in mySelection
                    if class of aTrack is file track then
                        set end of these_titles to ((name of aTrack) as string)
                        set end of these_times to ((time of aTrack) as string)
                        set end of these_files to (posix path of (get location of aTrack))
                        set end of the_index to (count of these_titles)
                        -- Get metadata from the first track
                        if i is 1 then
                            set pcatArtist to ((artist of aTrack) as string)
                            set pcatAlbum to ((album of aTrack) as string)
                            set pcatComposer to ((composer of aTrack) as string)
                            set pcatGenre to ((genre of aTrack) as string)
                            set pcatDisc to ((disc number of aTrack) as string)
                            set pcatDiscs to ((disc count of aTrack) as string)
                        end if
                        set i to (i + 1)
                    end if
                end repeat
            end if
        end tell
        -- Display the songs to be concatenated
        -- via http://stackoverflow.com/questions/25537750/setstringvalue-with-applescript-list
        set olddelimeters to AppleScript's text item delimiters
        set AppleScript's text item delimiters to "\n"
        set disp_titles to these_titles as string
        trackTable's setStringValue_(disp_titles)
        set AppleScript's text item delimiters to olddelimeters
        -- Update the default metadata
        catArtist's setStringValue_(pcatArtist)
        catAlbum's setStringValue_(pcatAlbum)
        catComposer's setStringValue_(pcatComposer)
        catGenre's setStringValue_(pcatGenre)
        catDisc's setStringValue_(pcatDisc)
        catDiscs's setStringValue_(pcatDiscs)
    end btnGetTracks_

    on btnConcatenate_(sender)
        set the_pipes to {}
        repeat with theIndex in the_index
            -- TODO: Needs error checking!
            -- TODO: We need to check what kind of audio files we have, then adjust accordingly
            do shell script (cmdPrefix & "ffmpeg -i \"" & (item theIndex of these_files as text) & "\" -c copy -bsf:v h264_mp4toannexb -f mpegts /private/tmp/concat" & theIndex & ".ts 2> /dev/null" as text)
            log ("Processed file number" & theIndex) as text
            set end of the_pipes to ("/private/tmp/concat" & theIndex & ".ts" as text)
        end repeat
        -- Run the actual concatenation command in ffmpeg (for mp4/AAC files only!)
        -- via https://trac.ffmpeg.org/wiki/How%20to%20concatenate%20(join,%20merge)%20media%20files
        set olddelimeters to AppleScript's text item delimiters
        set AppleScript's text item delimiters to "|"
        set disp_thepipes to the_pipes as string
        do shell script (cmdPrefix & "ffmpeg -f mpegts -i \"concat:" & (disp_thepipes as text) & "\" -c copy -bsf:a aac_adtstoasc /private/tmp/cat.mp4")
        set AppleScript's text item delimiters to olddelimeters
        -- Log some debugging information
        log (pcatArtist as string)
        log (pcatAlbum as string)
        log (pcatComposer as string)
        log (pcatGenre as string)
        log (pcatDisc as string)
        log (pcatDiscs as string)
        -- Now let's create the chapter file
        repeat with theIndex in the_index
            if theIndex < 2 then
                do shell script ("/bin/echo \"00:00:00.000 " & (item theIndex of these_titles as text) & "\" > /private/tmp/cat.chapters.txt" as text)
                set theCounter to (do shell script (cmdPrefix & "ffprobe -loglevel panic -show_streams /private/tmp/concat" & (theIndex as text) & ".ts | egrep -m 1 'duration=[0-9]+\\.' | sed 's/duration=\\([0-9]*[0-9]\\)\\.[0-9]*/\\1/'" as text) as string)
            else
                set theDateStamp to do shell script (cmdPrefix & "t="& (theCounter as text) & ";((sec=t%60, t/=60, min=t%60, hrs=t/60));timestamp=$(printf \"%02d:%02d:%02d\" $hrs $min $sec);/bin/echo $timestamp" as text)
                do shell script ("/bin/echo \"" & (theDateStamp as text) & ".000 " & (item theIndex of these_titles as text) & "\" >> /private/tmp/cat.chapters.txt" as text)
                log ("Before the addition, theCounter is " & theCounter) as text
                set theCounter to do shell script (cmdPrefix & "t=" & theCounter & ";t=`echo $t\"+\\`ffprobe -loglevel panic -show_streams /private/tmp/concat" & (theIndex as text) & ".ts | egrep -m 1 'duration=[0-9]+\\.' | sed 's/duration=\\([0-9]*[0-9]\\)\\.[0-9]*/\\1/'\\`\" | bc`;echo $t" as text)
                log ("After the addition, theCounter is " & theCounter) as text
            end if
        end repeat
        -- Chapterize cat.mp4
        do shell script (cmdPrefix & "mp4chaps -i /private/tmp/cat.mp4" as text)
        -- Clean up
        do shell script "/bin/rm /private/tmp/concat* /private/tmp/cat.chapters.txt /private/tmp/cat.mp4"
        set theCounter to ""
    end btnConcatenate_

	on applicationWillFinishLaunching_(aNotification)
		-- Insert code here to initialize your application before any files are opened
	end applicationWillFinishLaunching_

	on applicationShouldTerminate_(sender)
		-- Insert code here to do any housekeeping before your application quits
		return current application's NSTerminateNow
	end applicationShouldTerminate_

end script

Update the text fields when tracks are loaded


(* commented out printer section for now
tell application "iPhone Simulator" to activate

tell application "System Events"
    tell process "iPhone Simulator"
        tell menu bar 1
            tell menu bar item "File"
                tell menu "File"
                    click menu item "Open Printer Simulator"
                end tell
            end tell
        end tell
    end tell
end tell
*)

tell application "iPhone Simulator" to launch

set inTime to current date
repeat
    tell application "System Events"
        if "iPhone Simulator" is in (get name of processes) then exit repeat
    end tell
    if (current date) - inTime is greater than 10 then exit repeat
    delay 0.2
end repeat

tell application "iPhone Simulator" to activate

set inTime to current date
repeat
    tell application "System Events"
        if visible of process "iPhone Simulator" is true then exit repeat
    end tell
    if (current date) - inTime is greater than 10 then exit repeat
    delay 0.2
end repeat

tell application "System Events"
    tell process "iPhone Simulator"
        tell menu bar 1
            tell menu bar item "iOS Simulator"
                tell menu "iOS Simulator"
                    click menu item "Reset Content and Settings…"
                end tell
            end tell
        end tell

        tell window 1
            click button "Reset"
        end tell
    end tell
end tell

tell application "iPhone Simulator" to quit

set inTime to current date
repeat
    tell application "System Events"
        if "iPhone Simulator" is not in (get name of processes) then exit repeat
    end tell
    if (current date) - inTime is greater than 10 then exit repeat
    delay 0.2
end repeat

-- tell application "System Events" to tell process "Printer Simulator" to set visible to false

(* commented out printer section for now
tell application "iPhone Simulator" to activate

tell application "System Events"
    tell process "iPhone Simulator"
        tell menu bar 1
            tell menu bar item "File"
                tell menu "File"
                    click menu item "Open Printer Simulator"
                end tell
            end tell
        end tell
    end tell
end tell
*)

tell application "iOS Simulator" to launch

set inTime to current date
repeat
    tell application "System Events"
        if "iOS Simulator" is in (get name of processes) then exit repeat
    end tell
    if (current date) - inTime is greater than 10 then exit repeat
    delay 0.2
end repeat

tell application "iOS Simulator" to activate

set inTime to current date
repeat
    tell application "System Events"
        if visible of process "iOS Simulator" is true then exit repeat
    end tell
    if (current date) - inTime is greater than 10 then exit repeat
    delay 0.2
end repeat

tell application "System Events"
    tell process "iOS Simulator"
        tell menu bar 1
            tell menu bar item "iOS Simulator"
                tell menu "iOS Simulator"
                    click menu item "Reset Content and Settings…"
                end tell
            end tell
        end tell

        tell window 1
            click button "Reset"
        end tell
    end tell
end tell

tell application "iOS Simulator" to quit

set inTime to current date
repeat
    tell application "System Events"
        if "iOS Simulator" is not in (get name of processes) then exit repeat
    end tell
    if (current date) - inTime is greater than 10 then exit repeat
    delay 0.2
end repeat

-- tell application "System Events" to tell process "Printer Simulator" to set visible to false

fix apple script

fix apple script


set myTabs to {"http://app.getsentry.com/", "http://github.com/uberVU/thehole/issues/assigned/palcu?direction=desc&labels=&milestone=&page=1&sort=updated&state=open/", "https://mail.google.com/mail/u/1/?shva=1#inbox", "https://drive.google.com/a/hootsuite.com/#folders/0BwuFsHJDxJWPYmxXQ1VQVlN6T2M"}
tell application "Google Chrome"
	activate
	repeat with i in myTabs
		open location i
	end repeat
end tell

set myTabs to {"https://github.com/search?utf8=%E2%9C%93&q=assignee%3Apalcu+state%3Aopen&type=Issues&ref=searchresults", "https://mail.google.com/mail/u/1/?shva=1#inbox", "https://drive.google.com/a/hootsuite.com/#folders/0BwuFsHJDxJWPYmxXQ1VQVlN6T2M"}
tell application "Google Chrome"
	activate
	repeat with i in myTabs
		open location i
	end repeat
end tell

Update URLs that open at the office

Update URLs that open at the office


set current_path to POSIX path of ((path to me as text) & "::")

-- get work apps
set appList to {}
set myApps to paragraphs of (read current_path & "apps.txt")
repeat with nextLine in myApps
	if length of nextLine is greater than 0 then
		copy (nextLine as string) to the end of appList
	end if
end repeat

-- close work apps
repeat with i in appList
	tell application i
		quit
	end tell
end repeat

-- run other scripts from folder
set scriptList to {"clean_repos", "halt_vagrant"}
repeat with i in scriptList
	run script current_path & i & ".applescript"
end repeat

set current_path to POSIX path of ((path to me as text) & "::")

-- get work apps
set appList to {}
set myApps to paragraphs of (read current_path & "apps.txt")
repeat with nextLine in myApps
	if length of nextLine is greater than 0 then
		copy (nextLine as string) to the end of appList
	end if
end repeat

-- close work apps
repeat with i in appList
	tell application i
		quit
	end tell
end repeat

-- run other scripts from folder
set scriptList to {"halt_vagrant"}
repeat with i in scriptList
	run script current_path & i & ".applescript"
end repeat

Remove clean_repos

Remove clean_repos


tell application "Finder"
	set json_path to file "json.scpt" of folder of (path to me)
end tell
set json to load script (json_path as alias)

on is_running(appName)
	tell application "System Events" to (name of processes) contains appName
end is_running

set reply to json's createDict()
if is_running("Hermes") then
	reply's setkv("running", true)
	set hermesInfo to json's createDict()
--	set hermesStations to json's createDict()
	tell application "Hermes"
		hermesInfo's setkv("state", playback state as string)
		hermesInfo's setkv("volume", playback volume)

-- XXX: execution error: Hermes got an error: every station doesn’t understand the “count” message. (-1708)
--		repeat with theStation in stations
--			hermesStations's setkv("name", theStation's name)
--			hermesStations's setkv("id", theStation's station ID)
--		end repeat

		hermesInfo's setkv("title", current song's title)
		hermesInfo's setkv("artist", current song's artist)
		hermesInfo's setkv("album", current song's album)
		hermesInfo's setkv("artwork", current song's artwork URL)
		hermesInfo's setkv("rating", current song's rating)
		hermesInfo's setkv("position", playback position as integer)
		hermesInfo's setkv("duration", current song duration as integer)
		hermesInfo's setkv("station_name", current station's name)
		hermesInfo's setkv("station_id", current station's station ID)
	end tell
--	hermesInfo's setkv("stations", hermesStations)
	reply's setkv("info", hermesInfo)
else
	reply's setkv("running", false)
end if
reply's setkv("time", (do shell script "date -u +%s"))
return reply's toJson()

tell application "Finder"
	set json_path to file "json.scpt" of folder of (path to me)
end tell
set json to load script (json_path as alias)

on is_running(appName)
	tell application "System Events" to (name of processes) contains appName
end is_running

on hermes_status()
	global json
	set reply to json's createDict()
	if is_running("Hermes") then
		reply's setkv("running", true)
		set hermesInfo to json's createDict()
--		set hermesStations to json's createDict()
		tell application "Hermes"
			hermesInfo's setkv("state", playback state as string)
			hermesInfo's setkv("volume", playback volume)

--			XXX: execution error: Hermes got an error: every station doesn’t understand the “count” message. (-1708)
--			repeat with theStation in stations
--				hermesStations's setkv("name", theStation's name)
--				hermesStations's setkv("id", theStation's station ID)
--			end repeat

			hermesInfo's setkv("title", current song's title)
			hermesInfo's setkv("artist", current song's artist)
			hermesInfo's setkv("album", current song's album)
			hermesInfo's setkv("artwork", current song's artwork URL)
			hermesInfo's setkv("rating", current song's rating)
			hermesInfo's setkv("position", playback position as integer)
			hermesInfo's setkv("duration", current song duration as integer)
			hermesInfo's setkv("station_name", current station's name)
			hermesInfo's setkv("station_id", current station's station ID)
		end tell
--		hermesInfo's setkv("stations", hermesStations)
		reply's setkv("info", hermesInfo)
	else
		reply's setkv("running", false)
	end if
	reply's setkv("time", (do shell script "date -u +%s"))
	return reply's toJson()
end hermes_status

return hermes_status()

Move script logic into hermes_status()

Move script logic into hermes_status()


############################
# How to generate the PDFs #
############################
# 1. Generate Cover.pdf with latest version date
#    a. Create "ebook" folder in ~/Downloads
#    b. update date in cover.html
#    c. open in safari file:///Users/frank/Sites/ServerlessStackCom/etc/cover.html
#    d. "Export to PDF…"
#    e. Place Cover.pdf in ~/ebook folder
# 2. Ensure "ebook" folder is an option when "Export to PDF…" in Safari
# 3. In terminal, run "osascript pdf.scpt"

set theChaptersStr to "who-is-this-guide-for
what-does-this-guide-cover
how-to-get-help
what-is-serverless
what-is-aws-lambda
why-create-serverless-apps
create-an-aws-account
create-an-iam-user
what-is-iam
what-is-an-arn
configure-the-aws-cli
create-a-dynamodb-table
create-an-s3-bucket-for-file-uploads
create-a-cognito-user-pool
create-a-cognito-test-user
setup-the-serverless-framework
add-support-for-es6-es7-javascript
initialize-the-backend-repo
add-a-create-note-api
add-a-get-note-api
add-a-list-all-the-notes-api
add-an-update-note-api
add-a-delete-note-api
working-with-3rd-party-apis
setup-a-stripe-account
add-a-billing-api
load-secrets-from-env
test-the-billing-api
unit-tests-in-serverless
handle-api-gateway-cors-errors
deploy-the-apis
create-a-cognito-identity-pool
cognito-user-pool-vs-identity-pool
test-the-apis
create-a-new-reactjs-app
initialize-the-frontend-repo
add-app-favicons
setup-custom-fonts
setup-bootstrap
handle-routes-with-react-router
create-containers
adding-links-in-the-navbar
handle-404s
configure-aws-amplify
create-a-login-page
login-with-aws-cognito
add-the-session-to-the-state
load-the-state-from-the-session
clear-the-session-on-logout
redirect-on-login-and-logout
give-feedback-while-logging-in
create-a-custom-react-hook-to-handle-form-fields
create-a-signup-page
create-the-signup-form
signup-with-aws-cognito
add-the-create-note-page
call-the-create-api
upload-a-file-to-s3
list-all-the-notes
call-the-list-api
display-a-note
render-the-note-form
save-changes-to-a-note
delete-a-note
create-a-settings-page
add-stripe-keys-to-config
create-a-billing-form
connect-the-billing-form
setup-secure-pages
create-a-route-that-redirects
use-the-redirect-routes
redirect-on-login
getting-production-ready
what-is-infrastructure-as-code
configure-dynamodb-in-serverless
configure-s3-in-serverless
configure-cognito-user-pool-in-serverless
configure-cognito-identity-pool-in-serverless
deploy-your-serverless-infrastructure
automating-serverless-deployments
setting-up-your-project-on-seed
configure-secrets-in-seed
deploying-through-seed
set-custom-domains-through-seed
test-the-configured-apis
automating-react-deployments
manage-environments-in-create-react-app
create-a-build-script
setting-up-your-project-on-netlify
custom-domain-in-netlify
frontend-workflow
debugging-full-stack-serverless-apps
setup-error-reporting-in-react
report-api-errors-in-react
setup-an-error-boundary-in-react
setup-error-logging-in-serverless
logic-errors-in-lambda-functions
unexpected-errors-in-lambda-functions
errors-outside-lambda-functions
errors-in-api-gateway
wrapping-up
further-reading
translations
giving-back
changelog
staying-up-to-date
best-practices-for-building-serverless-apps
organizing-serverless-projects
cross-stack-references-in-serverless
dynamodb-as-a-serverless-service
s3-as-a-serverless-service
cognito-as-a-serverless-service
share-code-between-services
share-an-api-endpoint-between-services
deploy-a-serverless-app-with-dependencies
environments-in-serverless-apps
structure-environments-across-aws-accounts
manage-aws-accounts-using-aws-organizations
parameterize-serverless-resources-names
deploying-to-multiple-aws-accounts
deploy-the-resources-repo
deploy-the-api-services-repo
manage-environment-related-config
storing-secrets-in-serverless-apps
share-route-53-domains-across-aws-accounts
monitor-usage-for-environments
working-on-serverless-apps
invoke-lambda-functions-locally
invoke-api-gateway-endpoints-locally
creating-feature-environments
creating-pull-request-environments
promoting-to-production
rollback-changes
deploying-only-updated-services
tracing-serverless-apps-with-x-ray
wrapping-up-the-best-practices
api-gateway-and-lambda-logs
debugging-serverless-api-issues
serverless-environment-variables
stages-in-serverless-framework
backups-in-dynamodb
configure-multiple-aws-profiles
customize-the-serverless-iam-policy
mapping-cognito-identity-id-and-user-pool-id
connect-to-api-gateway-with-iam-auth
serverless-nodejs-starter
package-lambdas-with-serverless-bundle
understanding-react-hooks
code-splitting-in-create-react-app
environments-in-create-react-app
deploying-a-react-app-to-aws
create-an-s3-bucket
deploy-to-s3
create-a-cloudfront-distribution
setup-your-domain-with-cloudfront
setup-www-domain-redirect
setup-ssl
deploy-updates
manage-user-accounts-in-aws-amplify
handle-forgot-and-reset-password
allow-users-to-change-passwords
allow-users-to-change-their-email
facebook-login-with-cognito-using-aws-amplify"

set text item delimiters to "
"

set theChapters to text items of theChaptersStr

########
# Main #
########
downloadPdfs(theChapters)
mergePdfs(theChapters)

##############
# Merge PDFs #
##############
on mergePdfs(theChapters)
  set outputFile to "~/Downloads/ebook/ServerlessStack.pdf"

  set pdfFiles to "~/Downloads/ebook/Cover.pdf"
  repeat with theCurrentChapter in theChapters
    set pdfFiles to pdfFiles & " ~/Downloads/ebook/" & theCurrentChapter & ".pdf"
  end repeat

  do shell script "/System/Library/Automator/Combine\\ PDF\\ Pages.action/Contents/Resources/join.py " & "-o " & outputFile & " " & pdfFiles
end mergePdfs

#################
# Download PDFs #
#################
on downloadPdfs(theChapters)
  repeat with theCurrentChapter in theChapters
    if not(checkFileExist(theCurrentChapter)) then
      downloadPdf(theCurrentChapter)
    end if
  end repeat
end downloadPdfs

on checkFileExist(theChapterName)
  set basePath to POSIX path of (path to home folder) & "Downloads/ebook/"

  tell application "Finder"
    return exists basePath & theChapterName & ".pdf" as POSIX file
  end tell
end checkFileExist

on downloadPdf(theChapterName)
  tell application "System Events"

    tell process "Safari"
      set frontmost to true

      if ((theChapterName as string) is equal to "index") then
        set urlPath to theChapterName
      else
        set urlPath to "chapters/" & theChapterName
      end if
      open location "https://serverless-stack.com/" & urlPath & ".html"

      delay 1

      repeat until menu item "Export as PDF…" of menu "File" of menu bar 1 exists
        delay 0.2
      end repeat
      repeat
        if ((value of menu item "Export as PDF…" of menu "File" of menu bar 1 is enabled) = true)
          exit repeat
        end if
        delay 0.2
      end repeat
      click menu item "Export as PDF…" of menu "File" of menu bar 1

      tell window 1
        repeat until sheet 1 exists
        end repeat

        tell sheet 1
          keystroke theChapterName
          click pop up button "Where:"

          repeat until menu 1 of pop up button "Where:" exists
          end repeat
          click menu item "ebook" of menu 1 of pop up button "Where:"
          click button "Save"
        end tell

      end tell

      click menu item "Close Tab" of menu "File" of menu bar 1

    end tell

  end tell
end downloadPdf

############################
# How to generate the PDFs #
############################
# 1. Generate Cover.pdf with latest version date
#    a. Create "ebook" folder in ~/Downloads
#    b. update date in cover.html
#    c. open in safari file:///Users/frank/Sites/ServerlessStackCom/etc/cover.html
#    d. "Export to PDF…"
#    e. Place Cover.pdf in ~/ebook folder
# 2. Ensure "ebook" folder is an option when "Export to PDF…" in Safari
# 3. In terminal, run "osascript pdf.scpt"

set theChaptersStr to "who-is-this-guide-for
what-does-this-guide-cover
how-to-get-help
what-is-serverless
what-is-aws-lambda
why-create-serverless-apps
create-an-aws-account
create-an-iam-user
what-is-iam
what-is-an-arn
configure-the-aws-cli
create-a-dynamodb-table
create-an-s3-bucket-for-file-uploads
create-a-cognito-user-pool
create-a-cognito-test-user
setup-the-serverless-framework
add-support-for-es6-es7-javascript
initialize-the-backend-repo
add-a-create-note-api
add-a-get-note-api
add-a-list-all-the-notes-api
add-an-update-note-api
add-a-delete-note-api
working-with-3rd-party-apis
setup-a-stripe-account
add-a-billing-api
load-secrets-from-env
test-the-billing-api
unit-tests-in-serverless
handle-api-gateway-cors-errors
deploy-the-apis
create-a-cognito-identity-pool
cognito-user-pool-vs-identity-pool
test-the-apis
create-a-new-reactjs-app
initialize-the-frontend-repo
add-app-favicons
setup-custom-fonts
setup-bootstrap
handle-routes-with-react-router
create-containers
adding-links-in-the-navbar
handle-404s
configure-aws-amplify
create-a-login-page
login-with-aws-cognito
add-the-session-to-the-state
load-the-state-from-the-session
clear-the-session-on-logout
redirect-on-login-and-logout
give-feedback-while-logging-in
create-a-custom-react-hook-to-handle-form-fields
create-a-signup-page
create-the-signup-form
signup-with-aws-cognito
add-the-create-note-page
call-the-create-api
upload-a-file-to-s3
list-all-the-notes
call-the-list-api
display-a-note
render-the-note-form
save-changes-to-a-note
delete-a-note
create-a-settings-page
add-stripe-keys-to-config
create-a-billing-form
connect-the-billing-form
setup-secure-pages
create-a-route-that-redirects
use-the-redirect-routes
redirect-on-login
getting-production-ready
what-is-infrastructure-as-code
configure-dynamodb-in-serverless
configure-s3-in-serverless
configure-cognito-user-pool-in-serverless
configure-cognito-identity-pool-in-serverless
deploy-your-serverless-infrastructure
automating-serverless-deployments
setting-up-your-project-on-seed
configure-secrets-in-seed
deploying-through-seed
set-custom-domains-through-seed
test-the-configured-apis
automating-react-deployments
manage-environments-in-create-react-app
create-a-build-script
setting-up-your-project-on-netlify
custom-domain-in-netlify
frontend-workflow
debugging-full-stack-serverless-apps
setup-error-reporting-in-react
report-api-errors-in-react
setup-an-error-boundary-in-react
setup-error-logging-in-serverless
logic-errors-in-lambda-functions
unexpected-errors-in-lambda-functions
errors-outside-lambda-functions
errors-in-api-gateway
wrapping-up
further-reading
translations
giving-back
changelog
staying-up-to-date
best-practices-for-building-serverless-apps
organizing-serverless-projects
cross-stack-references-in-serverless
dynamodb-as-a-serverless-service
s3-as-a-serverless-service
cognito-as-a-serverless-service
share-code-between-services
share-an-api-endpoint-between-services
deploy-a-serverless-app-with-dependencies
environments-in-serverless-apps
structure-environments-across-aws-accounts
manage-aws-accounts-using-aws-organizations
parameterize-serverless-resources-names
deploying-to-multiple-aws-accounts
deploy-the-resources-repo
deploy-the-api-services-repo
manage-environment-related-config
storing-secrets-in-serverless-apps
share-route-53-domains-across-aws-accounts
monitor-usage-for-environments
working-on-serverless-apps
invoke-lambda-functions-locally
invoke-api-gateway-endpoints-locally
creating-feature-environments
creating-pull-request-environments
promoting-to-production
rollback-changes
deploying-only-updated-services
tracing-serverless-apps-with-x-ray
wrapping-up-the-best-practices
api-gateway-and-lambda-logs
debugging-serverless-api-issues
serverless-environment-variables
stages-in-serverless-framework
backups-in-dynamodb
configure-multiple-aws-profiles
customize-the-serverless-iam-policy
mapping-cognito-identity-id-and-user-pool-id
connect-to-api-gateway-with-iam-auth
serverless-nodejs-starter
package-lambdas-with-serverless-bundle
understanding-react-hooks
code-splitting-in-create-react-app
environments-in-create-react-app
deploying-a-react-app-to-aws
create-an-s3-bucket
deploy-to-s3
create-a-cloudfront-distribution
setup-your-domain-with-cloudfront
setup-www-domain-redirect
setup-ssl
deploy-updates
manage-user-accounts-in-aws-amplify
handle-forgot-and-reset-password
allow-users-to-change-passwords
allow-users-to-change-their-email
facebook-login-with-cognito-using-aws-amplify"

set text item delimiters to "
"

set theChapters to text items of theChaptersStr

########
# Main #
########
downloadPdfs(theChapters)
mergePdfs(theChapters)

##############
# Merge PDFs #
##############
on mergePdfs(theChapters)
  set outputFile to "~/Downloads/ebook/ServerlessStack.pdf"

  set pdfFiles to "~/Downloads/ebook/Cover.pdf"
  repeat with theCurrentChapter in theChapters
    set pdfFiles to pdfFiles & " ~/Downloads/ebook/" & theCurrentChapter & ".pdf"
  end repeat

  do shell script "/System/Library/Automator/Combine\\ PDF\\ Pages.action/Contents/Resources/join.py " & "-o " & outputFile & " " & pdfFiles
end mergePdfs

#################
# Download PDFs #
#################
on downloadPdfs(theChapters)
  repeat with theCurrentChapter in theChapters
    if not(checkFileExist(theCurrentChapter)) then
      downloadPdf(theCurrentChapter)
    end if
  end repeat
end downloadPdfs

on checkFileExist(theChapterName)
  set basePath to POSIX path of (path to home folder) & "Downloads/ebook/"

  tell application "Finder"
    return exists basePath & theChapterName & ".pdf" as POSIX file
  end tell
end checkFileExist

on downloadPdf(theChapterName)
  tell application "System Events"

    tell process "Safari"
      set frontmost to true

      if ((theChapterName as string) is equal to "index") then
        set urlPath to theChapterName
      else
        set urlPath to "chapters/" & theChapterName
      end if
      open location "https://serverless-stack.com/" & urlPath & ".html"

      delay 1

      repeat until menu item "Export as PDF…" of menu "File" of menu bar 1 exists
        delay 0.2
      end repeat
      repeat
        if ((value of menu item "Export as PDF…" of menu "File" of menu bar 1 is enabled) = true)
          exit repeat
        end if
        delay 0.2
      end repeat
      click menu item "Export as PDF…" of menu "File" of menu bar 1

      tell window 1
        repeat until sheet 1 exists
        end repeat

        tell sheet 1
          keystroke theChapterName
          click pop up button "Where:"

          repeat until menu 1 of pop up button "Where:" exists
          end repeat
          click menu item "ebook" of menu 1 of pop up button "Where:"
          click button "Save"
        end tell

      end tell

      delay 2

      click menu item "Close Tab" of menu "File" of menu bar 1

    end tell

  end tell
end downloadPdf

Fix pdf script

Fix pdf script


-- thumbscrew.scpt
-- usage: thumbscript.scpt <path_to_git_root_dir> <path_to_keynotePresentation>
--
-- Will create scaled thumbnails of length `thumbSize` in the directory
-- <path_to_presentation>
property thumbSize : 480

on getImages(f)
  tell application "Finder" to return (files of folder f) as alias list
end getImages

on run argv
  set savePath to item 1 of argv
  set keynoteName to item 2 of argv
  set thumbnailDir to keynoteName
  if thumbnailDir ends with ".key" then set thumbnailDir to text 1 thru -5 of thumbnailDir

  set keynoteFile to (POSIX file keynoteName) as alias
  set keynoteFullName to savePath & "/" & keynoteName
  set documentPath to posix file (POSIX path of (do shell script "dirname " & quoted form of keynoteFullName)) as alias

  tell application "Finder"
    if not (exists folder thumbnailDir of folder documentPath)
      make new folder at folder documentPath with properties {name:thumbnailDir}
    end if
    set the targetFolder to folder thumbnailDir of folder documentPath
    set the targetFolderHFSPath to targetFolder as string
  end tell

  tell application "Keynote" to run
  tell application "Keynote"
    open keynoteFile

    if playing is true then stop the front document

    export front document as slide images to file targetFolderHFSPath with properties {image format: JPEG}
    set jpegs to my getImages(targetFolderHFSPath)
    repeat with thisJPEG in jpegs
      try
        tell application "Image Events"
          launch
          set this_image to open thisJPEG
          scale this_image to size thumbSize
          save this_image with icon
          close this_image
        end tell
        on error error_message
          display dialog error_message
      end try
    end repeat

--    close front document without saving
  end tell
end run

-- thumbscrew.scpt
-- usage: thumbscript.scpt <path_to_git_root_dir> <path_to_keynotePresentation>
--
-- Will create scaled thumbnails of length `thumbSize` in the directory
-- <path_to_presentation>
property thumbSize : 480

on getImages(f)
  tell application "Finder" to return (files of folder f) as alias list
end getImages

on run argv
  set savePath to item 1 of argv
  set keynoteName to item 2 of argv
  set thumbnailDir to keynoteName
  if thumbnailDir ends with ".key" then set thumbnailDir to text 1 thru -5 of thumbnailDir

  set keynoteFile to (POSIX file keynoteName) as alias
  set keynoteFullName to savePath & "/" & keynoteName
  set savePath to posix file savePath

  tell application "Finder"
    if not (exists folder thumbnailDir of folder savePath)
      make new folder at folder savePath with properties {name:thumbnailDir}
    end if
    set the targetFolder to folder thumbnailDir of folder savePath
    set the targetFolderHFSPath to targetFolder as string
  end tell

  tell application "Keynote" to run
  tell application "Keynote"
    open keynoteFile

    if playing is true then stop the front document

    export front document as slide images to file targetFolderHFSPath with properties {image format: JPEG}
    set jpegs to my getImages(targetFolderHFSPath)
    repeat with thisJPEG in jpegs
      try
        tell application "Image Events"
          launch
          set this_image to open thisJPEG
          scale this_image to size thumbSize
          save this_image with icon
          close this_image
        end tell
        on error error_message
          display dialog error_message
      end try
    end repeat

    close front document without saving
  end tell
end run

make it work again

make it work again


############################
# How to generate the PDFs #
############################
# 1. Generate Cover.pdf with latest version date
#    a. Create "ebook" folder in ~/Downloads
#    b. update date in cover.html
#    c. open in safari file:///Users/frank/Sites/ServerlessStackCom/etc/cover.html
#    d. "Export to PDF…"
#    e. Place Cover.pdf in ~/ebook folder
# 2. Ensure "ebook" folder is an option when "Export to PDF…" in Safari
# 3. In terminal, run "osascript pdf.scpt"

set theChaptersStr to "who-is-this-guide-for
what-does-this-guide-cover
how-to-get-help
what-is-serverless
what-is-aws-lambda
why-create-serverless-apps
create-an-aws-account
create-an-iam-user
what-is-iam
what-is-an-arn
configure-the-aws-cli
create-a-dynamodb-table
create-an-s3-bucket-for-file-uploads
create-a-cognito-user-pool
create-a-cognito-test-user
setup-the-serverless-framework
add-support-for-es6-es7-javascript
initialize-the-backend-repo
add-a-create-note-api
add-a-get-note-api
add-a-list-all-the-notes-api
add-an-update-note-api
add-a-delete-note-api
working-with-3rd-party-apis
setup-a-stripe-account
add-a-billing-api
load-secrets-from-env
test-the-billing-api
unit-tests-in-serverless
handle-api-gateway-cors-errors
deploy-the-apis
create-a-cognito-identity-pool
cognito-user-pool-vs-identity-pool
test-the-apis
create-a-new-reactjs-app
initialize-the-frontend-repo
add-app-favicons
setup-custom-fonts
setup-bootstrap
handle-routes-with-react-router
create-containers
adding-links-in-the-navbar
handle-404s
configure-aws-amplify
create-a-login-page
login-with-aws-cognito
add-the-session-to-the-state
load-the-state-from-the-session
clear-the-session-on-logout
redirect-on-login-and-logout
give-feedback-while-logging-in
create-a-custom-react-hook-to-handle-form-fields
create-a-signup-page
create-the-signup-form
signup-with-aws-cognito
add-the-create-note-page
call-the-create-api
upload-a-file-to-s3
list-all-the-notes
call-the-list-api
display-a-note
render-the-note-form
save-changes-to-a-note
delete-a-note
create-a-settings-page
add-stripe-keys-to-config
create-a-billing-form
connect-the-billing-form
setup-secure-pages
create-a-route-that-redirects
use-the-redirect-routes
redirect-on-login
getting-production-ready
what-is-infrastructure-as-code
configure-dynamodb-in-serverless
configure-s3-in-serverless
configure-cognito-user-pool-in-serverless
configure-cognito-identity-pool-in-serverless
deploy-your-serverless-infrastructure
automating-serverless-deployments
setting-up-your-project-on-seed
configure-secrets-in-seed
deploying-through-seed
set-custom-domains-through-seed
test-the-configured-apis
automating-react-deployments
manage-environments-in-create-react-app
create-a-build-script
setting-up-your-project-on-netlify
custom-domain-in-netlify
frontend-workflow
debugging-full-stack-serverless-apps
setup-error-reporting-in-react
report-api-errors-in-react
setup-an-error-boundary-in-react
setup-error-logging-in-serverless
logic-errors-in-lambda-functions
unexpected-errors-in-lambda-functions
errors-outside-lambda-functions
errors-in-api-gateway
wrapping-up
further-reading
translations
giving-back
changelog
staying-up-to-date
best-practices-for-building-serverless-apps
organizing-serverless-projects
cross-stack-references-in-serverless
dynamodb-as-a-serverless-service
s3-as-a-serverless-service
cognito-as-a-serverless-service
share-code-between-services
share-an-api-endpoint-between-services
deploy-a-serverless-app-with-dependencies
environments-in-serverless-apps
structure-environments-across-aws-accounts
manage-aws-accounts-using-aws-organizations
parameterize-serverless-resources-names
deploying-to-multiple-aws-accounts
deploy-the-resources-repo
deploy-the-api-services-repo
manage-environment-related-config
storing-secrets-in-serverless-apps
share-route-53-domains-across-aws-accounts
monitor-usage-for-environments
working-on-serverless-apps
invoke-lambda-functions-locally
invoke-api-gateway-endpoints-locally
creating-feature-environments
creating-pull-request-environments
promoting-to-production
rollback-changes
deploying-only-updated-services
tracing-serverless-apps-with-x-ray
wrapping-up-the-best-practices
api-gateway-and-lambda-logs
debugging-serverless-api-issues
serverless-environment-variables
stages-in-serverless-framework
backups-in-dynamodb
configure-multiple-aws-profiles
customize-the-serverless-iam-policy
mapping-cognito-identity-id-and-user-pool-id
connect-to-api-gateway-with-iam-auth
serverless-nodejs-starter
package-lambdas-with-serverless-bundle
understanding-react-hooks
code-splitting-in-create-react-app
environments-in-create-react-app
deploying-a-react-app-to-aws
create-an-s3-bucket
deploy-to-s3
create-a-cloudfront-distribution
setup-your-domain-with-cloudfront
setup-www-domain-redirect
setup-ssl
deploy-updates
manage-user-accounts-in-aws-amplify
handle-forgot-and-reset-password
allow-users-to-change-passwords
allow-users-to-change-their-email
facebook-login-with-cognito-using-aws-amplify"

set text item delimiters to "
"

set theChapters to text items of theChaptersStr

########
# Main #
########
downloadPdfs(theChapters)
mergePdfs(theChapters)

##############
# Merge PDFs #
##############
on mergePdfs(theChapters)
  set outputFile to "~/Downloads/ebook/ServerlessStack.pdf"

  set pdfFiles to "~/Downloads/ebook/Cover.pdf"
  repeat with theCurrentChapter in theChapters
    set pdfFiles to pdfFiles & " ~/Downloads/ebook/" & theCurrentChapter & ".pdf"
  end repeat

  do shell script "/System/Library/Automator/Combine\\ PDF\\ Pages.action/Contents/Resources/join.py " & "-o " & outputFile & " " & pdfFiles
end mergePdfs

#################
# Download PDFs #
#################
on downloadPdfs(theChapters)
  repeat with theCurrentChapter in theChapters
    if not(checkFileExist(theCurrentChapter)) then
      downloadPdf(theCurrentChapter)
    end if
  end repeat
end downloadPdfs

on checkFileExist(theChapterName)
  set basePath to POSIX path of (path to home folder) & "Downloads/ebook/"

  tell application "Finder"
    return exists basePath & theChapterName & ".pdf" as POSIX file
  end tell
end checkFileExist

on downloadPdf(theChapterName)
  tell application "System Events"

    tell process "Safari"
      set frontmost to true

      if ((theChapterName as string) is equal to "index") then
        set urlPath to theChapterName
      else
        set urlPath to "chapters/" & theChapterName
      end if
      open location "https://serverless-stack.com/" & urlPath & ".html"

      delay 1

      repeat until menu item "Export as PDF…" of menu "File" of menu bar 1 exists
        delay 0.2
      end repeat
      repeat until menu item "Export as PDF…" of menu "File" of menu bar 1 is enabled
        delay 0.2
      end repeat
      click menu item "Export as PDF…" of menu "File" of menu bar 1

      tell window 1
        repeat until sheet 1 exists
        end repeat

        tell sheet 1
          keystroke theChapterName
          click pop up button "Where:"

          repeat until menu 1 of pop up button "Where:" exists
          end repeat
          click menu item "ebook" of menu 1 of pop up button "Where:"
          click button "Save"
        end tell

      end tell

      click menu item "Close Tab" of menu "File" of menu bar 1

    end tell

  end tell
end downloadPdf

############################
# How to generate the PDFs #
############################
# 1. Generate Cover.pdf with latest version date
#    a. Create "ebook" folder in ~/Downloads
#    b. update date in cover.html
#    c. open in safari file:///Users/frank/Sites/ServerlessStackCom/etc/cover.html
#    d. "Export to PDF…"
#    e. Place Cover.pdf in ~/ebook folder
# 2. Ensure "ebook" folder is an option when "Export to PDF…" in Safari
# 3. In terminal, run "osascript pdf.scpt"

set theChaptersStr to "who-is-this-guide-for
what-does-this-guide-cover
how-to-get-help
what-is-serverless
what-is-aws-lambda
why-create-serverless-apps
create-an-aws-account
create-an-iam-user
what-is-iam
what-is-an-arn
configure-the-aws-cli
create-a-dynamodb-table
create-an-s3-bucket-for-file-uploads
create-a-cognito-user-pool
create-a-cognito-test-user
setup-the-serverless-framework
add-support-for-es6-es7-javascript
initialize-the-backend-repo
add-a-create-note-api
add-a-get-note-api
add-a-list-all-the-notes-api
add-an-update-note-api
add-a-delete-note-api
working-with-3rd-party-apis
setup-a-stripe-account
add-a-billing-api
load-secrets-from-env
test-the-billing-api
unit-tests-in-serverless
handle-api-gateway-cors-errors
deploy-the-apis
create-a-cognito-identity-pool
cognito-user-pool-vs-identity-pool
test-the-apis
create-a-new-reactjs-app
initialize-the-frontend-repo
add-app-favicons
setup-custom-fonts
setup-bootstrap
handle-routes-with-react-router
create-containers
adding-links-in-the-navbar
handle-404s
configure-aws-amplify
create-a-login-page
login-with-aws-cognito
add-the-session-to-the-state
load-the-state-from-the-session
clear-the-session-on-logout
redirect-on-login-and-logout
give-feedback-while-logging-in
create-a-custom-react-hook-to-handle-form-fields
create-a-signup-page
create-the-signup-form
signup-with-aws-cognito
add-the-create-note-page
call-the-create-api
upload-a-file-to-s3
list-all-the-notes
call-the-list-api
display-a-note
render-the-note-form
save-changes-to-a-note
delete-a-note
create-a-settings-page
add-stripe-keys-to-config
create-a-billing-form
connect-the-billing-form
setup-secure-pages
create-a-route-that-redirects
use-the-redirect-routes
redirect-on-login
getting-production-ready
what-is-infrastructure-as-code
configure-dynamodb-in-serverless
configure-s3-in-serverless
configure-cognito-user-pool-in-serverless
configure-cognito-identity-pool-in-serverless
deploy-your-serverless-infrastructure
automating-serverless-deployments
setting-up-your-project-on-seed
configure-secrets-in-seed
deploying-through-seed
set-custom-domains-through-seed
test-the-configured-apis
automating-react-deployments
manage-environments-in-create-react-app
create-a-build-script
setting-up-your-project-on-netlify
custom-domain-in-netlify
frontend-workflow
debugging-full-stack-serverless-apps
setup-error-reporting-in-react
report-api-errors-in-react
setup-an-error-boundary-in-react
setup-error-logging-in-serverless
logic-errors-in-lambda-functions
unexpected-errors-in-lambda-functions
errors-outside-lambda-functions
errors-in-api-gateway
wrapping-up
further-reading
translations
giving-back
changelog
staying-up-to-date
best-practices-for-building-serverless-apps
organizing-serverless-projects
cross-stack-references-in-serverless
dynamodb-as-a-serverless-service
s3-as-a-serverless-service
cognito-as-a-serverless-service
share-code-between-services
share-an-api-endpoint-between-services
deploy-a-serverless-app-with-dependencies
environments-in-serverless-apps
structure-environments-across-aws-accounts
manage-aws-accounts-using-aws-organizations
parameterize-serverless-resources-names
deploying-to-multiple-aws-accounts
deploy-the-resources-repo
deploy-the-api-services-repo
manage-environment-related-config
storing-secrets-in-serverless-apps
share-route-53-domains-across-aws-accounts
monitor-usage-for-environments
working-on-serverless-apps
invoke-lambda-functions-locally
invoke-api-gateway-endpoints-locally
creating-feature-environments
creating-pull-request-environments
promoting-to-production
rollback-changes
deploying-only-updated-services
tracing-serverless-apps-with-x-ray
wrapping-up-the-best-practices
api-gateway-and-lambda-logs
debugging-serverless-api-issues
serverless-environment-variables
stages-in-serverless-framework
backups-in-dynamodb
configure-multiple-aws-profiles
customize-the-serverless-iam-policy
mapping-cognito-identity-id-and-user-pool-id
connect-to-api-gateway-with-iam-auth
serverless-nodejs-starter
package-lambdas-with-serverless-bundle
understanding-react-hooks
code-splitting-in-create-react-app
environments-in-create-react-app
deploying-a-react-app-to-aws
create-an-s3-bucket
deploy-to-s3
create-a-cloudfront-distribution
setup-your-domain-with-cloudfront
setup-www-domain-redirect
setup-ssl
deploy-updates
manage-user-accounts-in-aws-amplify
handle-forgot-and-reset-password
allow-users-to-change-passwords
allow-users-to-change-their-email
facebook-login-with-cognito-using-aws-amplify"

set text item delimiters to "
"

set theChapters to text items of theChaptersStr

########
# Main #
########
downloadPdfs(theChapters)
mergePdfs(theChapters)

##############
# Merge PDFs #
##############
on mergePdfs(theChapters)
  set outputFile to "~/Downloads/ebook/ServerlessStack.pdf"

  set pdfFiles to "~/Downloads/ebook/Cover.pdf"
  repeat with theCurrentChapter in theChapters
    set pdfFiles to pdfFiles & " ~/Downloads/ebook/" & theCurrentChapter & ".pdf"
  end repeat

  do shell script "/System/Library/Automator/Combine\\ PDF\\ Pages.action/Contents/Resources/join.py " & "-o " & outputFile & " " & pdfFiles
end mergePdfs

#################
# Download PDFs #
#################
on downloadPdfs(theChapters)
  repeat with theCurrentChapter in theChapters
    if not(checkFileExist(theCurrentChapter)) then
      downloadPdf(theCurrentChapter)
    end if
  end repeat
end downloadPdfs

on checkFileExist(theChapterName)
  set basePath to POSIX path of (path to home folder) & "Downloads/ebook/"

  tell application "Finder"
    return exists basePath & theChapterName & ".pdf" as POSIX file
  end tell
end checkFileExist

on downloadPdf(theChapterName)
  tell application "System Events"

    tell process "Safari"
      set frontmost to true

      if ((theChapterName as string) is equal to "index") then
        set urlPath to theChapterName
      else
        set urlPath to "chapters/" & theChapterName
      end if
      open location "https://serverless-stack.com/" & urlPath & ".html"

      delay 1

      repeat until menu item "Export as PDF…" of menu "File" of menu bar 1 exists
        delay 0.2
      end repeat
      repeat
        if ((value of menu item "Export as PDF…" of menu "File" of menu bar 1 is enabled) = true)
          exit repeat
        end if
        delay 0.2
      end repeat
      click menu item "Export as PDF…" of menu "File" of menu bar 1

      tell window 1
        repeat until sheet 1 exists
        end repeat

        tell sheet 1
          keystroke theChapterName
          click pop up button "Where:"

          repeat until menu 1 of pop up button "Where:" exists
          end repeat
          click menu item "ebook" of menu 1 of pop up button "Where:"
          click button "Save"
        end tell

      end tell

      click menu item "Close Tab" of menu "File" of menu bar 1

    end tell

  end tell
end downloadPdf

Fix pdf script

Fix pdf script


tell application "Finder"
	tell disk "Growl"
		open
		tell container window
			set current view to icon view
			set toolbar visible to false
			set statusbar visible to false
			--set the bounds to {30, 50, 579, 600}
		end tell
		close
		set opts to the icon view options of container window
		tell opts
			set icon size to 64
			set arrangement to not arranged
		end tell
		set background picture of opts to file ".background:growlDMGBackground.png"
		set position of item "Growl.prefPane" to {147, 75}
		set position of item "Extras" to {80, 315}
		--set position of item "Scripts" to {36, 153}
		set position of item "Growl Documentation.webloc" to {100, 215}
		set position of item "Growl version history.webloc" to {275, 215}
		set position of item "Get more styles.webloc" to {415, 215}
		set position of item "Uninstall Growl.app" to {415, 315}
		update without registering applications
		set the_window_id to id of container window
		update without registering applications
	end tell
	set bounds of window id the_window_id to {30, 50, 579, 900}
	--give the finder some time to write the .DS_Store file
	delay 5
end tell

tell application "Finder"
	tell disk "Growl"
		open
		tell container window
			set current view to icon view
			set toolbar visible to false
			set statusbar visible to false
			--set the bounds to {30, 50, 579, 600}
		end tell
		close
		set opts to the icon view options of container window
		tell opts
			set icon size to 64
			set arrangement to not arranged
		end tell
		set background picture of opts to file ".background:growlDMGBackground.png"
		set position of item "Growl.prefPane" to {147, 75}
		set position of item "Extras" to {80, 315}
		--set position of item "Scripts" to {36, 153}
		set position of item "Growl Documentation.webloc" to {100, 215}
		set position of item "Growl version history.webloc" to {275, 215}
		set position of item "Get more styles.webloc" to {415, 215}
		set position of item "Uninstall Growl.app" to {415, 315}
		update without registering applications
		tell container window
			open
			set the_window_id to id
		end tell
		update without registering applications
	end tell
	set bounds of window id the_window_id to {30, 50, 579, 462}
	--give the finder some time to write the .DS_Store file
	delay 5
end tell

Save before committing!

Save before committing!


-- app to be excepted
set expApp to {"thunderbird-bin", "XRG", "Skype"}

-- app to be half size, in left monitor (0.7 times full)
set halfSizeApp_L to {}

-- app to be half size, in right monitor
set halfSizeApp_R to {"AdobeReader"}

-- app only to be moved, in left monitor
set noResizeApp_L to {}

-- app only to be moved, in right monitor
set noResizeApp_R to {"Finder", "Skype", "Microsoft Word", "Microsoft Excel", "Microsoft PowerPoint"}

-- app to be moved left
set app_L to {"firefox", "Evernote", "thunderbird", "thunderbird-bin", "Mail"}

-- app to be moved right
set app_R to {"iTerm"}

-- get screen size
tell application "Finder"
	set scriptPath to (path to me)'s folder as text
end tell
set windowSizeScpt to scriptPath & "windowSize.scpt"
set windowSize to load script file windowSizeScpt

-- main screen
set svs to windowSize's getVisibleFrame(100, 100)
set dPosX to item 1 of svs
set dPosY to item 2 of svs
set dWidth to item 3 of svs
set dHeight to item 4 of svs

-- try to get left screen
set dPosX_L to dPosX
set dPosY_L to dPosY
try
	set svsL to windowSize's getVisibleFrame(-100, 100)
	set dPosX_L to item 1 of svsL
	set dPosY_L to item 2 of svsL
end try

-- try to get right screen
set dPosX_R to dPosX
set dPosY_R to dPosY
try
	set svsR to windowSize's getVisibleFrame(dPosX + dWidth + 100, 100)
	set dPosX_R to item 1 of svsR
	set dPosY_R to item 2 of svsR
end try

-- get application name
tell application "System Events"
	set appList to (get name of every application process whose visible is true)
end tell

-- repeat for all app
repeat with appName in appList
	if appName is not in expApp then
		tell application "System Events"
			try
				tell process appName
					set nW to number of windows
					repeat with i from 1 to nW
						log appName & i
						if appName is in halfSizeApp_L then
							windowSize's windowSize({appName:appName, windowNumber:i, monPosX:dPosX_L, monPosY:dPosY_L, xsize:0.7, ysize:0.7})
						else if appName is in halfSizeApp_R then
							windowSize's windowSize({appName:appName, windowNumber:i, monPosX:dPosX_R, monPosY:dPosY_R, xsize:0.7, ysize:0.7})
						else if appName is in noResizeApp_L then
							windowSize's windowSize({appName:appName, windowNumber:i, monPosX:dPosX_L, monPosY:dPosY_L, resize:0})
						else if appName is in noResizeApp_R then
							windowSize's windowSize({appName:appName, windowNumber:i, monPosX:dPosX_R, monPosY:dPosY_R, resize:0})
						else if appName is in app_L then
							log "app_L" & appName
							windowSize's windowSize({appName:appName, windowNumber:i, monPosX:dPosX_L, monPosY:dPosY_L})
						else if appName is in app_R then
							log "app_R" & appName
							windowSize's windowSize({appName:appName, windowNumber:i, monPosX:dPosX_R, monPosY:dPosY_R})
						end if
					end repeat
				end tell
			end try
		end tell
	end if
end repeat

-- app to be excepted
set expApp to {"thunderbird-bin", "XRG", "Skype"}

-- app to be half size, in left monitor (0.7 times full)
set halfSizeApp_L to {}

-- app to be half size, in right monitor
set halfSizeApp_R to {"AdobeReader"}

-- app only to be moved, in left monitor
set noResizeApp_L to {}

-- app only to be moved, in right monitor
set noResizeApp_R to {"Finder", "Skype", "Microsoft Word", "Microsoft Excel", "Microsoft PowerPoint"}

-- app to be moved left
set app_L to {"firefox", "Evernote", "thunderbird", "thunderbird-bin", "Mail"}

-- app to be moved right
set app_R to {"iTerm"}

-- get screen size
tell application "Finder"
	set scriptPath to (path to me)'s folder as text
end tell
set windowSizeScpt to scriptPath & "windowSize.scpt"
set windowSize to load script file windowSizeScpt

-- main screen
set svs to windowSize's getVisibleFrame(100, 100)
set dPosX to item 1 of svs
set dPosY to item 2 of svs
set dWidth to item 3 of svs
set dHeight to item 4 of svs

-- try to get left screen
set dPosX_L to dPosX
set dPosY_L to dPosY
try
	set svsL to windowSize's getVisibleFrame(-100, 100)
	set dPosX_L to item 1 of svsL
	set dPosY_L to item 2 of svsL
end try

-- try to get right screen
set dPosX_R to dPosX
set dPosY_R to dPosY
try
	set svsR to windowSize's getVisibleFrame(dPosX + dWidth + 100, 100)
	set dPosX_R to item 1 of svsR
	set dPosY_R to item 2 of svsR
end try

-- get application name
tell application "System Events"
	set appList to (get name of every application process whose visible is true)
end tell

-- repeat for all app
repeat with appName in appList
	if appName is not in expApp then
		tell application "System Events"
			try
				tell process appName
					set nW to number of windows
					display dialog appName & " " & nW

					repeat with i from 1 to nW
						log appName & i
						if appName is in halfSizeApp_L then
							windowSize's windowSize({appName:appName, windowNumber:i, monPosX:dPosX_L, monPosY:dPosY_L, xsize:0.7, ysize:0.7})
						else if appName is in halfSizeApp_R then
							windowSize's windowSize({appName:appName, windowNumber:i, monPosX:dPosX_R, monPosY:dPosY_R, xsize:0.7, ysize:0.7})
						else if appName is in noResizeApp_L then
							windowSize's windowSize({appName:appName, windowNumber:i, monPosX:dPosX_L, monPosY:dPosY_L, resize:0})
						else if appName is in noResizeApp_R then
							windowSize's windowSize({appName:appName, windowNumber:i, monPosX:dPosX_R, monPosY:dPosY_R, resize:0})
						else if appName is in app_L then
							log "app_L" & appName
							windowSize's windowSize({appName:appName, windowNumber:i, monPosX:dPosX_L, monPosY:dPosY_L})
						else if appName is in app_R then
							log "app_R" & appName
							windowSize's windowSize({appName:appName, windowNumber:i, monPosX:dPosX_R, monPosY:dPosY_R})
						end if
					end repeat
				end tell
			end try
		end tell
	end if
end repeat

update from darwin11

update from darwin11


#!/usr/bin/env osascript

-- Fist: Click Install Button
delay 2.0

set timeoutSeconds to 2.0
set uiScript to "click UI Element 4 of window 1 of application process \"Install Command Line Developer Tools\""
my doWithTimeout(uiScript, timeoutSeconds)

on doWithTimeout(uiScript, timeoutSeconds)
  set endDate to (current date) + timeoutSeconds
  repeat
    try
      run script "tell application \"System Events\"
" & uiScript & "
end tell"
      exit repeat
    on error errorMessage
      if ((current date) > endDate) then
        error "Can not " & uiScript
      end if
    end try
  end repeat
end doWithTimeout

#!/usr/bin/env osascript

-- Fist: Click Install Button
set timeoutSeconds to 2.0
set uiScript to "click UI Element 4 of window 1 of application process \"Install Command Line Developer Tools\""
my doWithTimeout(uiScript, timeoutSeconds)

on doWithTimeout(uiScript, timeoutSeconds)
  set endDate to (current date) + timeoutSeconds
  repeat
    try
      run script "tell application \"System Events\"
" & uiScript & "
end tell"
      exit repeat
    on error errorMessage
      if ((current date) > endDate) then
        error "Can not " & uiScript
      end if
    end try
  end repeat
end doWithTimeout

Remove delay

Remove delay


-- fmGUI_Popup_SelectByCommand({objRef:"", objValue:"", calcValue:null, selectCommand:"", clickIfAlreadySet:""})
-- Daniel A. Shockley, NYHTC
-- Selects a choice from a popup menu

(*
REQUIRES:
	clickObjectByCoords
	fmGUI_SpecifyCalcWindowSet

HISTORY:
	2020-05-21 ( dshockley ): Try a 2nd time to click-and-wait for the menu to appear.
	1.4.1 - 2018-04-30 ( eshagdar ): tell FM to click on the value since it might not be visible ( and unclickable by CLI ).
	1.4 - 2017-09-22 ( eshagdar ): set calc using handler.
	1.3 - 2017-09-06 ( eshagdar ): added calcValue param that sets a calc in the 'Specify Calculation' that comes up.
	1.2 - 2017-09-05 ( eshagdar ): clicking done by handler
	1.1 - 2017-06-29 ( eshagdar ): prefs must be a record. incoming param may be a string, so ensure that it's an object reference.
	1.0 - created
*)

on run
	tell application "System Events"
		tell application process "FileMaker Pro Advanced"
			set frontmost to true
			delay 1
			--set popUpButtonRef to pop up button "Available menu commands:" of window 1
			set popUpButtonRef to pop up button "View" of window 1
		end tell
	end tell

	fmGUI_Popup_SelectByCommand({objRef:popUpButtonRef, objValue:"limited...", calcValue:"If ( True; True; GetAsNumber ( \"1\" ) )", clickIfAlreadySet:true})

end run

--------------------
-- START OF CODE
--------------------

on fmGUI_Popup_SelectByCommand(prefs)
	-- version 2020-05-21-1231

	set defaultPrefs to {objRef:null, objValue:null, calcValue:null, selectCommand:"is", clickIfAlreadySet:false}
	set prefs to prefs & defaultPrefs

	set objRef to ensureObjectRef(objRef of prefs)
	set selectCommand to selectCommand of prefs
	set objValue to objValue of prefs
	set clickIfAlreadySet to clickIfAlreadySet of prefs -- re-select even if popup is the requested value.

	try
		tell application "System Events"
			if not (exists objRef) then error "The specified objRef does not exist." number 1024

			-- the objRef DOES exist
			set mustPick to false
			if not (exists value of objRef) then
				-- first check if the value of the objRef exists - if it doesn't, then we can't test it directly
				set mustPick to true

			else -- we can see the value without 'picking' the menu, so test it:
				-- note that our selection might be one of several 'matching' commands:
				if clickIfAlreadySet then
					-- RE-SELECT even if popup already is the requested value.
					set mustPick to true

				else if selectCommand is equal to "is" then
					if value of objRef is not objValue then
						set mustPick to true
					end if

				else if selectCommand is equal to "contains" then
					if value of objRef does not contain objValue then
						set mustPick to true
					end if

				else if selectCommand is equal to "startsWith" then
					if value of objRef does not start with objValue then
						set mustPick to true
					end if

				else if selectCommand is equal to "beginsWith" then
					if value of objRef does not start with objValue then
						set mustPick to true
					end if

				else if selectCommand is equal to "endsWith" then
					if value of objRef does not end with objValue then
						set mustPick to true
					end if

				end if
			end if
		end tell

		if mustPick then
			if objValue is not null then
				-- click pop up button so the menu becomes available
				delay 0.3 -- short delay to make sure click can happen:
				clickObjectByCoords(objRef)

				-- wait to see if menu becomes available
				repeat 100 times
					try
						tell application "System Events"
							tell application process "FileMaker Pro Advanced"
								if exists (menu 1 of objRef) then exit repeat
							end tell
						end tell
					on error
						delay 0.5
					end try
				end repeat

				if not (exists (menu 1 of objRef)) then
					-- SECOND attempt to click-then-wait for menu to be available, but give up sooner:

					-- click pop up button so the menu becomes available
					clickObjectByCoords(objRef)

					--wait until menu is available
					repeat 20 times
						try
							tell application "System Events"
								tell application process "FileMaker Pro Advanced"
									if exists (menu 1 of objRef) then exit repeat
								end tell
							end tell
						on error
							delay 0.5
						end try
					end repeat
				end if

				-- now pick an item from the pop up
				tell application "System Events"
					objRef
					if selectCommand is equal to "is" then
						set objValue to first menu item of menu 1 of objRef whose name is objValue
					else if selectCommand is equal to "contains" then
						set objValue to first menu item of menu 1 of objRef whose name contains objValue
					else if selectCommand is equal to "beginsWith" then
						set objValue to first menu item of menu 1 of objRef whose name starts with objValue
					else if selectCommand is equal to "endsWith" then
						set objValue to first menu item of menu 1 of objRef whose name ends with objValue
					else
						error "unable to pick objValue because select command is failed" number -1024
					end if

					tell process "FileMaker Pro Advanced"
						click objValue
					end tell
				end tell

				-- must tell FM to click since the value might now be available ( need to scroll )
				--clickObjectByCoords(objValue)
			end if

			-- set calc if there is one
			if calcValue of prefs is not null then fmGUI_SpecifyCalcWindowSet({calcValue:calcValue of prefs})
		end if

		return true
	on error errMsg number errNum
		error "unable to fmGUI_Popup_SelectByCommand ( value _" & selectCommand & "_ '" & objValue & "' in popup ) - " & errMsg number errNum
	end try
end fmGUI_Popup_SelectByCommand

--------------------
-- END OF CODE
--------------------

on clickObjectByCoords(objRef)
	tell application "htcLib" to clickObjectByCoords(my coerceToString(objRef))
end clickObjectByCoords

on fmGUI_SpecifyCalcWindowSet(prefs)
	tell application "htcLib" to fmGUI_SpecifyCalcWindowSet(prefs)
end fmGUI_SpecifyCalcWindowSet

on coerceToString(incomingObject)
	-- 2017-07-12 ( eshagdar ): bootstrap code to bring a coerceToString into this file for the sample to run ( instead of having a copy of the handler locally ).

	tell application "Finder" to set coercePath to (container of (container of (path to me)) as text) & "text parsing:coerceToString.applescript"
	set codeCoerce to read file coercePath as text
	tell application "htcLib" to set codeCoerce to "script codeCoerce " & return & getTextBetween({sourceText:codeCoerce, beforeText:"-- START OF CODE", afterText:"-- END OF CODE"}) & return & "end script" & return & "return codeCoerce"
	set codeCoerce to run script codeCoerce
	tell codeCoerce to coerceToString(incomingObject)
end coerceToString

on ensureObjectRef(someObjectRef)
	-- 2017-07-12 ( eshagdar ): bootstrap code to bring a ensureObjectRef into this file for the sample to run ( instead of having a copy of the handler locally ).

	tell application "Finder" to set ensureObjPath to (container of (container of (path to me)) as text) & "text parsing:ensureObjectRef.applescript"
	set codeEnsureObj to read file ensureObjPath as text
	tell application "htcLib" to set codeEnsureObj to "script codeEnsureObj " & return & getTextBetween({sourceText:codeEnsureObj, beforeText:"-- START OF CODE", afterText:"-- END OF CODE"}) & return & "end script" & return & "return codeEnsureObj"
	set codeEnsureObj to run script codeEnsureObj
	tell codeEnsureObj to ensureObjectRef(someObjectRef)
end ensureObjectRef

-- fmGUI_Popup_SelectByCommand({objRef:"", objValue:"", calcValue:null, selectCommand:"", clickIfAlreadySet:""})
-- Daniel A. Shockley, NYHTC
-- Selects a choice from a popup menu

(*
REQUIRES:
	clickObjectByCoords
	fmGUI_SpecifyCalcWindowSet

HISTORY:
	2020-05-21 ( dshockley ): Try a 2nd time to click-and-wait for the menu to appear. And, don't try a 2nd "exists" command, since that seems to fail. Instead, save the result of that in a variable "isMenuOpen".
	1.4.1 - 2018-04-30 ( eshagdar ): tell FM to click on the value since it might not be visible ( and unclickable by CLI ).
	1.4 - 2017-09-22 ( eshagdar ): set calc using handler.
	1.3 - 2017-09-06 ( eshagdar ): added calcValue param that sets a calc in the 'Specify Calculation' that comes up.
	1.2 - 2017-09-05 ( eshagdar ): clicking done by handler
	1.1 - 2017-06-29 ( eshagdar ): prefs must be a record. incoming param may be a string, so ensure that it's an object reference.
	1.0 - created
*)

on run
	tell application "System Events"
		tell application process "FileMaker Pro Advanced"
			set frontmost to true
			delay 1
			--set popUpButtonRef to pop up button "Available menu commands:" of window 1
			set popUpButtonRef to pop up button "View" of window 1
		end tell
	end tell

	fmGUI_Popup_SelectByCommand({objRef:popUpButtonRef, objValue:"limited...", calcValue:"If ( True; True; GetAsNumber ( \"1\" ) )", clickIfAlreadySet:true})

end run

--------------------
-- START OF CODE
--------------------

on fmGUI_Popup_SelectByCommand(prefs)
	-- version 2020-05-21-1321

	set defaultPrefs to {objRef:null, objValue:null, calcValue:null, selectCommand:"is", clickIfAlreadySet:false}
	set prefs to prefs & defaultPrefs

	set objRef to ensureObjectRef(objRef of prefs)
	set selectCommand to selectCommand of prefs
	set objValue to objValue of prefs
	set clickIfAlreadySet to clickIfAlreadySet of prefs -- re-select even if popup is the requested value.

	try
		tell application "System Events"
			if not (exists objRef) then error "The specified objRef does not exist." number 1024

			-- the objRef DOES exist
			set mustPick to false
			if not (exists value of objRef) then
				-- first check if the value of the objRef exists - if it doesn't, then we can't test it directly
				set mustPick to true

			else -- we can see the value without 'picking' the menu, so test it:
				-- note that our selection might be one of several 'matching' commands:
				if clickIfAlreadySet then
					-- RE-SELECT even if popup already is the requested value.
					set mustPick to true

				else if selectCommand is equal to "is" then
					if value of objRef is not objValue then
						set mustPick to true
					end if

				else if selectCommand is equal to "contains" then
					if value of objRef does not contain objValue then
						set mustPick to true
					end if

				else if selectCommand is equal to "startsWith" then
					if value of objRef does not start with objValue then
						set mustPick to true
					end if

				else if selectCommand is equal to "beginsWith" then
					if value of objRef does not start with objValue then
						set mustPick to true
					end if

				else if selectCommand is equal to "endsWith" then
					if value of objRef does not end with objValue then
						set mustPick to true
					end if

				end if
			end if
		end tell

		if mustPick then
			if objValue is not null then

				set isMenuOpen to false (* INITIALIZE *)

				-- click pop up button so the menu becomes available
				delay 0.3 -- short delay to make sure click can happen:
				clickObjectByCoords(objRef)

				-- wait to see if menu becomes available
				repeat 100 times
					try
						tell application "System Events"
							tell application process "FileMaker Pro Advanced"
								if exists (menu 1 of objRef) then
									set isMenuOpen to true
									exit repeat
								end if
							end tell
						end tell
					on error
						delay 0.5
					end try
				end repeat

				if not isMenuOpen then
					-- SECOND attempt to click-then-wait for menu to be available, but give up sooner:

					-- click pop up button so the menu becomes available
					clickObjectByCoords(objRef)

					--wait until menu is available
					repeat 20 times
						try
							tell application "System Events"
								tell application process "FileMaker Pro Advanced"
									if exists (menu 1 of objRef) then
										set isMenuOpen to true
										exit repeat
									end if
								end tell
							end tell
						on error
							delay 0.5
						end try
					end repeat
				end if

				if not isMenuOpen then
					error "Was not able to get the popup _menu_ to appear (by clicking base object) so an item could be chosen." number 1024
				end if

				-- now pick an item from the pop up
				tell application "System Events"
					objRef
					if selectCommand is equal to "is" then
						set objValue to first menu item of menu 1 of objRef whose name is objValue
					else if selectCommand is equal to "contains" then
						set objValue to first menu item of menu 1 of objRef whose name contains objValue
					else if selectCommand is equal to "beginsWith" then
						set objValue to first menu item of menu 1 of objRef whose name starts with objValue
					else if selectCommand is equal to "endsWith" then
						set objValue to first menu item of menu 1 of objRef whose name ends with objValue
					else
						error "unable to pick objValue because select command is failed" number -1024
					end if

					tell process "FileMaker Pro Advanced"
						click objValue
					end tell
				end tell

				-- must tell FM to click since the value might now be available ( need to scroll )
				--clickObjectByCoords(objValue)
			end if

			-- set calc if there is one
			if calcValue of prefs is not null then fmGUI_SpecifyCalcWindowSet({calcValue:calcValue of prefs})
		end if

		return true
	on error errMsg number errNum
		error "unable to fmGUI_Popup_SelectByCommand ( value _" & selectCommand & "_ '" & objValue & "' in popup ) - " & errMsg number errNum
	end try
end fmGUI_Popup_SelectByCommand

--------------------
-- END OF CODE
--------------------

on clickObjectByCoords(objRef)
	tell application "htcLib" to clickObjectByCoords(my coerceToString(objRef))
end clickObjectByCoords

on fmGUI_SpecifyCalcWindowSet(prefs)
	tell application "htcLib" to fmGUI_SpecifyCalcWindowSet(prefs)
end fmGUI_SpecifyCalcWindowSet

on coerceToString(incomingObject)
	-- 2017-07-12 ( eshagdar ): bootstrap code to bring a coerceToString into this file for the sample to run ( instead of having a copy of the handler locally ).

	tell application "Finder" to set coercePath to (container of (container of (path to me)) as text) & "text parsing:coerceToString.applescript"
	set codeCoerce to read file coercePath as text
	tell application "htcLib" to set codeCoerce to "script codeCoerce " & return & getTextBetween({sourceText:codeCoerce, beforeText:"-- START OF CODE", afterText:"-- END OF CODE"}) & return & "end script" & return & "return codeCoerce"
	set codeCoerce to run script codeCoerce
	tell codeCoerce to coerceToString(incomingObject)
end coerceToString

on ensureObjectRef(someObjectRef)
	-- 2017-07-12 ( eshagdar ): bootstrap code to bring a ensureObjectRef into this file for the sample to run ( instead of having a copy of the handler locally ).

	tell application "Finder" to set ensureObjPath to (container of (container of (path to me)) as text) & "text parsing:ensureObjectRef.applescript"
	set codeEnsureObj to read file ensureObjPath as text
	tell application "htcLib" to set codeEnsureObj to "script codeEnsureObj " & return & getTextBetween({sourceText:codeEnsureObj, beforeText:"-- START OF CODE", afterText:"-- END OF CODE"}) & return & "end script" & return & "return codeEnsureObj"
	set codeEnsureObj to run script codeEnsureObj
	tell codeEnsureObj to ensureObjectRef(someObjectRef)
end ensureObjectRef

make popup menu selecting work

make popup menu selecting work