Added ability to update updater script

Added ability to update updater script

Moving the main update checking code to a dedicated script allows us to update everything but the main script, and that is nothing but a stub that launches the updater script.

-- This is the master machq script to replace all others!
-- First find out the version of OS X

global osVersion
global externalIP
global SWUpdateServer
global store
global resources_directory

set osVersion to do shell script "/usr/bin/sw_vers -productVersion | /usr/bin/awk -F . '{print $2}'"

try
	set externalIP to do shell script "/usr/bin/curl http://icanhazip.com/"

	set test1 to do shell script "/usr/bin/dig +short 001.machq.com"
	set test2 to do shell script "/usr/bin/dig +short 002.machq.com"
	set test3 to do shell script "/usr/bin/dig +short 003.machq.com"

	if externalIP is test1 then
		set store to "001"
		set SWUpdateServer to "mhq-swupdate.local:8088"
	else if externalIP is test2 then
		set store to "002"
		set SWUpdateServer to "xserve.local:8088"
	else if externalIP is test3 then
		set store to "003"
		set SWUpdateServer to "servercdr.local:8088"
	end if

on error
	--can't determine which store automatically
	set theStoreList to {"St. Louis", "O'Fallon", "Cedar Rapids"}
	set theStore to choose from list theStoreList with title "Help!" with prompt "Where are we?"

	if theStore as string is "St. Louis" then
		set SWUpdateServer to "mhq-swupdate.local:8088"
	else if theStore as string is "O'Fallon" then
		set SWUpdateServer to "xserve.local:8088"
	else if theStore as string is "Cedar Rapids" then
		set SWUpdateServer to "servercdr.local:8088"
	end if

end try

--check for updates to the updater script
try
	tell application "Finder"
		set scripts_directory to (container of (path to me) as text)
		set resources_directory to (container of container of (path to me) as text)
	end tell

	set local_file to the POSIX path of (resources_directory & "updater.version")
	set local_version to do shell script "/bin/cat \"" & local_file & "\""

	set current_version to do shell script "/usr/bin/curl https://raw.githubusercontent.com/nilness/mhqtools/master/updater.version"
	--display dialog "Local version of updater is: " & local_version & ", current version is: " & current_version

	if current_version > local_version then

		--download the new version
		set local_file to the POSIX path of (scripts_directory & "updater.applescript")
		do shell script "curl https://raw.githubusercontent.com/nilness/mhqtools/master/updater.applescript > \"" & local_file & "\""
		--update the local version string
		set local_file to the POSIX path of (resources_directory & "updater.version")
		do shell script "curl https://raw.githubusercontent.com/nilness/mhqtools/master/updater.version > \"" & local_file & "\""

	end if
end try

tell application "Finder"
	set resources_directory to (container of container of (path to me) as text)
end tell

--display dialog osVersion buttons {"OK"}

--display dialog SWUpdateServer buttons {"OK"}

set theButtonNames to {"Set Used Prefs (all *'ed items)", "Set SWUpdateServer*", "List SWUpdateServer", "Remove SWUpdateServer", "Set MacHQ homepage*", "Disable Sleep*", "Rename HD by Size*", "Install MHQ Reset Script", "Remove Current User & Reset CPU", "Test for Flashback Trojan", "Test for ShellShock vulnerability", "Rebuild Launch Services DB", "Flush DNS Cache", "Reset Fake preferences", "Update Fake Workflows from Server", "Install SWUpdate StartupItem", "Save System Profiler Report to server"}

repeat
	set theChoice to choose from list theButtonNames
	if theChoice is false then
		exit repeat
	else if theChoice as string is "Set SWUpdateServer*" then
		setSWUpdateServer()
	else if theChoice as string is "List SWUpdateServer" then
		listSWUpdateServer()
	else if theChoice as string is "Remove SWUpdateServer" then
		resetSWUpdateServer()
	else if theChoice as string is "Set MacHQ homepage*" then
		setHomePage()
	else if theChoice as string is "Set Used Prefs (all *'ed items)" then
		setUsedPrefs()
	else if theChoice as string is "Disable Sleep*" then
		disableSleep()
	else if theChoice as string is "Rename HD by Size*" then
		renameHDbySize()
	else if theChoice as string is "Install MHQ Reset Script" then
		installResetScript()
	else if theChoice as string is "Remove MHQ User & Reset CPU" then
		if resetUserCPU() = -128 then
			return
		end if
	else if theChoice as string is "Remove Current User & Reset CPU" then
		if resetThisUserCPU() = -128 then
			return
		end if
	else if theChoice as string is "Test for Flashback Trojan" then
		testForFlashbackTrojan()
	else if theChoice as string is "Rebuild Launch Services DB" then
		rebuildLaunchServicesDB()
	else if theChoice as string is "Reset Fake preferences" then
		reinstallDefaultFakePreferences()
	else if theChoice as string is "Reinstall Fake Workflows" then
		reinstallFakeWorkflows()
	else if theChoice as string is "Install SWUpdate StartupItem" then
		InstallSWUpdatePlist()
	else if theChoice as string is "Flush DNS Cache" then
		FlushDNSCache()
	else if theChoice as string is "Save System Profiler Report to server" then
		SystemProfilerReport()
	else if theChoice as string is "Update Fake Workflows from Server" then
		UpdateWorkflowsFromServer()
	else if theChoice as string is "Test for ShellShock vulnerability" then
		testForShellShockVulnerability()
	else
		tell me to quit
	end if

end repeat

on setUsedPrefs()
	disableSleep()
	setSWUpdateServer()
	setHomePage()
	renameHDbySize()
end setUsedPrefs

on setHomePage()
	set fileTarget to (path to library folder from user domain as text) & "Preferences:com.apple.Safari.plist"

	try
		-- we don't really need the alias; we're just checking to see if it exists
		fileTarget as alias
	on error
		tell application "Safari"
			activate
		end tell
	end try
	if running of application "Safari" then
		tell application "Safari"
			quit
		end tell
		repeat while (running of application "Safari")
			delay 1
		end repeat
		delay 2
	end if
	do shell script "defaults write com.apple.Safari HomePage http://twitter.com/machq; defaults write com.apple.Safari NewWindowBehavior 0"
	delay 2
	tell application "Safari"
		activate
		delay 2
		close every window
		quit
	end tell
end setHomePage

on listSWUpdateServer()
	try
		set server_name to do shell script "defaults read /Library/Preferences/com.apple.SoftwareUpdate CatalogURL"
		display dialog "SW update server is: " & server_name buttons {"OK"}
	on error
		display dialog "Using default Apple SW Update Server" buttons {"OK"}
	end try
end listSWUpdateServer

on resetSWUpdateServer()
	try
		--if running in 10.7 or later we need to supply password

		if (osVersion as number > 7) then
			do shell script "defaults delete /Library/Preferences/com.apple.SoftwareUpdate CatalogURL" with administrator privileges
		else
			do shell script "/usr/bin/defaults delete /Library/Preferences/com.apple.SoftwareUpdate CatalogURL"
		end if

		--do shell script "defaults delete /Library/Preferences/com.apple.SoftwareUpdate CatalogURL"
	end try
end resetSWUpdateServer

on disableSleep()
	try
		do shell script "pmset -c displaysleep 0 sleep 0 disksleep 0" with administrator privileges
	end try
end disableSleep

on renameHDbySize()
	set theSetScript to "

#!/bin/bash

boot_vol=`bless --getBoot`

boot_disk=`diskutil info ${boot_vol} |sed '/^ *Volume Name: */!d;s###'`

disk_size=`system_profiler SPSerialATADataType |sed '/^ *Capacity: */!d;s###' | awk '{print int($1+0.5)  $2\" HD\"}' | head -n 1 `

diskutil rename \"${boot_disk}\" \"${disk_size}\"

# Show icons for hard drives, servers, and removable media on the desktop
#defaults write com.apple.finder ShowExternalHardDrivesOnDesktop -bool true
defaults write com.apple.finder ShowHardDrivesOnDesktop -bool true
#defaults write com.apple.finder ShowMountedServersOnDesktop -bool true
#defaults write com.apple.finder ShowRemovableMediaOnDesktop -bool true

killall Finder

"
	do shell script theSetScript

end renameHDbySize

on setSWUpdateServer()

	set theSetScript to "

#!/bin/bash

URL1='http://" & SWUpdateServer & "'
    case `/usr/bin/sw_vers -productVersion | /usr/bin/awk -F . '{print $2}'` in
      4) URL=\"${URL1}/index.sucatalog\" ;;
      5) URL=\"${URL1}/index-leopard.merged-1.sucatalog\" ;;
      6) URL=\"${URL1}/index-leopard-snowleopard.merged-1.sucatalog\" ;;
	7) URL=\"${URL1}/index-lion-snowleopard-leopard.merged-1.sucatalog\" ;;
	8) URL=\"${URL1}/index-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog\" ;;
	9) URL=\"${URL1}/index-10.9-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog\" ;;
	10) URL=\"${URL1}/index-10.10-10.9-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog\" ;;
      *) echo \"Unsupported client OS\"; exit 1 ;;
    esac

/usr/bin/defaults write /Library/Preferences/com.apple.SoftwareUpdate CatalogURL \"${URL}\"

	"
	--if running in 10.7 or 10.8 we need to supply password
	try
		if (osVersion as number > 7) then
			do shell script theSetScript with administrator privileges
		else
			do shell script theSetScript
		end if
	end try
end setSWUpdateServer

on installResetScript()
	try
		tell application "Finder"
			set TheFile to (resources_directory & "mhqreset.sh") as alias
			duplicate TheFile to the startup disk with replacing
		end tell
	on error error_message
		display dialog error_message
	end try
end installResetScript

on resetUserCPU()
	try
		display dialog "This will install the MHQ reset script and restart the computer into single user mode, then run the reset script automatically. Do you wish to continue?" buttons {"Quit", "Continue"} default button "Continue" cancel button "Quit"
		installResetScript()

		if osVersion is "10" then
			set target_file to ".bashrc"
		else
			set target_file to ".profile"
		end if

		do shell script "echo \"sh /mhqreset.sh\" >> /private/var/root/" & target_file with administrator privileges

		do shell script "nvram boot-args=\"-s\"" with administrator privileges

		tell application "Finder" to restart
		return -128
	end try
end resetUserCPU

on resetThisUserCPU()
	try
		tell application "System Events"
			set current_user to get the name of current user
		end tell

		display dialog "This will install the MHQ reset script and restart the computer into single user mode, then run the reset script automatically. The user \"" & current_user & "\" will be deleted with all it's files. Do you wish to continue?" buttons {"Quit", "Continue"} default button "Continue" cancel button "Quit"
		display dialog "Are you absolutely certain?. The user \"" & current_user & "\" will be deleted with all it's files. Do you wish to continue?" buttons {"Quit", "Continue"} default button "Continue" cancel button "Quit"
		installResetScript()

		if osVersion is "10" then
			set target_file to ".bashrc"
		else
			set target_file to ".profile"
		end if

		do shell script "echo \"sh /mhqreset.sh\" " & current_user & " >> /private/var/root/" & target_file with administrator privileges

		do shell script "nvram boot-args=\"-s\"" with administrator privileges

		tell application "Finder" to restart
		return -128
	end try
end resetThisUserCPU

on InstallSWUpdatePlist()

	set TheFile to (resources_directory & "Set SWUpdate Server") as alias

	if (osVersion as number > 7) then

		tell application "Finder"
			duplicate TheFile to (path to startup items from local domain as alias) with replacing
		end tell
	else

		set theScript to "

		#!/bin/bash

		if [ ! -e '/Library/StartupItems/Set SWUpdate Server' ]; then
		    mkdir '/Library/StartupItems/Set SWUpdate Server'
		fi
		cp -R '" & (the POSIX path of TheFile) & "' '/Library/StartupItems/Set SWUpdate Server/.'
		"
		do shell script theScript with administrator privileges

	end if

	do shell script "chmod -R 755 '/Library/StartupItems/Set SWUpdate Server'; sudo chown -R root:wheel '/Library/StartupItems/Set SWUpdate Server'" with administrator privileges

end InstallSWUpdatePlist

on testForFlashbackTrojan()
	display alert ("Beginning test") message "Testing for presence of Flashback trojan. Keep in mind this is NOT a definitive test!"

	try
		set check1 to do shell script "defaults read /Applications/Safari.app/Contents/Info LSEnvironment"
		display alert ("Possible infection!") message "Recommend running full antivirus scan with up to date scanner. Please note this test is a first release and may produce false positives."

	on error error_message number error_number
		if error_number is equal to 1 then
			display alert ("Alert!") message "First check appears okay"
		end if
	end try

	try
		set check2 to do shell script "defaults read ~/.MacOSX/environment DYLD_INSERT_LIBRARIES"
		display alert ("Possible infection!") message "Recommend running full antivirus scan with up to date scanner. Please note this test is a first release and may produce false positives."

	on error error_message number error_number
		if error_number is equal to 1 then
			display alert ("Alert!") message "Second check appears okay"
		end if
	end try
end testForFlashbackTrojan

on rebuildLaunchServicesDB()
	display alert ("Alert!") message "The Finder must be quit and will relaunch when complete."

	try
		tell application "Finder" to quit
		do shell script "/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister -kill -r -domain local -domain system -domain user"
		tell application "Finder" to activate

	end try
end rebuildLaunchServicesDB

on reinstallDefaultFakePreferences()

	--delete the current preference file

	tell application "Finder"
		set oldFile to (path to preferences folder as string) & "com.fakeapp.Fake.plist"
		delete file oldFile
	end tell

	-- create new preference file and set the properties we care about
	set theSetScript to "
#!/bin/bash

touch \"~/Preferences/com.fakeapp.Fake.plist\"
defaults write com.fakeapp.Fake \"FakeDelayBetweenRunningActions\" '0'
defaults write com.fakeapp.Fake \"FakePlaySuccessFailureSounds\" '0'
"
	do shell script theSetScript

end reinstallDefaultFakePreferences

on reinstallFakeWorkflows()
	set oldFolder to (path to application support from user domain as text) & "Fake:Workflows:"
	set fakeFolder to (path to application support from user domain as text) & "Fake:"
	set newFolder to (resources_directory & "Workflows") as alias
	--	display dialog oldFolder buttons {"OK"}
	tell application "Finder"
		try
			delete oldFolder
		end try
		duplicate newFolder to fakeFolder
	end tell
end reinstallFakeWorkflows

on FlushDNSCache()
	set theSetScript to "

#!/bin/bash

case `/usr/bin/sw_vers -productVersion | /usr/bin/awk -F . '{print $2}'` in
    4) lookupd -flushcache ;;
   [56]) dscacheutil -flushcache ;;
    [78]) sudo killall -HUP mDNSResponder ;;
    9) dscacheutil -flushcache; sudo killall -HUP mDNSResponder ;;
  10) dscacheutil -flushcache; sudo discoveryutil mdnsflushcache ;;
      *) echo \"Unsupported client OS\"; exit 1 ;;
esac

	"
	--if running in 10.7 or 10.8 we need to supply password

	if (osVersion as number > 7) then
		do shell script theSetScript with administrator privileges
	else
		do shell script theSetScript
	end if
end FlushDNSCache

on SystemProfilerReport()

	if (store = "001") then
		set destination to "/Volumes/MHQ/Backed Up/System Profiler Reports/"
		set dest_volume to "afp://mhq-swupdate.local/MHQ"
	else if (store = "002") then
		set destination to "/Volumes/Service/System Profiler Reports/"
		set dest_volume to "afp://xserve.local/Service"
	else if (store = "003") then
		set destination to "/Volumes/Service/System Profiler Reports/"
		set dest_volume to "afp://servercdr.local/Service"
	end if

	--	display dialog oldFolder

	tell application "Finder"
		try
			mount volume dest_volume
		on error
			return "Error mounting server volume \"" & dest_volume & "\". Please connect to server manually and try again."
			tell me to quit
		end try
	end tell

	--this shell script will generate a system profiler report and save it to the server
	do shell script "#!/bin/sh

# the location includes a folder based on the date in yyyy-mm-dd format
report_location=\"" & destination & "`date \"+%Y-%m-%d\"`/\"

if [ ! -d \"${report_location}\" ]; then
	mkdir \"${report_location}\"
fi

serial=`system_profiler SPHardwareDataType | grep \"Serial Number\" | awk  '{print $4}'`

SPDataTypes=\"SPHardwareDataType SPMemoryDataType SPPowerDataType SPSerialATADataType SPSoftwareDataType SPThunderboltDataType SPUSBDataType SPAirPortDataType SPFireWireDataType SPParallelATADataType SPAudioDataType SPBluetoothDataType SPNetworkDataType\"

system_profiler -xml $SPDataTypes > $report_location$serial\".spx\"
"

end SystemProfilerReport

on UpdateWorkflowsFromServer()

	set destination to POSIX path of ((path to application support from user domain as text) & "Fake:Workflows:")

	if (store = "001") then
		set source to "/Volumes/MHQ/Backed Up/Retail Stuff/Current Workflows/"
		set dest_volume to "afp://mhq-swupdate.local/MHQ"
	else if (store = "002") then
		set source to "/Volumes/Retail/Current Workflows/"
		set dest_volume to "afp://xserve.local/Retail"
	else if (store = "003") then
		set source to "/Volumes/Retail/Current Workflows/"
		set dest_volume to "afp://servercdr.local/Retail"
	end if

	--	display dialog oldFolder buttons {"OK"}

	tell application "Finder"
		try
			mount volume dest_volume
		on error
			return "Error mounting server volume \"" & dest_volume & "\". Please connect to server manually and try again."
			tell me to quit
		end try
	end tell

	try
		set theScript to "
	#!/bin/bash

	/usr/bin/rsync -a '" & source & "' '" & destination & "'
	" --shell script

		do shell script theScript --with administrator privileges
	on error
		return "Error syncronizing folders."
	end try

end UpdateWorkflowsFromServer

on testForShellShockVulnerability()

	set test_1 to "
#!/bin/bash

EXPLOIT_1=`env x='() { :;}; echo vulnerable' bash -c \"echo this is a test\"`
if [ \"${EXPLOIT_1}\" = \"vulnerable\" ]; then
    echo \"Test 1 (CVE-2014-6271):	**** Machine appears to be vulnerable ****\"
else
    echo \"Test 1 (CVE-2014-6271):	Machine doesn't appear to be vulnerable\"
fi
"
	set test_2 to "
#!/bin/bash

EXPLOIT_2=`env X='() { (shellshocker.net)=>\\' bash -c \"echo date\"; cat echo; rm ./echo `
if [ \"${EXPLOIT_2}\" != \"date\" ]; then
    echo \"Test 2 (CVE-2014-7169):	**** Machine appears to be vulnerable ****\"
else
    echo \"Test 2 (CVE-2014-7169):	Machine doesn't appear to be vulnerable\"
fi
"
	set test_3 to "
#!/bin/bash

EXPLOIT_3=`env X=' () { }; echo hello' bash -c 'date'`
if [ \"${EXPLOIT_3}\" = \"hello\" ]; then
    echo \"Test 3 (CVE-??):	**** Machine appears to be vulnerable ****\"
else
    echo \"Test 3 (CVE-??):	Machine doesn't appear to be vulnerable\"
fi

"

	set test_4 to "
#!/bin/bash

EXPLOIT_4=`bash -c 'true <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF' || echo \"CVE-2014-7186 vulnerable, redir_stack\"`
if [ \"${EXPLOIT_4}\" = \"CVE-2014-7186 vulnerable, redir_stack\" ]; then
    echo \"Test 4 (CVE-2014-7186):	**** Machine appears to be vulnerable ****\"
else
    echo \"Test 4 (CVE-2014-7186):	Machine doesn't appear to be vulnerable\"
fi

"

	set test_5 to "
#!/bin/bash

EXPLOIT_5=`(for x in {1..200} ; do echo \"for x$x in ; do :\"; done; for x in {1..200} ; do echo done ; done) | bash || echo \"CVE-2014-7187 vulnerable, word_lineno\"`
if [ \"${EXPLOIT_5}\" = \"CVE-2014-7187 vulnerable, word_lineno\" ]; then
    echo \"Test 5 (CVE-2014-7187):	**** Machine appears to be vulnerable ****\"
else
    echo \"Test 5 (CVE-2014-7187):	Machine doesn't appear to be vulnerable\"
fi

"
	set test_6 to "
#!/bin/bash

EXPLOIT_6=`shellshocker='() { echo You are vulnerable; }' bash -c shellshocker`
if [ \"${EXPLOIT_6}\" = \"You are vulnerable\" ]; then
    echo \"Test 6 (CVE-2014-6278):	**** Machine appears to be vulnerable ****\"
else
    echo \"Test 6 (CVE-2014-6278):	Machine doesn't appear to be vulnerable\"
fi

"
	set test_7 to "
#!/bin/bash

EXPLOIT_7=`bash -c \"f() { x() { _;}; x() { _;} <<a; }\" 2>/dev/null || echo vulnerable`
if [ \"${EXPLOIT_7}\" = \"vulnerable\" ]; then
    echo \"Test 7 (CVE-2014-6277):	**** Machine appears to be vulnerable ****\"
else
    echo \"Test 7 (CVE-2014-6277):	Machine doesn't appear to be vulnerable\"
fi

"

	set result_1 to do shell script test_1
	set result_2 to do shell script test_2
	set result_3 to do shell script test_3
	set result_4 to do shell script test_4
	set result_5 to do shell script test_5
	set result_6 to do shell script test_6
	set result_7 to do shell script test_7

	try
		display dialog result_1 & return & result_2 & return & result_3 & return & result_4 & return & result_6 & return & result_6 & return & result_7 & return buttons {"OK"}
	end try
end testForShellShockVulnerability

-- This is the master machq script to replace all others!
-- First find out the version of OS X

global osVersion
global externalIP
global SWUpdateServer
global store
global resources_directory

set osVersion to do shell script "/usr/bin/sw_vers -productVersion | /usr/bin/awk -F . '{print $2}'"

try
	set externalIP to do shell script "/usr/bin/curl http://icanhazip.com/"

	set test1 to do shell script "/usr/bin/dig +short 001.machq.com"
	set test2 to do shell script "/usr/bin/dig +short 002.machq.com"
	set test3 to do shell script "/usr/bin/dig +short 003.machq.com"

	if externalIP is test1 then
		set store to "001"
		set SWUpdateServer to "mhq-swupdate.local:8088"
	else if externalIP is test2 then
		set store to "002"
		set SWUpdateServer to "xserve.local:8088"
	else if externalIP is test3 then
		set store to "003"
		set SWUpdateServer to "servercdr.local:8088"
	end if

on error
	--can't determine which store automatically
	set theStoreList to {"St. Louis", "O'Fallon", "Cedar Rapids"}
	set theStore to choose from list theStoreList with title "Help!" with prompt "Where are we?"

	if theStore as string is "St. Louis" then
		set SWUpdateServer to "mhq-swupdate.local:8088"
	else if theStore as string is "O'Fallon" then
		set SWUpdateServer to "xserve.local:8088"
	else if theStore as string is "Cedar Rapids" then
		set SWUpdateServer to "servercdr.local:8088"
	end if

end try

tell application "Finder"
	set resources_directory to (container of container of (path to me) as text)
end tell

--display dialog osVersion buttons {"OK"}

--display dialog SWUpdateServer buttons {"OK"}

set theButtonNames to {"Set Used Prefs (all *'ed items)", "Set SWUpdateServer*", "List SWUpdateServer", "Remove SWUpdateServer", "Set MacHQ homepage*", "Disable Sleep*", "Rename HD by Size*", "Install MHQ Reset Script", "Remove Current User & Reset CPU", "Test for Flashback Trojan", "Test for ShellShock vulnerability", "Rebuild Launch Services DB", "Flush DNS Cache", "Reset Fake preferences", "Update Fake Workflows from Server", "Install SWUpdate StartupItem", "Save System Profiler Report to server"}

repeat
	set theChoice to choose from list theButtonNames
	if theChoice is false then
		exit repeat
	else if theChoice as string is "Set SWUpdateServer*" then
		setSWUpdateServer()
	else if theChoice as string is "List SWUpdateServer" then
		listSWUpdateServer()
	else if theChoice as string is "Remove SWUpdateServer" then
		resetSWUpdateServer()
	else if theChoice as string is "Set MacHQ homepage*" then
		setHomePage()
	else if theChoice as string is "Set Used Prefs (all *'ed items)" then
		setUsedPrefs()
	else if theChoice as string is "Disable Sleep*" then
		disableSleep()
	else if theChoice as string is "Rename HD by Size*" then
		renameHDbySize()
	else if theChoice as string is "Install MHQ Reset Script" then
		installResetScript()
	else if theChoice as string is "Remove MHQ User & Reset CPU" then
		if resetUserCPU() = -128 then
			return
		end if
	else if theChoice as string is "Remove Current User & Reset CPU" then
		if resetThisUserCPU() = -128 then
			return
		end if
	else if theChoice as string is "Test for Flashback Trojan" then
		testForFlashbackTrojan()
	else if theChoice as string is "Rebuild Launch Services DB" then
		rebuildLaunchServicesDB()
	else if theChoice as string is "Reset Fake preferences" then
		reinstallDefaultFakePreferences()
	else if theChoice as string is "Reinstall Fake Workflows" then
		reinstallFakeWorkflows()
	else if theChoice as string is "Install SWUpdate StartupItem" then
		InstallSWUpdatePlist()
	else if theChoice as string is "Flush DNS Cache" then
		FlushDNSCache()
	else if theChoice as string is "Save System Profiler Report to server" then
		SystemProfilerReport()
	else if theChoice as string is "Update Fake Workflows from Server" then
		UpdateWorkflowsFromServer()
	else if theChoice as string is "Test for ShellShock vulnerability" then
		testForShellShockVulnerability()
	else
		tell me to quit
	end if

end repeat

on setUsedPrefs()
	disableSleep()
	setSWUpdateServer()
	setHomePage()
	renameHDbySize()
end setUsedPrefs

on setHomePage()
	set fileTarget to (path to library folder from user domain as text) & "Preferences:com.apple.Safari.plist"

	try
		-- we don't really need the alias; we're just checking to see if it exists
		fileTarget as alias
	on error
		tell application "Safari"
			activate
		end tell
	end try
	if running of application "Safari" then
		tell application "Safari"
			quit
		end tell
		repeat while (running of application "Safari")
			delay 1
		end repeat
		delay 2
	end if
	do shell script "defaults write com.apple.Safari HomePage http://twitter.com/machq; defaults write com.apple.Safari NewWindowBehavior 0"
	delay 2
	tell application "Safari"
		activate
		delay 2
		close every window
		quit
	end tell
end setHomePage

on listSWUpdateServer()
	try
		set server_name to do shell script "defaults read /Library/Preferences/com.apple.SoftwareUpdate CatalogURL"
		display dialog "SW update server is: " & server_name buttons {"OK"}
	on error
		display dialog "Using default Apple SW Update Server" buttons {"OK"}
	end try
end listSWUpdateServer

on resetSWUpdateServer()
	try
		--if running in 10.7 or later we need to supply password

		if (osVersion as number > 7) then
			do shell script "defaults delete /Library/Preferences/com.apple.SoftwareUpdate CatalogURL" with administrator privileges
		else
			do shell script "/usr/bin/defaults delete /Library/Preferences/com.apple.SoftwareUpdate CatalogURL"
		end if

		--do shell script "defaults delete /Library/Preferences/com.apple.SoftwareUpdate CatalogURL"
	end try
end resetSWUpdateServer

on disableSleep()
	try
		do shell script "pmset -c displaysleep 0 sleep 0 disksleep 0" with administrator privileges
	end try
end disableSleep

on renameHDbySize()
	set theSetScript to "

#!/bin/bash

boot_vol=`bless --getBoot`

boot_disk=`diskutil info ${boot_vol} |sed '/^ *Volume Name: */!d;s###'`

disk_size=`system_profiler SPSerialATADataType |sed '/^ *Capacity: */!d;s###' | awk '{print int($1+0.5)  $2\" HD\"}' | head -n 1 `

diskutil rename \"${boot_disk}\" \"${disk_size}\"

# Show icons for hard drives, servers, and removable media on the desktop
#defaults write com.apple.finder ShowExternalHardDrivesOnDesktop -bool true
defaults write com.apple.finder ShowHardDrivesOnDesktop -bool true
#defaults write com.apple.finder ShowMountedServersOnDesktop -bool true
#defaults write com.apple.finder ShowRemovableMediaOnDesktop -bool true

killall Finder

"
	do shell script theSetScript

end renameHDbySize

on setSWUpdateServer()

	set theSetScript to "

#!/bin/bash

URL1='http://" & SWUpdateServer & "'
    case `/usr/bin/sw_vers -productVersion | /usr/bin/awk -F . '{print $2}'` in
      4) URL=\"${URL1}/index.sucatalog\" ;;
      5) URL=\"${URL1}/index-leopard.merged-1.sucatalog\" ;;
      6) URL=\"${URL1}/index-leopard-snowleopard.merged-1.sucatalog\" ;;
	7) URL=\"${URL1}/index-lion-snowleopard-leopard.merged-1.sucatalog\" ;;
	8) URL=\"${URL1}/index-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog\" ;;
	9) URL=\"${URL1}/index-10.9-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog\" ;;
	10) URL=\"${URL1}/index-10.10-10.9-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog\" ;;
      *) echo \"Unsupported client OS\"; exit 1 ;;
    esac

/usr/bin/defaults write /Library/Preferences/com.apple.SoftwareUpdate CatalogURL \"${URL}\"

	"
	--if running in 10.7 or 10.8 we need to supply password
	try
		if (osVersion as number > 7) then
			do shell script theSetScript with administrator privileges
		else
			do shell script theSetScript
		end if
	end try
end setSWUpdateServer

on installResetScript()
	try
		tell application "Finder"
			set TheFile to (resources_directory & "mhqreset.sh") as alias
			duplicate TheFile to the startup disk with replacing
		end tell
	on error error_message
		display dialog error_message
	end try
end installResetScript

on resetUserCPU()
	try
		display dialog "This will install the MHQ reset script and restart the computer into single user mode, then run the reset script automatically. Do you wish to continue?" buttons {"Quit", "Continue"} default button "Continue" cancel button "Quit"
		installResetScript()

		if osVersion is "10" then
			set target_file to ".bashrc"
		else
			set target_file to ".profile"
		end if

		do shell script "echo \"sh /mhqreset.sh\" >> /private/var/root/" & target_file with administrator privileges

		do shell script "nvram boot-args=\"-s\"" with administrator privileges

		tell application "Finder" to restart
		return -128
	end try
end resetUserCPU

on resetThisUserCPU()
	try
		tell application "System Events"
			set current_user to get the name of current user
		end tell

		display dialog "This will install the MHQ reset script and restart the computer into single user mode, then run the reset script automatically. The user \"" & current_user & "\" will be deleted with all it's files. Do you wish to continue?" buttons {"Quit", "Continue"} default button "Continue" cancel button "Quit"
		display dialog "Are you absolutely certain?. The user \"" & current_user & "\" will be deleted with all it's files. Do you wish to continue?" buttons {"Quit", "Continue"} default button "Continue" cancel button "Quit"
		installResetScript()

		if osVersion is "10" then
			set target_file to ".bashrc"
		else
			set target_file to ".profile"
		end if

		do shell script "echo \"sh /mhqreset.sh\" " & current_user & " >> /private/var/root/" & target_file with administrator privileges

		do shell script "nvram boot-args=\"-s\"" with administrator privileges

		tell application "Finder" to restart
		return -128
	end try
end resetThisUserCPU

on InstallSWUpdatePlist()

	set TheFile to (resources_directory & "Set SWUpdate Server") as alias

	if (osVersion as number > 7) then

		tell application "Finder"
			duplicate TheFile to (path to startup items from local domain as alias) with replacing
		end tell
	else

		set theScript to "

		#!/bin/bash

		if [ ! -e '/Library/StartupItems/Set SWUpdate Server' ]; then
		    mkdir '/Library/StartupItems/Set SWUpdate Server'
		fi
		cp -R '" & (the POSIX path of TheFile) & "' '/Library/StartupItems/Set SWUpdate Server/.'
		"
		do shell script theScript with administrator privileges

	end if

	do shell script "chmod -R 755 '/Library/StartupItems/Set SWUpdate Server'; sudo chown -R root:wheel '/Library/StartupItems/Set SWUpdate Server'" with administrator privileges

end InstallSWUpdatePlist

on testForFlashbackTrojan()
	display alert ("Beginning test") message "Testing for presence of Flashback trojan. Keep in mind this is NOT a definitive test!"

	try
		set check1 to do shell script "defaults read /Applications/Safari.app/Contents/Info LSEnvironment"
		display alert ("Possible infection!") message "Recommend running full antivirus scan with up to date scanner. Please note this test is a first release and may produce false positives."

	on error error_message number error_number
		if error_number is equal to 1 then
			display alert ("Alert!") message "First check appears okay"
		end if
	end try

	try
		set check2 to do shell script "defaults read ~/.MacOSX/environment DYLD_INSERT_LIBRARIES"
		display alert ("Possible infection!") message "Recommend running full antivirus scan with up to date scanner. Please note this test is a first release and may produce false positives."

	on error error_message number error_number
		if error_number is equal to 1 then
			display alert ("Alert!") message "Second check appears okay"
		end if
	end try
end testForFlashbackTrojan

on rebuildLaunchServicesDB()
	display alert ("Alert!") message "The Finder must be quit and will relaunch when complete."

	try
		tell application "Finder" to quit
		do shell script "/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister -kill -r -domain local -domain system -domain user"
		tell application "Finder" to activate

	end try
end rebuildLaunchServicesDB

on reinstallDefaultFakePreferences()

	--delete the current preference file

	tell application "Finder"
		set oldFile to (path to preferences folder as string) & "com.fakeapp.Fake.plist"
		delete file oldFile
	end tell

	-- create new preference file and set the properties we care about
	set theSetScript to "
#!/bin/bash

touch \"~/Preferences/com.fakeapp.Fake.plist\"
defaults write com.fakeapp.Fake \"FakeDelayBetweenRunningActions\" '0'
defaults write com.fakeapp.Fake \"FakePlaySuccessFailureSounds\" '0'
"
	do shell script theSetScript

end reinstallDefaultFakePreferences

on reinstallFakeWorkflows()
	set oldFolder to (path to application support from user domain as text) & "Fake:Workflows:"
	set fakeFolder to (path to application support from user domain as text) & "Fake:"
	set newFolder to (resources_directory & "Workflows") as alias
	--	display dialog oldFolder buttons {"OK"}
	tell application "Finder"
		try
			delete oldFolder
		end try
		duplicate newFolder to fakeFolder
	end tell
end reinstallFakeWorkflows

on FlushDNSCache()
	set theSetScript to "

#!/bin/bash

case `/usr/bin/sw_vers -productVersion | /usr/bin/awk -F . '{print $2}'` in
    4) lookupd -flushcache ;;
   [56]) dscacheutil -flushcache ;;
    [78]) sudo killall -HUP mDNSResponder ;;
    9) dscacheutil -flushcache; sudo killall -HUP mDNSResponder ;;
  10) dscacheutil -flushcache; sudo discoveryutil mdnsflushcache ;;
      *) echo \"Unsupported client OS\"; exit 1 ;;
esac

	"
	--if running in 10.7 or 10.8 we need to supply password

	if (osVersion as number > 7) then
		do shell script theSetScript with administrator privileges
	else
		do shell script theSetScript
	end if
end FlushDNSCache

on SystemProfilerReport()

	if (store = "001") then
		set destination to "/Volumes/MHQ/Backed Up/System Profiler Reports/"
		set dest_volume to "afp://mhq-swupdate.local/MHQ"
	else if (store = "002") then
		set destination to "/Volumes/Service/System Profiler Reports/"
		set dest_volume to "afp://xserve.local/Service"
	else if (store = "003") then
		set destination to "/Volumes/Service/System Profiler Reports/"
		set dest_volume to "afp://servercdr.local/Service"
	end if

	--	display dialog oldFolder

	tell application "Finder"
		try
			mount volume dest_volume
		on error
			return "Error mounting server volume \"" & dest_volume & "\". Please connect to server manually and try again."
			tell me to quit
		end try
	end tell

	--this shell script will generate a system profiler report and save it to the server
	do shell script "#!/bin/sh

# the location includes a folder based on the date in yyyy-mm-dd format
report_location=\"" & destination & "`date \"+%Y-%m-%d\"`/\"

if [ ! -d \"${report_location}\" ]; then
	mkdir \"${report_location}\"
fi

serial=`system_profiler SPHardwareDataType | grep \"Serial Number\" | awk  '{print $4}'`

SPDataTypes=\"SPHardwareDataType SPMemoryDataType SPPowerDataType SPSerialATADataType SPSoftwareDataType SPThunderboltDataType SPUSBDataType SPAirPortDataType SPFireWireDataType SPParallelATADataType SPAudioDataType SPBluetoothDataType SPNetworkDataType\"

system_profiler -xml $SPDataTypes > $report_location$serial\".spx\"
"

end SystemProfilerReport

on UpdateWorkflowsFromServer()

	set destination to POSIX path of ((path to application support from user domain as text) & "Fake:Workflows:")

	if (store = "001") then
		set source to "/Volumes/MHQ/Backed Up/Retail Stuff/Current Workflows/"
		set dest_volume to "afp://mhq-swupdate.local/MHQ"
	else if (store = "002") then
		set source to "/Volumes/Retail/Current Workflows/"
		set dest_volume to "afp://xserve.local/Retail"
	else if (store = "003") then
		set source to "/Volumes/Retail/Current Workflows/"
		set dest_volume to "afp://servercdr.local/Retail"
	end if

	--	display dialog oldFolder buttons {"OK"}

	tell application "Finder"
		try
			mount volume dest_volume
		on error
			return "Error mounting server volume \"" & dest_volume & "\". Please connect to server manually and try again."
			tell me to quit
		end try
	end tell

	try
		set theScript to "
	#!/bin/bash

	/usr/bin/rsync -a '" & source & "' '" & destination & "'
	" --shell script

		do shell script theScript --with administrator privileges
	on error
		return "Error syncronizing folders."
	end try

end UpdateWorkflowsFromServer

on testForShellShockVulnerability()

	set test_1 to "
#!/bin/bash

EXPLOIT_1=`env x='() { :;}; echo vulnerable' bash -c \"echo this is a test\"`
if [ \"${EXPLOIT_1}\" = \"vulnerable\" ]; then
    echo \"Test 1 (CVE-2014-6271):	**** Machine appears to be vulnerable ****\"
else
    echo \"Test 1 (CVE-2014-6271):	Machine doesn't appear to be vulnerable\"
fi
"
	set test_2 to "
#!/bin/bash

EXPLOIT_2=`env X='() { (shellshocker.net)=>\\' bash -c \"echo date\"; cat echo; rm ./echo `
if [ \"${EXPLOIT_2}\" != \"date\" ]; then
    echo \"Test 2 (CVE-2014-7169):	**** Machine appears to be vulnerable ****\"
else
    echo \"Test 2 (CVE-2014-7169):	Machine doesn't appear to be vulnerable\"
fi
"
	set test_3 to "
#!/bin/bash

EXPLOIT_3=`env X=' () { }; echo hello' bash -c 'date'`
if [ \"${EXPLOIT_3}\" = \"hello\" ]; then
    echo \"Test 3 (CVE-??):	**** Machine appears to be vulnerable ****\"
else
    echo \"Test 3 (CVE-??):	Machine doesn't appear to be vulnerable\"
fi

"

	set test_4 to "
#!/bin/bash

EXPLOIT_4=`bash -c 'true <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF' || echo \"CVE-2014-7186 vulnerable, redir_stack\"`
if [ \"${EXPLOIT_4}\" = \"CVE-2014-7186 vulnerable, redir_stack\" ]; then
    echo \"Test 4 (CVE-2014-7186):	**** Machine appears to be vulnerable ****\"
else
    echo \"Test 4 (CVE-2014-7186):	Machine doesn't appear to be vulnerable\"
fi

"

	set test_5 to "
#!/bin/bash

EXPLOIT_5=`(for x in {1..200} ; do echo \"for x$x in ; do :\"; done; for x in {1..200} ; do echo done ; done) | bash || echo \"CVE-2014-7187 vulnerable, word_lineno\"`
if [ \"${EXPLOIT_5}\" = \"CVE-2014-7187 vulnerable, word_lineno\" ]; then
    echo \"Test 5 (CVE-2014-7187):	**** Machine appears to be vulnerable ****\"
else
    echo \"Test 5 (CVE-2014-7187):	Machine doesn't appear to be vulnerable\"
fi

"
	set test_6 to "
#!/bin/bash

EXPLOIT_6=`shellshocker='() { echo You are vulnerable; }' bash -c shellshocker`
if [ \"${EXPLOIT_6}\" = \"You are vulnerable\" ]; then
    echo \"Test 6 (CVE-2014-6278):	**** Machine appears to be vulnerable ****\"
else
    echo \"Test 6 (CVE-2014-6278):	Machine doesn't appear to be vulnerable\"
fi

"
	set test_7 to "
#!/bin/bash

EXPLOIT_7=`bash -c \"f() { x() { _;}; x() { _;} <<a; }\" 2>/dev/null || echo vulnerable`
if [ \"${EXPLOIT_7}\" = \"vulnerable\" ]; then
    echo \"Test 7 (CVE-2014-6277):	**** Machine appears to be vulnerable ****\"
else
    echo \"Test 7 (CVE-2014-6277):	Machine doesn't appear to be vulnerable\"
fi

"

	set result_1 to do shell script test_1
	set result_2 to do shell script test_2
	set result_3 to do shell script test_3
	set result_4 to do shell script test_4
	set result_5 to do shell script test_5
	set result_6 to do shell script test_6
	set result_7 to do shell script test_7

	try
		display dialog result_1 & return & result_2 & return & result_3 & return & result_4 & return & result_6 & return & result_6 & return & result_7 & return buttons {"OK"}
	end try
end testForShellShockVulnerability


Clean up daily sync script

Clean up daily sync script

FasdUAS 1.101.10
k
lIC ==================================================================		 ==================================================================

l
	 PROGRESS
 PROGRESS
lIC ================================================================== ==================================================================
l
l
r
mDaily Sync
1

ppgd
l
r !
 m
!1

ppgt"#
"j$0
progresssteps
progressSteps
$m#%&
%i'(
'I) 0updateprogressupdateProgress)*
*1

dscr
(k#++,-
,I.
.sysodelanullnmbr
.m-/0
/r12
11

dscr
21

ppga034
3r56
5[78
7o0
progresssteps
progressSteps
8m
6o0
progresssteps
progressSteps49
9r#:;
:o0
progresssteps
progressSteps
;1"

ppgc&<=
<l=>?
>l?@A
@lBCBIC ==================================================================CDD ==================================================================AEF
ElGHG STARTHII STARTFJK
JlLMLIC ==================================================================MNN ==================================================================KOP
OlPQR
QlS
SIT 0updateprogressupdateProgressTU
Um
VVWW6Starting apps and processesRXY
XlYZ[
Zi
\]
\I^0gettodayappsgetTodayApps^_`
_o0core`ab
ao	0otherbcd
co0workde
eo0
background
]k.ffgh
gr	ij
inkl
km

wkdy
llm
mI
.misccurdldt null
jo	0todayhn
nZ
.opqr
ol

s
s=

tu
to
	0today
um

sun
pLv
vbwx
wo0core
xo0
backgroundqyz
yl{
{=|}
|o	0today
}m

sat z~
~L#
b"
b
o0core
o	0other
o !0
background
rL&.
b&-
b&+
b&)
o&'0core
o'(	0other
o)*0work
o+,0
background[
l
l Open native apps" Open native apps
l
r
J
mTodoist
mCalendar
mMessages
mMail
o0core
l$
r$
J"
mPhotos
mAnki
mSpotify
m
Slack
o	0other
l%+
r%+
J%'
o0work
l,F
r,F
J,B
m,/Google Drive
m/2(Google Photos Backup
m25Flux
m58
Slate
m8;Seil
m;>Karabiner
o0
background
lGX
rGX
IGT0gettodayappsgetTodayApps
oHI0core
oIJ	0other
oJM0work
oMP0
background
o0
nativeapps
nativeApps
lY~
XY~
Ioy
.aevtoappnull****
4ou

capp
ost0	nativeapp	nativeApp0	nativeapp	nativeApp
o\_0
nativeapps
nativeApps
l
l Open web apps Open web apps
l
r
J
m>http://www.apple.com/ios/health
m0https://myfitnesspal.com
o~~0core
l}|
r

	J

mHhttps://www.rescuetime.com/dashboard

m<https://wakatime.com/dashboard
m(https://www.mint.com
m,https://www.egghead.io
m0https://www.codewars.com !
 m""##$https://buffer.com!$%
$m&&''Thttps://www.youtube.com/feed/subscriptions%()
(m**++(https://facebook.com),{
,m--..&https://twitter.com{

ozz	0other}|/0
/l1yx
1r23
2J4456
5m7788@https://domo.demo.domo.com/inbox69:
9m;;<<6https://domo.domo.com/inbox:=>
=m??@@https://domo.okta.com/home/jira_onprem/0oa1moe1d0joaWP4P0x7/3549>AB
AmCCDDhttps://git.empdev.domo.com/pulls?utf8=%E2%9C%93&q=is%3Aopen+is%3Apr+label%3A%22mobile-web%22BEw
EmFFGGfhttps://app.getsentry.com/domo-mobile-web/mobilewebw
3ovv0workyx0HI
HlJut
JrKL
KJss
Lorr0
backgroundutIMN
MlOqp
OrPQ
PIoRno0gettodayappsgetTodayAppsRST
Somm0coreTUV
Uoll	0otherVWX
Wokk0workXYj
Yoii0
backgroundjn
Qohh0webappswebAppsqpNZ[
Zl\gf
\X]e^
]Id_c
d.sysoexecTEXTTEXT
_b`a
`mbbcc
open
aobb0webappwebAppce0webappwebApp
^oaa0webappswebAppsgf[de
dl`_^`_^efg
fl]\[]\[ghi
hlZjkZjIC ==================================================================kll ==================================================================imn
mlYopYo
 CONFIGUREpqq CONFIGUREnrs
rlXtuXtIC ==================================================================uvv ==================================================================swx
wlWVUWVUxyz
yl
{TS
{I
R|QR 0updateprogressupdateProgress|}P
}m~~(Configuring settingsPQTSz
lONMONM
lLL Turn off WiFi Turn off WiFi
lKJ
IIH
I.sysoexecTEXTTEXT
mJnetworksetup -setairportpower en0 offHKJ
lGFEGFE
lDD Run window manager& Run window manager
lCB
IA@
A.sysodelanullnmbr
m??@CB>
l5=<
O5
I4;
;.prcskcodnull****
m"::98
9
faal
J%0
m%(7
7eMdsKcmd
m(+6
6eMdsKopt5
m+.4
4eMdsKctl58
msevsalisMacintosh HD{H+ZKSystem Events.app]u	 CoreServices
ZKZJZI=Macintosh HD:System:Library:CoreServices:System Events.app$System Events.appMacintosh HD-System/Library/CoreServices/System Events.app/=<>3210/.-,3+*)('&%$#"! +0
progresssteps
progressSteps* 0updateprogressupdateProgress)0gettodayappsgetTodayApps
(.aevtoappnull****'0core&	0other%0work$0
background#0
nativeapps
nativeApps"0webappswebApps! 2
( 0updateprogressupdateProgress

dscr

dscr
.sysodelanullnmbr

ppga

ppgc$kjO*,FObkEcOb*,F]0gettodayappsgetTodayApps

	0core	0other
0work	0
background0core	0other0work0
background	0today
.misccurdldt null

wkdy

sun

sat /*j,EO	%Y%%Y
%%%
.aevtoappnull****
k5Q/HMZy0	nativeapp	nativeApp0webappwebApp?V"&*-7;?CFb~

ppgd

ppgt 0updateprogressupdateProgress0core	0other0work0
background0gettodayappsgetTodayApps0
nativeapps
nativeApps

kocl

cobj
.corecnte********

capp
.aevtoappnull****	0webappswebApps
.sysoexecTEXTTEXT
.sysodelanullnmbr

faal
eMdsKcmd
eMdsKopt
eMdsKctl
.prcskcodnull****6*,FOl*,FO*k+OvEOvEOjvE`OaaaaaaavE`O*__+E`O$_[aalkh*a/j[OYOa a!lvEOa"a#a$a%a&a'a(a)a*a+vEOa,a-a.a/a0a1vE`OjvE`O*__+E`2O#_2[aalkha3%j4[OYO*a5k+Oa6j4Okj7Oa8a9a:a;a<a=mvl>U		"&*-7;?CF

10/.-,ascrޭ

FasdUAS 1.101.10
k
lIC ==================================================================		 ==================================================================

l
	 PROGRESS
 PROGRESS
lIC ================================================================== ==================================================================
l
l
r
mDaily Sync
1

ppgd
l
r !
 m
!1

ppgt"#
"j$0
progresssteps
progressSteps
$m#%&
%i'(
'I) 0updateprogressupdateProgress)*
*1

dscr
(k#++,-
,I.
.sysodelanullnmbr
.m-/0
/r12
11

dscr
21

ppga034
3r56
5[78
7o0
progresssteps
progressSteps
8m
6o0
progresssteps
progressSteps49
9r#:;
:o0
progresssteps
progressSteps
;1"

ppgc&<=
<l=>?
>l?@A
@lBCBIC ==================================================================CDD ==================================================================AEF
ElGHG STARTHII STARTFJK
JlLMLIC ==================================================================MNN ==================================================================KOP
OlPQR
QlS
SIT 0updateprogressupdateProgressTU
Um
VVWW6Starting apps and processesRXY
XlYZ[
Zi
\]
\I^0gettodayappsgetTodayApps^_`
_o0core`ab
ao	0otherbcd
co0workde
eo0
background
]k.ffgh
gr	ij
inkl
km

wkdy
llm
mI
.misccurdldt null
jo	0todayhn
nZ
.opqr
ol

s
s=

tu
to
	0today
um

sun
pLv
vbwx
wo0core
xo0
backgroundqyz
yl{
{=|}
|o	0today
}m

sat z~
~L#
b"
b
o0core
o	0other
o !0
background
rL&.
b&-
b&+
b&)
o&'0core
o'(	0other
o)*0work
o+,0
background[
l
l Open native apps" Open native apps
l
r
J
mTodoist
mCalendar
mMessages
mMail
o0core
l$
r$
J"
mPhotos
mAnki
mSpotify
m
Slack
o	0other
l%+
r%+
J%'
o0work
l,F
r,F
J,B
m,/Google Drive
m/2(Google Photos Backup
m25Flux
m58
Slate
m8;Seil
m;>Karabiner
o0
background
lGX
rGX
IGT0gettodayappsgetTodayApps
oHI0core
oIJ	0other
oJM0work
oMP0
background
o0
nativeapps
nativeApps
lY~
XY~
Ioy
.aevtoappnull****
4ou

capp
ost0	nativeapp	nativeApp0	nativeapp	nativeApp
o\_0
nativeapps
nativeApps
l
l Open web apps Open web apps
l
r
J
m>http://www.apple.com/ios/health
m0https://myfitnesspal.com
o~~0core
l}|
r

	J

mHhttps://www.rescuetime.com/dashboard

m<https://wakatime.com/dashboard
m(https://www.mint.com
m,https://www.egghead.io
m0https://www.codewars.com !
 m""##$https://buffer.com!$%
$m&&''Thttps://www.youtube.com/feed/subscriptions%()
(m**++(https://facebook.com),{
,m--..&https://twitter.com{

ozz	0other}|/0
/l1yx
1r23
2J4456
5m7788@https://domo.demo.domo.com/inbox69:
9m;;<<6https://domo.domo.com/inbox:=>
=m??@@https://domo.okta.com/home/jira_onprem/0oa1moe1d0joaWP4P0x7/3549>AB
AmCCDDhttps://git.empdev.domo.com/pulls?utf8=%E2%9C%93&q=is%3Aopen+is%3Apr+label%3A%22mobile-web%22BEw
EmFFGGfhttps://app.getsentry.com/domo-mobile-web/mobilewebw
3ovv0workyx0HI
HlJut
JrKL
KJss
Lorr0
backgroundutIMN
MlOqp
OrPQ
PIoRno0gettodayappsgetTodayAppsRST
Somm0coreTUV
Uoll	0otherVWX
Wokk0workXYj
Yoii0
backgroundjn
Qohh0webappswebAppsqpNZ[
Zl\gf
\X]e^
]Id_c
d.sysoexecTEXTTEXT
_b`a
`mbbcc
open
aobb0webappwebAppce0webappwebApp
^oaa0webappswebAppsgf[de
dl`_^`_^efg
fl]\[]\[ghi
hlZjkZjIC ==================================================================kll ==================================================================imn
mlYopYo
 CONFIGUREpqq CONFIGUREnrs
rlXtuXtIC ==================================================================uvv ==================================================================swx
wlWVUWVUxyz
yl
{TS
{I
R|QR 0updateprogressupdateProgress|}P
}m~~(Configuring settingsPQTSz
lONMONM
lLL Turn off WiFi Turn off WiFi
lKJ
IIH
I.sysoexecTEXTTEXT
mJnetworksetup -setairportpower en0 offHKJ
lGFEGFE
lDD Run window manager& Run window manager
lCB
IA@
A.sysodelanullnmbr
m??@CB>
l5=<
O5
I4;
;.prcskcodnull****
m"::98
9
faal
J%0
m%(7
7eMdsKcmd
m(+6
6eMdsKopt5
m+.4
4eMdsKctl58
msevsalisMacintosh HD{H+ZKSystem Events.app]u	 CoreServices
ZKZJZI=Macintosh HD:System:Library:CoreServices:System Events.app$System Events.appMacintosh HD-System/Library/CoreServices/System Events.app/=<>3210/.-,3+*)('&%$#"! +0
progresssteps
progressSteps* 0updateprogressupdateProgress)0gettodayappsgetTodayApps
(.aevtoappnull****'0core&	0other%0work$0
background#0
nativeapps
nativeApps"0webappswebApps! 2( 0updateprogressupdateProgress

dscr

dscr
.sysodelanullnmbr

ppga

ppgc$kjO*,FObkEcOb*,F]0gettodayappsgetTodayApps

	0core	0other
0work	0
background0core	0other0work0
background	0today
.misccurdldt null

wkdy

sun

sat /*j,EO	%Y%%Y
%%%
.aevtoappnull****
k5Q/HMZy0	nativeapp	nativeApp0webappwebApp?V"&*-7;?CFb~

ppgd

ppgt 0updateprogressupdateProgress0core	0other0work0
background0gettodayappsgetTodayApps0
nativeapps
nativeApps

kocl

cobj
.corecnte********

capp
.aevtoappnull****	0webappswebApps
.sysoexecTEXTTEXT
.sysodelanullnmbr

faal
eMdsKcmd
eMdsKopt
eMdsKctl
.prcskcodnull****6*,FOl*,FO*k+OvEOvEOjvE`OaaaaaaavE`O*__+E`O$_[aalkh*a/j[OYOa a!lvEOa"a#a$a%a&a'a(a)a*a+vEOa,a-a.a/a0a1vE`OjvE`O*__+E`2O#_2[aalkha3%j4[OYO*a5k+Oa6j4Okj7Oa8a9a:a;a<a=mvl>U		"&*-7;?CF"&*-7;?CF10/.-,ascrޭ


don't iterate over every doc in app documents

#!/usr/bin/osascript

on run argv
	set idx to item 1 of argv
    if application "Deckset" is running
        tell application "Deckset"
            tell first item of documents
                set slideIndex to idx
            end tell
        end tell
    end if
end run

#!/usr/bin/osascript

on run argv
	set idx to item 1 of argv
    if application "Deckset" is running
        tell application "Deckset"
            repeat with doc in documents
                tell doc
                	set slideIndex to idx
                end tell
            end repeat
        end tell
    end if
end run


Remove obsolete fileWrite() handler

Remove obsolete fileWrite() handler

-- core configuration --

-- configurable options --

-- limit number of songs to improve efficiency
property resultLimit : 15
-- whether or not to retrieve/display album artwork for each result
property albumArtEnabled : true

-- workflow parameters --

-- workflow folders
property libraryFolder : (path to library folder from user domain as text)
property cacheFolder : (libraryFolder & "Caches:")
property alfredWorkflowDataFolder : (cacheFolder & "com.runningwithcrayons.Alfred:Workflow Data:")
property bundleId : "com.calebevans.playsong"
property workflowCacheFolder : (alfredWorkflowDataFolder & bundleId & ":") as text

-- album artwork folders
property artworkDocsFolder : ((get path to library folder from user domain as text) & "Containers:com.apple.AMPArtworkAgent:Data:Documents")
property artworkImageFolder : (artworkDocsFolder & ":artwork:")

-- the default icon used for search results without album artwork
property defaultIconName : "resources/icon-noartwork.png"
-- the name of the playlist used by the workflow for playing songs
property workflowPlaylistName : "Alfred Play Song"
-- list of Alfred results
property resultList : {}

-- replaces substring in string with another substring
on replace(replaceThis, replaceWith, theString)

	set oldDelims to AppleScript's text item delimiters
	set AppleScript's text item delimiters to replaceThis
	set strItems to text items of theString
	set AppleScript's text item delimiters to replaceWith
	set newString to strItems as text
	set AppleScript's text item delimiters to oldDelims
	return newString

end replace

-- retrieve the plural/singular form of a quantity based on the given number
on quantifyNumber(theNumber, quantityName, pluralQuantityName)

	if theNumber is 1 then

		set theString to (theNumber as text) & space & quantityName

	else

		set theString to (theNumber as text) & space & pluralQuantityName

	end if

	return theString

end quantifyNumber

-- encodes JSON reserved characters in the given string
on encodeFeedbackChars(theString)

	set theString to replace("\\", "\\\\", theString)
	set theString to replace("\"", "\\\"", theString)
	return theString

end encodeFeedbackChars

-- decodes JSON reserved characters in the given string
on decodeFeedbackChars(theString)

	set theString to replace("\\\\", "\\", theString)
	set theString to replace("\\\"", "\"", theString)
	return theString

end decodeFeedbackChars

-- adds Alfred result to result list
on addResult(theResult)

	copy theResult to the end of resultList

end addResult

-- adds item for "No Results" message
on addNoResultsItem(query, queryType)

	addResult({uid:"no-results", valid:"no", title:"No Results Found", subtitle:("No " & queryType & "s matching '" & query & "'"), icon:defaultIconName})

end addNoResultsItem

on resultListIsFull()

	return (length of resultList is resultLimit)

end resultListIsFull

on resultListIsEmpty()

	return (length of resultList is 0)

end resultListIsFull

-- builds Alfred result item as JSON
on getResultFeedback(theResult)

	-- encode reserved JSON characters
	set resultUid to encodeFeedbackChars(uid of theResult)
	set resultValid to (valid of theResult) as text
	set resultTitle to encodeFeedbackChars(title of theResult)
	set resultSubtitle to encodeFeedbackChars(subtitle of theResult)

	if (icon of theResult) contains ":" then

		set resultIcon to encodeFeedbackChars(POSIX path of icon of theResult)

	else

		set resultIcon to icon of theResult

	end if

	set json to "{"
	set json to json & "\"uid\":\"" & resultUid & "\","
	set json to json & "\"arg\":\"" & resultUid & "\","
	set json to json & "\"valid\":\"" & resultValid & "\","
	set json to json & "\"title\":\"" & resultTitle & "\","
	set json to json & "\"subtitle\":\"" & resultSubtitle & "\","
	set json to json & "\"icon\":{\"path\":\"" & resultIcon & "\"}"
	set json to json & "}"
	return json

end getResultFeedback

-- retrieves JSON document for Alfred results
on getResultListFeedback()

	set json to "{\"items\": ["

	repeat with theResult in resultList

		set json to json & getResultFeedback(theResult)
		set json to json & ","

	end repeat

	-- remove trailing comma after last item
	set json to text 1 thru (length of json - 1) of json
	set json to json & "]}"
	return json

end getResultListFeedback

-- query path to artwork image file cached natively by Music.app in Catalina
on getSongArtworkPath(theSong)

	try

		if albumArtEnabled is false then return defaultIconName

		tell application "Music"

			-- get persistent ID of song and convert from hexadecimal to decimal (base-10)
			set hexSongId to persistent ID of theSong
			set decSongId to (do shell script "echo $((16#" & hexSongId & "))")

			-- retrieve filename of cached artwork (without extension)
			set artworkName to (do shell script ("/usr/bin/sqlite3 " & (POSIX path of artworkDocsFolder) & "/artworkd.sqlite '" & ¬
			"select ZHASHSTRING, ZKIND from ZIMAGEINFO where Z_PK = (" & ¬
			"(select ZIMAGEINFO from ZSOURCEINFO where Z_PK = (" & ¬
			"select ZSOURCEINFO from ZDATABASEITEMINFO where ZPERSISTENTID = " & ¬
			decSongId & ")))' | " & ¬
			"awk '{split($0,a,\"|\"); print a[1] \"_sk_\" a[2] \"_cid_1\"}'"))

			set artworkPath to (artworkImageFolder & artworkName)

		end tell

		return selectFirstArtworkThatExists({ ¬
			(artworkImageFolder & artworkName & ".jpeg"), ¬
			(artworkImageFolder & artworkName & ".png")}) of me

	on error errorMessage

		log errorMessage

	end try

end getSongArtworkPath

-- select the first path (in the given set of artwork paths) that exists on the
-- user's local system
on selectFirstArtworkThatExists(artworkPaths)

	tell application "Finder"
		repeat with artworkPath in artworkPaths
			if artworkPath exists then
				return artworkPath as text
			end if
		end repeat
	end tell

	return defaultIconName

end selectFirstArtworkThatExists

-- creates album artwork cache
on createWorkflowPlaylist()

	tell application "Music"

		if not (user playlist workflowPlaylistName exists) then

			make new user playlist with properties {name:workflowPlaylistName, shuffle:false}

		end if

	end tell

end createWorkflowPlaylist

on clearQueue()

	tell application "Music"

		if user playlist workflowPlaylistName exists then

			delete tracks of user playlist workflowPlaylistName

		end if

	end tell

end clearQueue

on queueSongs(theSongs)

	tell application "Music"

		repeat with theSong in theSongs

			duplicate theSong to user playlist workflowPlaylistName

		end repeat

	end tell

end queueSongs

on playQueue()

	tell application "Music"

		if number of tracks in user playlist workflowPlaylistName is not 0 then

			play user playlist workflowPlaylistName

		end if

	end tell

end playQueue

on getPlaylist(playlistId)

	tell application "Music"

		return (first playlist whose id is playlistId)

	end tell

end getPlaylist

on getPlaylistSongs(playlistId)

	tell application "Music"

		set thePlaylist to getPlaylist(playlistId) of me
		set playlistSongs to every track of thePlaylist

	end tell

	return playlistSongs

end getPlaylistSongs

-- retrieves list of artist names for the given genre
on getGenreArtists(genreName)

	tell application "Music"

		set genreSongs to every track of playlist 2 whose genre is genreName
		set artistNames to {}

		repeat with theSong in genreSongs

			if (artist of theSong) is not in artistNames then

				set artistNames to artistNames & (artist of theSong)

			end if

		end repeat

	end tell

	return artistNames

end getGenreArtists

-- retrieves list of songs within the given genre, sorted by artist
on getGenreSongs(genreName)

	set artistNames to getGenreArtists(genreName) of me
	set genreSongs to {}

	repeat with artistName in artistNames

		set genreSongs to genreSongs & getArtistSongs(artistName) of me

	end repeat

	return genreSongs

end getGenreSongs

-- retrieves list of album names for the given artist
on getArtistAlbums(artistName)

	tell application "Music"

		set artistSongs to every track of playlist 2 whose artist is artistName
		set albumNames to {}

		repeat with theSong in artistSongs

			if (album of theSong) is not in albumNames then

				set albumNames to albumNames & (album of theSong)

			end if

		end repeat

	end tell

	return albumNames

end getArtistAlbums

-- retrieves list of songs by the given artist, sorted by album
on getArtistSongs(artistName)

	tell application "Music"

		set albumNames to getArtistAlbums(artistName) of me
		set artistSongs to {}

		repeat with albumName in albumNames

			set albumSongs to (every track of playlist 2 whose artist is artistName and album is albumName)
			set artistSongs to artistSongs & albumSongs

		end repeat

	end tell

	return artistSongs

end getArtistSongs

-- retrieves list of songs in the given album
on getAlbumSongs(albumName)

	tell application "Music"

		set albumSongs to every track of playlist 2 whose album is albumName

	end tell

	return albumSongs

end getAlbumSongs

-- retrieves the song with the given ID
on getSong(songId)

	tell application "Music"

		set theSong to first track of playlist 2 whose database ID is songId

	end tell

	return theSong

end getSong

-- retrieves a list of objects or names matching the given query and type
on getResultsFromQuery(query, queryType)

	set evalScript to run script "
	script

		on findResults(query, queryType, resultLimit)

			tell application \"Music\"

				set theSongs to (get every track in playlist 2 whose " & queryType & " starts with query)

				if length of theSongs < resultLimit then

					set theSongs to theSongs & (get every track in playlist 2 whose " & queryType & " contains (space & query) and " & queryType & " does not start with query)

				end if

				if length of theSongs < resultLimit then

					set theSongs to theSongs & (get every track in playlist 2 whose " & queryType & " contains query and " & queryType & " does not start with query and " & queryType & " does not contain (space & query))

				end if

				if length of theSongs is 0 then

					if queryType is \"name\" then

						set theSongs to theSongs & (search playlist 2 for query only songs)

					else if queryType is not \"genre\" then

						set theSongs to theSongs & (search playlist 2 for query only " & queryType & "s)

					end if

				end if

				if queryType is \"name\" then

					if length of theSongs > resultLimit then

						set theSongs to items 1 thru resultLimit of theSongs

					end if

					set theResults to theSongs

				else

					set theResults to {}

					repeat with theSong in theSongs

						if length of theResults is resultLimit then exit repeat

						set theResult to " & queryType & " of theSong

						if theResult is not in theResults then

							set theResults to theResults & theResult

						end if

					end repeat

				end if

			end tell

			return theResults

		end findResults

	end script
	"

	evalScript's findResults(query, queryType, resultLimit)

end getResultsFromQuery

-- returns the given string with leading and trailing whitespace removed
on trimWhitespace(theString)

	-- trim leading whitespace
	repeat while theString begins with space

		if length of theString is 1 then return ""
		set theString to text 2 thru end of theString

	end repeat

	-- trim trailing whitespace
	repeat while theString ends with space

		set theString to text 1 thru ((length of theString) - 1) of theString

	end repeat

	return theString

end trimWhitespace

-- queues the song with the given ID
on queueSong(songId)

	set theSong to getSong(songId)
	queueSongs({theSong})

end queueSong

-- queues all songs belonging to the given album
on queueAlbum(albumName)

	set albumName to decodeFeedbackChars(albumName)
	set albumSongs to getAlbumSongs(albumName)
	queueSongs(albumSongs)

end queueAlbum

-- queues all songs by the given artist
on queueArtist(artistName)

	set artistName to decodeFeedbackChars(artistName)
	set artistSongs to getArtistSongs(artistName)
	queueSongs(artistSongs)

end queueArtist

-- queues all songs within the given genre
on queueGenre(genreName)

	set genreName to decodeFeedbackChars(genreName)
	set genreSongs to getGenreSongs(genreName)
	queueSongs(genreSongs)

end queueGenre

-- queues all songs in the given playlist
on queuePlaylist(playlistId)

	set playlistSongs to getPlaylistSongs(playlistId)
	queueSongs(playlistSongs)

end queuePlaylist

-- parses the given result query to retrieve type and id of item to queue
on parseResultQuery(query)

	set pos to offset of "-" in query
	set theType to text 1 thru (pos - 1) of query
	set theId to text (pos + 1) thru end of query
	return {type:theType, id:theId}

end parseResultQuery

on queue(query)

	set typeAndId to parseResultQuery(query)
	set theType to type of typeAndId
	set theId to id of typeAndId

	createWorkflowPlaylist()

	if theType is "song" then
		queueSong(theId)
	else if theType is "album" then
		queueAlbum(theId)
	else if theType is "artist" then
		queueArtist(theId)
	else if theType is "genre" then
		queueGenre(theId)
	else if theType is "playlist" then
		queuePlaylist(theId)
	else
		log "Unsupported type: " & theType
	end if

end queue

on play(query)

	clearQueue()
	queue(query)
	playQueue()

end play

-- core configuration --

-- configurable options --

-- limit number of songs to improve efficiency
property resultLimit : 15
-- whether or not to retrieve/display album artwork for each result
property albumArtEnabled : true

-- workflow parameters --

-- workflow folders
property libraryFolder : (path to library folder from user domain as text)
property cacheFolder : (libraryFolder & "Caches:")
property alfredWorkflowDataFolder : (cacheFolder & "com.runningwithcrayons.Alfred:Workflow Data:")
property bundleId : "com.calebevans.playsong"
property workflowCacheFolder : (alfredWorkflowDataFolder & bundleId & ":") as text

-- album artwork folders
property artworkDocsFolder : ((get path to library folder from user domain as text) & "Containers:com.apple.AMPArtworkAgent:Data:Documents")
property artworkImageFolder : (artworkDocsFolder & ":artwork:")

-- the default icon used for search results without album artwork
property defaultIconName : "resources/icon-noartwork.png"
-- the name of the playlist used by the workflow for playing songs
property workflowPlaylistName : "Alfred Play Song"
-- list of Alfred results
property resultList : {}

-- replaces substring in string with another substring
on replace(replaceThis, replaceWith, theString)

	set oldDelims to AppleScript's text item delimiters
	set AppleScript's text item delimiters to replaceThis
	set strItems to text items of theString
	set AppleScript's text item delimiters to replaceWith
	set newString to strItems as text
	set AppleScript's text item delimiters to oldDelims
	return newString

end replace

-- retrieve the plural/singular form of a quantity based on the given number
on quantifyNumber(theNumber, quantityName, pluralQuantityName)

	if theNumber is 1 then

		set theString to (theNumber as text) & space & quantityName

	else

		set theString to (theNumber as text) & space & pluralQuantityName

	end if

	return theString

end quantifyNumber

-- encodes JSON reserved characters in the given string
on encodeFeedbackChars(theString)

	set theString to replace("\\", "\\\\", theString)
	set theString to replace("\"", "\\\"", theString)
	return theString

end encodeFeedbackChars

-- decodes JSON reserved characters in the given string
on decodeFeedbackChars(theString)

	set theString to replace("\\\\", "\\", theString)
	set theString to replace("\\\"", "\"", theString)
	return theString

end decodeFeedbackChars

-- adds Alfred result to result list
on addResult(theResult)

	copy theResult to the end of resultList

end addResult

-- adds item for "No Results" message
on addNoResultsItem(query, queryType)

	addResult({uid:"no-results", valid:"no", title:"No Results Found", subtitle:("No " & queryType & "s matching '" & query & "'"), icon:defaultIconName})

end addNoResultsItem

on resultListIsFull()

	return (length of resultList is resultLimit)

end resultListIsFull

on resultListIsEmpty()

	return (length of resultList is 0)

end resultListIsFull

-- builds Alfred result item as JSON
on getResultFeedback(theResult)

	-- encode reserved JSON characters
	set resultUid to encodeFeedbackChars(uid of theResult)
	set resultValid to (valid of theResult) as text
	set resultTitle to encodeFeedbackChars(title of theResult)
	set resultSubtitle to encodeFeedbackChars(subtitle of theResult)

	if (icon of theResult) contains ":" then

		set resultIcon to encodeFeedbackChars(POSIX path of icon of theResult)

	else

		set resultIcon to icon of theResult

	end if

	set json to "{"
	set json to json & "\"uid\":\"" & resultUid & "\","
	set json to json & "\"arg\":\"" & resultUid & "\","
	set json to json & "\"valid\":\"" & resultValid & "\","
	set json to json & "\"title\":\"" & resultTitle & "\","
	set json to json & "\"subtitle\":\"" & resultSubtitle & "\","
	set json to json & "\"icon\":{\"path\":\"" & resultIcon & "\"}"
	set json to json & "}"
	return json

end getResultFeedback

-- retrieves JSON document for Alfred results
on getResultListFeedback()

	set json to "{\"items\": ["

	repeat with theResult in resultList

		set json to json & getResultFeedback(theResult)
		set json to json & ","

	end repeat

	-- remove trailing comma after last item
	set json to text 1 thru (length of json - 1) of json
	set json to json & "]}"
	return json

end getResultListFeedback

-- writes the given content to the given file
on fileWrite(theFile, theContent)

	set fileRef to open for access theFile with write permission
	try
		set eof of fileRef to 0
		write theContent to fileRef starting at eof
		close access fileRef
	on error
		close access fileRef
	end try

end fileWrite

-- query path to artwork image file cached natively by Music.app in Catalina
on getSongArtworkPath(theSong)

	try

		if albumArtEnabled is false then return defaultIconName

		tell application "Music"

			-- get persistent ID of song and convert from hexadecimal to decimal (base-10)
			set hexSongId to persistent ID of theSong
			set decSongId to (do shell script "echo $((16#" & hexSongId & "))")

			-- retrieve filename of cached artwork (without extension)
			set artworkName to (do shell script ("/usr/bin/sqlite3 " & (POSIX path of artworkDocsFolder) & "/artworkd.sqlite '" & ¬
			"select ZHASHSTRING, ZKIND from ZIMAGEINFO where Z_PK = (" & ¬
			"(select ZIMAGEINFO from ZSOURCEINFO where Z_PK = (" & ¬
			"select ZSOURCEINFO from ZDATABASEITEMINFO where ZPERSISTENTID = " & ¬
			decSongId & ")))' | " & ¬
			"awk '{split($0,a,\"|\"); print a[1] \"_sk_\" a[2] \"_cid_1\"}'"))

			set artworkPath to (artworkImageFolder & artworkName)

		end tell

		return selectFirstArtworkThatExists({ ¬
			(artworkImageFolder & artworkName & ".jpeg"), ¬
			(artworkImageFolder & artworkName & ".png")}) of me

	on error errorMessage

		log errorMessage

	end try

end getSongArtworkPath

-- select the first path (in the given set of artwork paths) that exists on the
-- user's local system
on selectFirstArtworkThatExists(artworkPaths)

	tell application "Finder"
		repeat with artworkPath in artworkPaths
			if artworkPath exists then
				return artworkPath as text
			end if
		end repeat
	end tell

	return defaultIconName

end selectFirstArtworkThatExists

-- creates album artwork cache
on createWorkflowPlaylist()

	tell application "Music"

		if not (user playlist workflowPlaylistName exists) then

			make new user playlist with properties {name:workflowPlaylistName, shuffle:false}

		end if

	end tell

end createWorkflowPlaylist

on clearQueue()

	tell application "Music"

		if user playlist workflowPlaylistName exists then

			delete tracks of user playlist workflowPlaylistName

		end if

	end tell

end clearQueue

on queueSongs(theSongs)

	tell application "Music"

		repeat with theSong in theSongs

			duplicate theSong to user playlist workflowPlaylistName

		end repeat

	end tell

end queueSongs

on playQueue()

	tell application "Music"

		if number of tracks in user playlist workflowPlaylistName is not 0 then

			play user playlist workflowPlaylistName

		end if

	end tell

end playQueue

on getPlaylist(playlistId)

	tell application "Music"

		return (first playlist whose id is playlistId)

	end tell

end getPlaylist

on getPlaylistSongs(playlistId)

	tell application "Music"

		set thePlaylist to getPlaylist(playlistId) of me
		set playlistSongs to every track of thePlaylist

	end tell

	return playlistSongs

end getPlaylistSongs

-- retrieves list of artist names for the given genre
on getGenreArtists(genreName)

	tell application "Music"

		set genreSongs to every track of playlist 2 whose genre is genreName
		set artistNames to {}

		repeat with theSong in genreSongs

			if (artist of theSong) is not in artistNames then

				set artistNames to artistNames & (artist of theSong)

			end if

		end repeat

	end tell

	return artistNames

end getGenreArtists

-- retrieves list of songs within the given genre, sorted by artist
on getGenreSongs(genreName)

	set artistNames to getGenreArtists(genreName) of me
	set genreSongs to {}

	repeat with artistName in artistNames

		set genreSongs to genreSongs & getArtistSongs(artistName) of me

	end repeat

	return genreSongs

end getGenreSongs

-- retrieves list of album names for the given artist
on getArtistAlbums(artistName)

	tell application "Music"

		set artistSongs to every track of playlist 2 whose artist is artistName
		set albumNames to {}

		repeat with theSong in artistSongs

			if (album of theSong) is not in albumNames then

				set albumNames to albumNames & (album of theSong)

			end if

		end repeat

	end tell

	return albumNames

end getArtistAlbums

-- retrieves list of songs by the given artist, sorted by album
on getArtistSongs(artistName)

	tell application "Music"

		set albumNames to getArtistAlbums(artistName) of me
		set artistSongs to {}

		repeat with albumName in albumNames

			set albumSongs to (every track of playlist 2 whose artist is artistName and album is albumName)
			set artistSongs to artistSongs & albumSongs

		end repeat

	end tell

	return artistSongs

end getArtistSongs

-- retrieves list of songs in the given album
on getAlbumSongs(albumName)

	tell application "Music"

		set albumSongs to every track of playlist 2 whose album is albumName

	end tell

	return albumSongs

end getAlbumSongs

-- retrieves the song with the given ID
on getSong(songId)

	tell application "Music"

		set theSong to first track of playlist 2 whose database ID is songId

	end tell

	return theSong

end getSong

-- retrieves a list of objects or names matching the given query and type
on getResultsFromQuery(query, queryType)

	set evalScript to run script "
	script

		on findResults(query, queryType, resultLimit)

			tell application \"Music\"

				set theSongs to (get every track in playlist 2 whose " & queryType & " starts with query)

				if length of theSongs < resultLimit then

					set theSongs to theSongs & (get every track in playlist 2 whose " & queryType & " contains (space & query) and " & queryType & " does not start with query)

				end if

				if length of theSongs < resultLimit then

					set theSongs to theSongs & (get every track in playlist 2 whose " & queryType & " contains query and " & queryType & " does not start with query and " & queryType & " does not contain (space & query))

				end if

				if length of theSongs is 0 then

					if queryType is \"name\" then

						set theSongs to theSongs & (search playlist 2 for query only songs)

					else if queryType is not \"genre\" then

						set theSongs to theSongs & (search playlist 2 for query only " & queryType & "s)

					end if

				end if

				if queryType is \"name\" then

					if length of theSongs > resultLimit then

						set theSongs to items 1 thru resultLimit of theSongs

					end if

					set theResults to theSongs

				else

					set theResults to {}

					repeat with theSong in theSongs

						if length of theResults is resultLimit then exit repeat

						set theResult to " & queryType & " of theSong

						if theResult is not in theResults then

							set theResults to theResults & theResult

						end if

					end repeat

				end if

			end tell

			return theResults

		end findResults

	end script
	"

	evalScript's findResults(query, queryType, resultLimit)

end getResultsFromQuery

-- returns the given string with leading and trailing whitespace removed
on trimWhitespace(theString)

	-- trim leading whitespace
	repeat while theString begins with space

		if length of theString is 1 then return ""
		set theString to text 2 thru end of theString

	end repeat

	-- trim trailing whitespace
	repeat while theString ends with space

		set theString to text 1 thru ((length of theString) - 1) of theString

	end repeat

	return theString

end trimWhitespace

-- queues the song with the given ID
on queueSong(songId)

	set theSong to getSong(songId)
	queueSongs({theSong})

end queueSong

-- queues all songs belonging to the given album
on queueAlbum(albumName)

	set albumName to decodeFeedbackChars(albumName)
	set albumSongs to getAlbumSongs(albumName)
	queueSongs(albumSongs)

end queueAlbum

-- queues all songs by the given artist
on queueArtist(artistName)

	set artistName to decodeFeedbackChars(artistName)
	set artistSongs to getArtistSongs(artistName)
	queueSongs(artistSongs)

end queueArtist

-- queues all songs within the given genre
on queueGenre(genreName)

	set genreName to decodeFeedbackChars(genreName)
	set genreSongs to getGenreSongs(genreName)
	queueSongs(genreSongs)

end queueGenre

-- queues all songs in the given playlist
on queuePlaylist(playlistId)

	set playlistSongs to getPlaylistSongs(playlistId)
	queueSongs(playlistSongs)

end queuePlaylist

-- parses the given result query to retrieve type and id of item to queue
on parseResultQuery(query)

	set pos to offset of "-" in query
	set theType to text 1 thru (pos - 1) of query
	set theId to text (pos + 1) thru end of query
	return {type:theType, id:theId}

end parseResultQuery

on queue(query)

	set typeAndId to parseResultQuery(query)
	set theType to type of typeAndId
	set theId to id of typeAndId

	createWorkflowPlaylist()

	if theType is "song" then
		queueSong(theId)
	else if theType is "album" then
		queueAlbum(theId)
	else if theType is "artist" then
		queueArtist(theId)
	else if theType is "genre" then
		queueGenre(theId)
	else if theType is "playlist" then
		queuePlaylist(theId)
	else
		log "Unsupported type: " & theType
	end if

end queue

on play(query)

	clearQueue()
	queue(query)
	playQueue()

end play


fixed process_fullAccessToggle bug

fixed process_fullAccessToggle bug

-- HTC sous-dev
-- 2017-05-03, Erik Shagdar, NYHTC

-- written against OS X 10.10.5 and FileMaker 15.0.3

(*
	2017-10-19 ( eshagdar ): open data viewer. open manage DB. 'added Functions Open' process
	2017-10-17 ( eshagdar ): update 'promptProcess' to show credential expiration TS.
	2017-10-16 ( eshagdar ): converted app to source files.
	2017-05-03 ( eshagdar ): created.
*)

property AppletName : "HTC sous-dev"
property htcLibURL : "https://github.com/NYHTC/applescript-fm-helper"

property debugMode : false
property logging : false

property orgNumLIST : {1, 2}

property idleTime : 5 * minutes

property credentialsTimeout : 2 * hours
property credentialsUpdatedTS : (current date) - credentialsTimeout
property fullAccessCredentials : {}
property userCredentials : {}

use htcBasic : script "htcBasic"
use credentialsLib : script "credentials"
use privSetLib : script "privSet"
use scripting additions

on run prefs
	if logging then htcBasic's logToConsole("Here I am")
	mainScript(prefs)
end run

on reopen prefs
	mainScript(prefs)
end reopen

on idle
	credentialsLib's credentialsCheck({})
	return idleTime -- sets idle time to specified time ( instead of the default of 30 seconds )
end idle

on quit
	process_quit({})
end quit

on mainScript(prefs)
	-- main script to determine what to run

	-- 2017-10-23 ( eshagdar ): added prefs. moved processes into separate handlers.
	-- 2017-xx-xx ( eshagdar ): created

	try
		-- pick up prefs, if specified
		set defaultPrefs to {null}
		try
			if class of prefs is script or prefs is equal to {} then set prefs to defaultPrefs
		on error
			set prefs to defaultPrefs
		end try

		-- launch htcLib
		launchHtcLib({})

		-- credentials debugging
		if debugMode then htcBasic's debugMsg("mainScript ---" & return &
			"fullAccessCredentials: " & htcBasic's coerceToString(fullAccessCredentials) & return &
			"userCredentials: " & htcBasic's coerceToString(userCredentials))

		-- ensure credentials are not outdated
		credentialsLib's credentialsEnsure({})

		-- prompt user what to do
		set process to item 1 of prefs
		return runProcess({process:process})
	on error errMsg number errNum
		tell it to activate
		tell application "htcLib" to set errStack to replaceSimple({sourceTEXT:errMsg, oldChars:" - ", newChars:return})
		set ignoreErrorNumList to {-128, -1024, -1719}
		(*
			-128: user cancel
			-1024: generic error
			-1719: assistive device
		*)
		if errNum is not in ignoreErrorNumList then set errStack to errStack & " ( errNum: " & errNum & " )"
		htcBasic's showUserError(errStack)
	end try
end mainScript

on launchHtcLib(prefs)
	-- attempt to open htcLib. if it doesn't exist, navigate user to github

	-- 2017-06-28 ( eshagdar ): create

	set openName to "Get it!"

	try
		if logging then htcBasic's logToConsole("launching htcLib")
		tell application "htcLib" to launch
	on error errMsg number errNum
		set missingAppDialog to display dialog "You do Not have the htcLib installed." with title AppletName buttons {"Cancel", openName} default button openName
		if button returned of missingAppDialog is openName then open location htcLibURL
		error "unable to launchHtcLib - " & errMsg number errNum
	end try
end launchHtcLib

on promptProcess(prefs)
	-- user user for which process to do

	-- 2017-10-17 ( eshagdar ): add expiration TS to prompt.
	-- 2017-06-28 ( eshagdar ): created

	set defaultPrefs to {processList:{}}
	set prefs to prefs & defaultPrefs

	try
		if logging then htcBasic's logToConsole("About to ask user to process")
		set promptProcessDialog to (choose from list processList of prefs with title AppletName with prompt "Creds expire: " & time string of (credentialsUpdatedTS + credentialsTimeout) & return & return & "Select a process to run:" OK button name "Run" without multiple selections allowed and empty selection allowed)
		if promptProcessDialog is false then return promptProcessDialog
		set processName to item 1 of promptProcessDialog
		if logging then htcBasic's logToConsole("Process: " & processName)
		return processName

	on error errMsg number errNum
		error "unable to promptProcess - " & errMsg number errNum
	end try
end promptProcess

on runProcess(prefs)
	-- run process specified by the user

	-- 2017-10-18 ( eshagdar ): added quit process
	-- 2017-06-28 ( eshagdar ): created.

	try
		set processList to {
			"DO NOTHING",
			"Full Access Toggle",
			"Db Manage",
			"Functions Open",
			"Security Open",
			"Security Save",
			"PrivSet - copy settings to other PrivSets",
			"New table",
			"Data Viewer",
			"Clipboard Clear",
			"Credentials Update",
			"QUIT"}
		set oneProcess to promptProcess({processList:processList})

		if oneProcess is equal to "DO NOTHING" or oneProcess is equal to false then
			return true

		else if oneProcess is equal to "Full Access Toggle" then
			return process_fullAccessToggle({})

		else if oneProcess is equal to "Db Manage" then
			return process_manageDB({})

		else if oneProcess is equal to "Functions Open" then
			return process_functionsOpen({})

		else if oneProcess is equal to "Security Open" then
			return process_securityOpen({})

		else if oneProcess is equal to "Security Save" then
			return process_securitySave({})

		else if oneProcess is equal to "PrivSet - copy settings to other PrivSets" then
			return process_PrivSetCopy({})

		else if oneProcess is equal to "New table" then
			display dialog "This process is not yet finished" with title AppletName buttons "OK" default button "OK"
			return true

		else if oneProcess is equal to "Data Viewer" then
			return process_dataViewerOpen({})

		else if oneProcess is equal to "Clipboard Clear" then
			return process_ClipboardClear({})

		else if oneProcess is equal to "Credentials Update" then
			return process_credentialsUpdate({})

		else if oneProcess is equal to "QUIT" then
			return process_quit({})

		else
			error "unknown process '" & oneProcess & "'" number -1024
		end if
	on error errMsg number errNum
		error "unable to runProcess - " & errMsg number errNum
	end try
end runProcess

on process_fullAccessToggle(prefs)
	-- wrapper for htcLib handler that toggles between full access and user account

	-- 2017-10-17 ( eshagdar ): moved function into htcLib and converted this to a wrapper

	try
		tell application "htcLib" to return fmGUI_fullAccessToggle(prefs & fullAccessCredentials & userCredentials)
	on error errMsg number errNum
		error "unable to process_fullAccessToggle - " & errMsg number errNum
	end try
end process_fullAccessToggle

on process_manageDB(prefs)
	-- wrapper for opening manage DB

	-- 2017-10-23 ( eshagdar ): moved from runProcess into a separate handler

	try
		set fullAccessToggle to process_fullAccessToggle({ensureMode:"full"})
		tell application "htcLib"
			fmGUI_Menu_OpenDB({})
			windowWaitUntil({windowName:"Manage Database for", whichWindow:"front", windowNameTest:"does not contain", waitCycleDelaySeconds:1, waitCycleMax:30 * minutes})
		end tell
		if modeSwitch of fullAccessToggle then process_fullAccessToggle({})

		return true
	on error errMsg number errNum
		error "unable to process_manageDB - " & errMsg number errNum
	end try
end process_manageDB

on process_functionsOpen(prefs)
	-- wrapper for opening custom functions

	-- 2017-10-23 ( eshagdar ): moved from runProcess into a separate handler

	try
		fullAccessToggle({ensureMode:"full"})
		tell application "htcLib" to return fmGUI_CustomFunctions_Open({})
	on error errMsg number errNum
		error "unable to process_functionsOpen - " & errMsg number errNum
	end try
end process_functionsOpen

on process_securityOpen(prefs)
	-- wrapper for opening security

	-- 2017-10-23 ( eshagdar ): moved from runProcess into a separate handler

	try
		fullAccessToggle({ensureMode:"full"})
		tell application "htcLib" to return fmGUI_ManageSecurity_GoToTab_PrivSets(fullAccessCredentials)
	on error errMsg number errNum
		error "unable to process_securityOpen - " & errMsg number errNum
	end try
end process_securityOpen

on process_securitySave(prefs)
	-- wrapper for saving security

	-- 2017-10-23 ( eshagdar ): moved from runProcess into a separate handler

	try
		tell application "htcLib"
			fmGUI_AppFrontMost()
			return fmGUI_ManageSecurity_Save(fullAccessCredentials)
		end tell
	on error errMsg number errNum
		error "unable to process_securitySave - " & errMsg number errNum
	end try
end process_securitySave

on process_PrivSetCopy(prefs)
	-- wrapper for copying a selected privSet

	-- 2017-10-23 ( eshagdar ): moved from runProcess into a separate handler

	try
		set fullAccessToggle to process_fullAccessToggle({ensureMode:"full"})
		privSetLib's copyPrivSetToOthers({})
		if modeSwitch of fullAccessToggle then process_fullAccessToggle({})
	on error errMsg number errNum
		error "unable to process_PrivSetCopy - " & errMsg number errNum
	end try
end process_PrivSetCopy

on process_dataViewerOpen(prefs)
	-- wrapper for opening the data viewer

	-- 2017-10-23 ( eshagdar ): moved from runProcess into a separate handler

	try
		tell application "htcLib" to return fmGUI_DataViewer_Open(fullAccessCredentials)
	on error errMsg number errNum
		error "unable to process_dataViewerOpen - " & errMsg number errNum
	end try
end process_dataViewerOpen

on process_ClipboardClear(prefs)
	-- wrapper for clearing the clipboard

	-- 2017-10-23 ( eshagdar ): moved from runProcess into a separate handler

	try
		set the clipboard to null
		return true
	on error errMsg number errNum
		error "unable to process_ClipboardClear - " & errMsg number errNum
	end try
end process_ClipboardClear

on process_credentialsUpdate(prefs)
	-- wrapper for updating credentials

	-- 2017-10-23 ( eshagdar ): moved from runProcess into a separate handler

	try
		return credentialsLib's credentialsUpdate(fullAccessCredentials & userCredentials)
	on error errMsg number errNum
		error "unable to process_credentialsUpdate - " & errMsg number errNum
	end try
end process_credentialsUpdate

on process_quit(prefs)
	-- wrapper for quiting applet

	-- 2017-10-23 ( eshagdar ): moved from runProcess into a separate handler

	try
		credentialsLib's credentialsCheck({forceClear:true})
		continue quit
	on error errMsg number errNum
		error "unable to process_quit - " & errMsg number errNum
	end try
end process_quit

-- HTC sous-dev
-- 2017-05-03, Erik Shagdar, NYHTC

-- written against OS X 10.10.5 and FileMaker 15.0.3

(*
	2017-10-19 ( eshagdar ): open data viewer. open manage DB. 'added Functions Open' process
	2017-10-17 ( eshagdar ): update 'promptProcess' to show credential expiration TS.
	2017-10-16 ( eshagdar ): converted app to source files.
	2017-05-03 ( eshagdar ): created.
*)

property AppletName : "HTC sous-dev"
property htcLibURL : "https://github.com/NYHTC/applescript-fm-helper"

property debugMode : false
property logging : false

property orgNumLIST : {1, 2}

property idleTime : 5 * minutes

property credentialsTimeout : 2 * hours
property credentialsUpdatedTS : (current date) - credentialsTimeout
property fullAccessCredentials : {}
property userCredentials : {}

use htcBasic : script "htcBasic"
use credentialsLib : script "credentials"
use privSetLib : script "privSet"
use scripting additions

on run prefs
	if logging then htcBasic's logToConsole("Here I am")
	mainScript(prefs)
end run

on reopen prefs
	mainScript(prefs)
end reopen

on idle
	credentialsLib's credentialsCheck({})
	return idleTime -- sets idle time to specified time ( instead of the default of 30 seconds )
end idle

on quit
	process_quit({})
end quit

on mainScript(prefs)
	-- main script to determine what to run

	-- 2017-10-23 ( eshagdar ): added prefs. moved processes into separate handlers.
	-- 2017-xx-xx ( eshagdar ): created

	try
		-- pick up prefs, if specified
		set defaultPrefs to {null}
		try
			if class of prefs is script or prefs is equal to {} then set prefs to defaultPrefs
		on error
			set prefs to defaultPrefs
		end try

		-- launch htcLib
		launchHtcLib({})

		-- credentials debugging
		if debugMode then htcBasic's debugMsg("mainScript ---" & return &
			"fullAccessCredentials: " & htcBasic's coerceToString(fullAccessCredentials) & return &
			"userCredentials: " & htcBasic's coerceToString(userCredentials))

		-- ensure credentials are not outdated
		credentialsLib's credentialsEnsure({})

		-- prompt user what to do
		set process to item 1 of prefs
		return runProcess({process:process})
	on error errMsg number errNum
		tell it to activate
		tell application "htcLib" to set errStack to replaceSimple({sourceTEXT:errMsg, oldChars:" - ", newChars:return})
		set ignoreErrorNumList to {-128, -1024, -1719}
		(*
			-128: user cancel
			-1024: generic error
			-1719: assistive device
		*)
		if errNum is not in ignoreErrorNumList then set errStack to errStack & " ( errNum: " & errNum & " )"
		htcBasic's showUserError(errStack)
	end try
end mainScript

on launchHtcLib(prefs)
	-- attempt to open htcLib. if it doesn't exist, navigate user to github

	-- 2017-06-28 ( eshagdar ): create

	set openName to "Get it!"

	try
		if logging then htcBasic's logToConsole("launching htcLib")
		tell application "htcLib" to launch
	on error errMsg number errNum
		set missingAppDialog to display dialog "You do Not have the htcLib installed." with title AppletName buttons {"Cancel", openName} default button openName
		if button returned of missingAppDialog is openName then open location htcLibURL
		error "unable to launchHtcLib - " & errMsg number errNum
	end try
end launchHtcLib

on promptProcess(prefs)
	-- user user for which process to do

	-- 2017-10-17 ( eshagdar ): add expiration TS to prompt.
	-- 2017-06-28 ( eshagdar ): created

	set defaultPrefs to {processList:{}}
	set prefs to prefs & defaultPrefs

	try
		if logging then htcBasic's logToConsole("About to ask user to process")
		set promptProcessDialog to (choose from list processList of prefs with title AppletName with prompt "Creds expire: " & time string of (credentialsUpdatedTS + credentialsTimeout) & return & return & "Select a process to run:" OK button name "Run" without multiple selections allowed and empty selection allowed)
		if promptProcessDialog is false then return promptProcessDialog
		set processName to item 1 of promptProcessDialog
		if logging then htcBasic's logToConsole("Process: " & processName)
		return processName

	on error errMsg number errNum
		error "unable to promptProcess - " & errMsg number errNum
	end try
end promptProcess

on runProcess(prefs)
	-- run process specified by the user

	-- 2017-10-18 ( eshagdar ): added quit process
	-- 2017-06-28 ( eshagdar ): created.

	try
		set processList to {
			"DO NOTHING",
			"Full Access Toggle",
			"Db Manage",
			"Functions Open",
			"Security Open",
			"Security Save",
			"PrivSet - copy settings to other PrivSets",
			"New table",
			"Data Viewer",
			"Clipboard Clear",
			"Credentials Update",
			"QUIT"}
		set oneProcess to promptProcess({processList:processList})

		if oneProcess is equal to "DO NOTHING" or oneProcess is equal to false then
			return true

		else if oneProcess is equal to "Full Access Toggle" then
			return process_fullAccessToggle({})

		else if oneProcess is equal to "Db Manage" then
			return process_manageDB({})

		else if oneProcess is equal to "Functions Open" then
			return process_functionsOpen({})

		else if oneProcess is equal to "Security Open" then
			return process_securityOpen({})

		else if oneProcess is equal to "Security Save" then
			return process_securitySave({})

		else if oneProcess is equal to "PrivSet - copy settings to other PrivSets" then
			return process_PrivSetCopy({})

		else if oneProcess is equal to "New table" then
			display dialog "This process is not yet finished" with title AppletName buttons "OK" default button "OK"
			return true

		else if oneProcess is equal to "Data Viewer" then
			return process_dataViewerOpen({})

		else if oneProcess is equal to "Clipboard Clear" then
			return process_ClipboardClear({})

		else if oneProcess is equal to "Credentials Update" then
			return process_credentialsUpdate({})

		else if oneProcess is equal to "QUIT" then
			return process_quit({})

		else
			error "unknown process '" & oneProcess & "'" number -1024
		end if
	on error errMsg number errNum
		error "unable to runProcess - " & errMsg number errNum
	end try
end runProcess

on process_fullAccessToggle(prefs)
	-- wrapper for htcLib handler that toggles between full access and user account

	-- 2017-10-17 ( eshagdar ): moved function into htcLib and converted this to a wrapper

	try
		tell application "htcLib" to return fmGUI_fullAccessToggle(prefs & fullAccessCredentials & userCredentials)
	on error errMsg number errNum
		error "unable to process_fullAccessToggle - " & errMsg number errNum
	end try
end process_fullAccessToggle

on process_manageDB(prefs)
	-- wrapper for opening manage DB

	-- 2017-10-23 ( eshagdar ): moved from runProcess into a separate handler

	try
		set fullAccessToggle to fullAccessToggle({ensureMode:"full"})
		tell application "htcLib"
			fmGUI_Menu_OpenDB({})
			windowWaitUntil({windowName:"Manage Database for", whichWindow:"front", windowNameTest:"does not contain", waitCycleDelaySeconds:1, waitCycleMax:30 * minutes})
		end tell
		if modeSwitch of fullAccessToggle then fullAccessToggle({})

		return true
	on error errMsg number errNum
		error "unable to process_manageDB - " & errMsg number errNum
	end try
end process_manageDB

on process_functionsOpen(prefs)
	-- wrapper for opening custom functions

	-- 2017-10-23 ( eshagdar ): moved from runProcess into a separate handler

	try
		fullAccessToggle({ensureMode:"full"})
		tell application "htcLib" to return fmGUI_CustomFunctions_Open({})
	on error errMsg number errNum
		error "unable to process_functionsOpen - " & errMsg number errNum
	end try
end process_functionsOpen

on process_securityOpen(prefs)
	-- wrapper for opening security

	-- 2017-10-23 ( eshagdar ): moved from runProcess into a separate handler

	try
		fullAccessToggle({ensureMode:"full"})
		tell application "htcLib" to return fmGUI_ManageSecurity_GoToTab_PrivSets(fullAccessCredentials)
	on error errMsg number errNum
		error "unable to process_securityOpen - " & errMsg number errNum
	end try
end process_securityOpen

on process_securitySave(prefs)
	-- wrapper for saving security

	-- 2017-10-23 ( eshagdar ): moved from runProcess into a separate handler

	try
		tell application "htcLib"
			fmGUI_AppFrontMost()
			return fmGUI_ManageSecurity_Save(fullAccessCredentials)
		end tell
	on error errMsg number errNum
		error "unable to process_securitySave - " & errMsg number errNum
	end try
end process_securitySave

on process_PrivSetCopy(prefs)
	-- wrapper for copying a selected privSet

	-- 2017-10-23 ( eshagdar ): moved from runProcess into a separate handler

	try
		set fullAccessToggle to fullAccessToggle({ensureMode:"full"})
		privSetLib's copyPrivSetToOthers({})
		if modeSwitch of fullAccessToggle then fullAccessToggle({})
	on error errMsg number errNum
		error "unable to process_PrivSetCopy - " & errMsg number errNum
	end try
end process_PrivSetCopy

on process_dataViewerOpen(prefs)
	-- wrapper for opening the data viewer

	-- 2017-10-23 ( eshagdar ): moved from runProcess into a separate handler

	try
		tell application "htcLib" to return fmGUI_DataViewer_Open(fullAccessCredentials)
	on error errMsg number errNum
		error "unable to process_dataViewerOpen - " & errMsg number errNum
	end try
end process_dataViewerOpen

on process_ClipboardClear(prefs)
	-- wrapper for clearing the clipboard

	-- 2017-10-23 ( eshagdar ): moved from runProcess into a separate handler

	try
		set the clipboard to null
		return true
	on error errMsg number errNum
		error "unable to process_ClipboardClear - " & errMsg number errNum
	end try
end process_ClipboardClear

on process_credentialsUpdate(prefs)
	-- wrapper for updating credentials

	-- 2017-10-23 ( eshagdar ): moved from runProcess into a separate handler

	try
		return credentialsLib's credentialsUpdate(fullAccessCredentials & userCredentials)
	on error errMsg number errNum
		error "unable to process_credentialsUpdate - " & errMsg number errNum
	end try
end process_credentialsUpdate

on process_quit(prefs)
	-- wrapper for quiting applet

	-- 2017-10-23 ( eshagdar ): moved from runProcess into a separate handler

	try
		credentialsLib's credentialsCheck({forceClear:true})
		continue quit
	on error errMsg number errNum
		error "unable to process_quit - " & errMsg number errNum
	end try
end process_quit


Added Applescript to get current track from iTunes

FasdUAS 1.101.10
l
O
k
r

n

1

pnam

1

pTrk
o0	trackname	trackName
r
n
1

pArt
1

pTrk
o0trackartisttrackArtist
b
b
o0	trackname	trackName
m -
o0trackartisttrackArtist
mhookalisNMacintosh HD+/H+Q
iTunes.appQ'	 Applications+rQ%Macintosh HD:Applications:iTunes.app
iTunes.appMacintosh HDApplications/iTunes.app/
.aevtoappnull****0	trackname	trackName0trackartisttrackArtist !"
.aevtoappnull****
 k##!"

pTrk

pnam0	trackname	trackName

pArt0trackartisttrackArtist*,,EO*,,EO%%U$$Maybe On Monday%%Calexicoascr
ޭ

FasdUAS 1.101.10
l
O
k
r

n

1

pnam

1

pTrk
o0	trackname	trackName
r
n
1

pArt
1

pTrk
o0trackartisttrackArtist
b
b
o0	trackname	trackName
m -
o0trackartisttrackArtist
mhookalisNMacintosh HD+/H+Q
iTunes.appQ'	 Applications+rQ%Macintosh HD:Applications:iTunes.app
iTunes.appMacintosh HDApplications/iTunes.app/
.aevtoappnull****0	trackname	trackName0trackartisttrackArtist !"
.aevtoappnull****
 k##!"

pTrk

pnam0	trackname	trackName

pArt0trackartisttrackArtist*,,EO*,,EO%%U$$Seven Stars%%Airascr
ޭ