property stdout : ""
on run
	set newline to ASCII character 10

	set stdout to stdout & "  shutdown TotalFinderCrashWatcher ..." & newline
	try
		do shell script "killall -SIGINT TotalFinderCrashWatcher" with administrator privileges
	on error
		set stdout to stdout & "    TotalFinderCrashWatcher not running" & newline
	end try

	set stdout to stdout & "  shutdown Finder ..." & newline
	try
		tell application "Finder" to quit
	on error
		set stdout to stdout & "    Finder was not running prior uninstallation" & newline
	end try

	set stdout to stdout & "  remove TotalFinder.app from login items ..." & newline
	try
		tell application "System Events"
			get the name of every login item
			if login item "TotalFinder.app" exists then
				delete login item "TotalFinder.app"
			end if
		end tell
	on error
		set stdout to stdout & "    Encountered problems when removing TotalFinder.app from login items"
	end try

	-- old version
	set stdout to stdout & "  removing the old TotalFinder files (0.8.2 and earlier) ..." & newline
	try
		do shell script "sudo launchctl unload -w \"/Library/LaunchDaemons/com.binaryage.echelon.launcher.plist\"" with administrator privileges
	end try
	try
		do shell script "sudo rm -f \"/Library/LaunchDaemons/com.binaryage.echelon.launcher.plist\"" with administrator privileges
	end try
	try
		do shell script "sudo kextunload \"/System/Library/Extensions/echelon.kext\"" with administrator privileges
	end try
	try
		do shell script "sudo rm -rf \"/System/Library/Extensions/echelon.kext\"" with administrator privileges
	end try
	try
		do shell script "sudo rm -rf \"/Library/Application Support/SIMBL/Plugins/TotalFinder.bundle\"" with administrator privileges
	end try

	-- new version
	set stdout to stdout & "  unload TotalFinder.kext ..." & newline
	try
		do shell script "sudo kextunload \"/System/Library/Extensions/TotalFinder.kext\"" with administrator privileges
	on error
		set stdout to stdout & "    TotalFinder.kext not loaded" & newline
	end try

	set stdout to stdout & "  remove TotalFinder.app ..." & newline
	try
		do shell script "sudo rm -rf \"/Applications/TotalFinder.app\"" with administrator privileges
	on error
		set stdout to stdout & "    unable to remove /Applications/TotalFinder.app" & newline
	end try

	set stdout to stdout & "  remove TotalFinder.kext ..." & newline
	try
		do shell script "sudo rm -rf \"/System/Library/Extensions/TotalFinder.kext\"" with administrator privileges
	on error
		set stdout to stdout & "    unable to remove /System/Library/Extensions/TotalFinder.kext" & newline
	end try

	set stdout to stdout & "  remove TotalFinder.osax ..." & newline
	try
		do shell script "sudo rm -rf \"/Library/ScriptingAdditions/TotalFinder.osax\"" with administrator privileges
	on error
		set stdout to stdout & "    unable to remove /Library/ScriptingAdditions/TotalFinder.osax" & newline
	end try

	set stdout to stdout & "  enable Finder animations again ..." & newline
	try
		do shell script "defaults write com.apple.finder DisableAllAnimations -bool false" with administrator privileges
		do shell script "defaults write com.apple.finder AnimateWindowZoom -bool true" with administrator privileges
		do shell script "defaults write com.apple.finder FXDisableFancyWindowTransition -bool false" with administrator privileges
	on error
		set stdout to stdout & "    unable to enable animations back" & newline
	end try

	set stdout to stdout & "  hide system files in Finder again ..." & newline
	try
		do shell script "defaults write com.apple.finder AppleShowAllFiles -bool false" with administrator privileges
	on error
		set stdout to stdout & "    hide system files in Finder back" & newline
	end try

	set stdout to stdout & "  relaunch Finder ..." & newline
	try
		tell application "Finder" to launch
	on error
		set stdout to stdout & "    failed to relaunch Finder" & newline
	end try

	-- at this point Finder should start cleanly and with no signs of TotalFinder
	-- you may check Events/Replies tab to see if there were no issues with uninstallation

	stdout -- this is needed for platypus to display output in details window
end run

property stdout : ""
on run
	set newline to ASCII character 10

	set stdout to stdout & "  shutdown TotalFinderCrashWatcher ..." & newline
	try
		do shell script "killall -SIGINT TotalFinderCrashWatcher" with administrator privileges
	on error
		set stdout to stdout & "    TotalFinderCrashWatcher was not running" & newline
	end try

	set stdout to stdout & "  shutdown Finder ..." & newline
	try
		tell application "Finder" to quit
	on error
		set stdout to stdout & "    Finder was not running prior uninstallation" & newline
	end try

	set stdout to stdout & "  remove TotalFinder.app from login items ..." & newline
	try
		tell application "System Events"
			get the name of every login item
			if login item "TotalFinder.app" exists then
				delete login item "TotalFinder.app"
			end if
		end tell
	on error
		set stdout to stdout & "    Encountered problems when removing TotalFinder.app from login items"
	end try

	-- old version
	set stdout to stdout & "  removing the old TotalFinder files (0.8.2 and earlier) ..." & newline
	try
		do shell script "sudo launchctl unload -w \"/Library/LaunchDaemons/com.binaryage.echelon.launcher.plist\"" with administrator privileges
	end try
	try
		do shell script "sudo rm -f \"/Library/LaunchDaemons/com.binaryage.echelon.launcher.plist\"" with administrator privileges
	end try
	try
		do shell script "sudo kextunload \"/System/Library/Extensions/echelon.kext\"" with administrator privileges
	end try
	try
		do shell script "sudo rm -rf \"/System/Library/Extensions/echelon.kext\"" with administrator privileges
	end try
	try
		do shell script "sudo rm -rf \"/Library/Application Support/SIMBL/Plugins/TotalFinder.bundle\"" with administrator privileges
	end try

	-- new version
	set stdout to stdout & "  unload TotalFinder.kext ..." & newline
	try
		do shell script "sudo kextunload \"/System/Library/Extensions/TotalFinder.kext\"" with administrator privileges
	on error
		set stdout to stdout & "    TotalFinder.kext not loaded" & newline
	end try

	set stdout to stdout & "  remove TotalFinder.app ..." & newline
	try
		do shell script "sudo rm -rf \"/Applications/TotalFinder.app\"" with administrator privileges
	on error
		set stdout to stdout & "    unable to remove /Applications/TotalFinder.app" & newline
	end try

	set stdout to stdout & "  remove TotalFinder.kext ..." & newline
	try
		do shell script "sudo rm -rf \"/System/Library/Extensions/TotalFinder.kext\"" with administrator privileges
	on error
		set stdout to stdout & "    unable to remove /System/Library/Extensions/TotalFinder.kext" & newline
	end try

	set stdout to stdout & "  remove TotalFinder.osax ..." & newline
	try
		do shell script "sudo rm -rf \"/Library/ScriptingAdditions/TotalFinder.osax\"" with administrator privileges
	on error
		set stdout to stdout & "    unable to remove /Library/ScriptingAdditions/TotalFinder.osax" & newline
	end try

	set stdout to stdout & "  enable Finder animations again ..." & newline
	try
		do shell script "defaults write com.apple.finder DisableAllAnimations -bool false" with administrator privileges
		do shell script "defaults write com.apple.finder AnimateWindowZoom -bool true" with administrator privileges
		do shell script "defaults write com.apple.finder FXDisableFancyWindowTransition -bool false" with administrator privileges
	on error
		set stdout to stdout & "    unable to enable animations back" & newline
	end try

	set stdout to stdout & "  hide system files in Finder again ..." & newline
	try
		do shell script "defaults write com.apple.finder AppleShowAllFiles -bool false" with administrator privileges
	on error
		set stdout to stdout & "    hide system files in Finder back" & newline
	end try

	set stdout to stdout & "  relaunch Finder ..." & newline
	try
		tell application "Finder" to launch
	on error
		set stdout to stdout & "    failed to relaunch Finder" & newline
	end try

	set stdout to stdout & "TotalFinder uninstallation done" & newline

	-- at this point Finder should start cleanly and with no signs of TotalFinder
	-- you may check Events/Replies tab to see if there were no issues with uninstallation

	stdout -- this is needed for platypus to display output in details window
end run

add final message to the uninstaller

add final message to the uninstaller


-- Go AppleScript library

property package : "Go"
property packageRoot : missing value

-- Get working directory for a given document
on getWorkingDirectory(doc)
	tell application "Finder"
		return POSIX path of ((container of ((file of doc) as alias) as string))
	end tell
end getWorkingDirectory

-- Find Go.bbpackage root
-- Assumption: this is *always* run from within the package!
on getPackageRoot()
	tell application "Finder"
		set cwd to ((container of (path to me)) as alias)
		repeat until name of cwd is "Go.bbpackage"
			set cwd to (container of cwd as alias)
		end repeat
	end tell
	return POSIX path of (cwd as string)
end getPackageRoot

on exec(doc, cmd)
	tell application "BBEdit"
		if source language of doc is not "Go" then
			error "Not a Go source file"
		end if
	end tell

	if packageRoot is missing value then
		set packageRoot to getPackageRoot()
	end if

	set runner to quoted form of (POSIX path of (packageRoot as string) & "Contents/Resources/gorunner")
	set shellCmd to runner & space & "-d " & POSIX path of ((file of doc) as alias) & space & cmd
	return do shell script (shellCmd)
end exec

on execCommands(doc, commands)
	set output to {}
	repeat with cmd in commands
		set entry to exec(doc, cmd)
		if length of entry > 0 then
			copy entry to the end of output
		end if
	end repeat
	return output
end execCommands

on packagePath(doc)
	return quoted form of exec(doc, "go list")
end packagePath

# Parse message into result browser entry
#
# Format:
#     [/path/to/file]:[line]:(col): [message]
on makeEntry(itemData, cwd)
	try
		# Get source path
		set src to text 1 thru ((offset of ":" in itemData) - 1) of itemData
		if src starts with "./" then
			set srcFile to POSIX file (cwd & text 3 thru -1 of src)
		else
			set srcFile to POSIX file (src)
		end if

		# Get line:column
		set lineColumn to text ((offset of ":" in itemData) + 1) thru ((offset of ": " in itemData) - 1) of itemData
		set lineNumber to (text 1 thru ((offset of ":" in lineColumn) - 1) of lineColumn) as number
		set columnNumber to (text ((offset of ":" in lineColumn) + 1) thru -1 of lineColumn) as number

		# Get message
		set msg to text ((offset of ": " in itemData) + 2) thru -1 of itemData

		tell application "BBEdit"
			set resultKind to error_kind
			#	if resultType is "note" then
			#		set resultKind to note_kind
			#	else if resultType is "warning" then
			#		set resultKind to warning_kind
			#	else
			#		set resultKind to error_kind
			#	end if

			set entry to {result_kind:resultKind, result_file:srcFile, result_line:lineNumber, message:msg}
		end tell
		return entry
	on error msg
		log "Error: " & msg
		return missing value
	end try
end makeEntry

-- Filter and sort incoming messages
on prepareMessages(messages)
	set prevDelimiter to AppleScript's text item delimiters
	set AppleScript's text item delimiters to {ASCII character 10}
	set filteredString to do shell script ("echo " & quoted form of (messages as string) & " | sort -f | uniq")
	set AppleScript's text item delimiters to prevDelimiter
	return paragraphs of filteredString
end prepareMessages

on showResults(title, doc, messages)
	tell application "Finder"
		set cwd to POSIX path of ((container of (doc as alias) as string))
	end tell

	set errorList to {}
	set messageList to prepareMessages(messages)

	repeat with msg in messageList
		if msg does not start with "#" then
			set entry to makeEntry(msg, cwd)
			if entry is not missing value then
				copy entry to the end of errorList
			end if
		end if
	end repeat

	if (count of errorList) > 0 then
		try
			tell application "BBEdit"
				make new results browser with data errorList with properties {name:title}
			end tell
		on error msg
			log "Error: " & msg
		end try
	end if
end showResults

on handleDocumentDidSave(doc)
	try
		set docPath to POSIX path of ((file of doc) as string)
		set pkgPath to packagePath(doc)
		set goCommands to {"goimports -w " & quoted form of docPath, "golint " & quoted form of docPath, "go build", "go test"}
		set output to execCommands(doc, goCommands)
		if output is not missing value then
			showResults("Save " & (name of doc), POSIX file (docPath), output)
		end if
	on error msg
		log "Error handleDocumentDidSave: " & msg
	end try
end handleDocumentDidSave

(*
on run
	tell application "BBEdit" to set doc to active document of window 1
	handleDocumentDidSave(doc)
end run
*)

-- Go AppleScript library

property package : "Go"
property packageRoot : missing value

-- Get working directory for a given document
on getWorkingDirectory(doc)
	tell application "Finder"
		return POSIX path of ((container of ((file of doc) as alias) as string))
	end tell
end getWorkingDirectory

-- Find Go.bbpackage root
-- Assumption: this is *always* run from within the package!
on getPackageRoot()
	tell application "Finder"
		set cwd to ((container of (path to me)) as alias)
		repeat until name of cwd is "Go.bbpackage"
			set cwd to (container of cwd as alias)
		end repeat
	end tell
	return POSIX path of (cwd as string)
end getPackageRoot

on exec(doc, cmd)
	tell application "BBEdit"
		if source language of doc is not "Go" then
			error "Not a Go source file"
		end if
	end tell

	if packageRoot is missing value then
		set packageRoot to getPackageRoot()
	end if

	set runner to quoted form of (POSIX path of (packageRoot as string) & "Contents/Resources/gorunner")
	set shellCmd to runner & space & "-d " & POSIX path of ((file of doc) as alias) & space & cmd
	return do shell script (shellCmd)
end exec

on execCommands(doc, commands)
	set output to {}
	repeat with cmd in commands
		set entry to exec(doc, cmd)
		if length of entry > 0 then
			copy entry to the end of output
		end if
	end repeat
	return output
end execCommands

on packagePath(doc)
	return quoted form of exec(doc, "go list")
end packagePath

-- Parse message into result browser entry
--
-- Format:
--     [/path/to/file]:[line]:(col): [message]
on makeEntry(itemData, cwd)
	try
		-- Get source path
		set src to text 1 thru ((offset of ":" in itemData) - 1) of itemData
		if src starts with "./" then
			set srcFile to POSIX file (cwd & text 3 thru -1 of src)
		else
			set srcFile to POSIX file (src)
		end if

		-- Get line:column
		set lineColumn to text ((offset of ":" in itemData) + 1) thru ((offset of ": " in itemData) - 1) of itemData
		set lineNumber to (text 1 thru ((offset of ":" in lineColumn) - 1) of lineColumn) as number
		set columnNumber to (text ((offset of ":" in lineColumn) + 1) thru -1 of lineColumn) as number

		-- Get message
		set msg to text ((offset of ": " in itemData) + 2) thru -1 of itemData

		tell application "BBEdit"
			set resultKind to error_kind
			--	if resultType is "note" then
			--		set resultKind to note_kind
			--	else if resultType is "warning" then
			--		set resultKind to warning_kind
			--	else
			--		set resultKind to error_kind
			--	end if

			set entry to {result_kind:resultKind, result_file:srcFile, result_line:lineNumber, message:msg}
		end tell
		return entry
	on error msg
		log "Error: " & msg
		return missing value
	end try
end makeEntry

-- Filter and sort incoming messages
on prepareMessages(messages)
	set prevDelimiter to AppleScript's text item delimiters
	set AppleScript's text item delimiters to {ASCII character 10}
	set filteredString to do shell script ("echo " & quoted form of (messages as string) & " | sort -f | uniq")
	set AppleScript's text item delimiters to prevDelimiter
	return paragraphs of filteredString
end prepareMessages

on showResults(title, doc, messages)
	tell application "Finder"
		set cwd to POSIX path of ((container of (doc as alias) as string))
	end tell

	set errorList to {}
	set messageList to prepareMessages(messages)

	repeat with msg in messageList
		if msg does not start with "#" then
			set entry to makeEntry(msg, cwd)
			if entry is not missing value then
				copy entry to the end of errorList
			end if
		end if
	end repeat

	if (count of errorList) > 0 then
		try
			tell application "BBEdit"
				make new results browser with data errorList with properties {name:title}
			end tell
		on error msg
			log "Error: " & msg
		end try
	end if
end showResults

on handleDocumentDidSave(doc)
	try
		set docPath to POSIX path of ((file of doc) as string)
		set pkgPath to packagePath(doc)
		set goCommands to {"goimports -w " & quoted form of docPath, "golint " & quoted form of docPath, "go build", "go test"}
		set output to execCommands(doc, goCommands)
		if output is not missing value then
			showResults("Save " & (name of doc), POSIX file (docPath), output)
		end if
	on error msg
		log "Error handleDocumentDidSave: " & msg
	end try
end handleDocumentDidSave

(*
on run
	tell application "BBEdit" to set doc to active document of window 1
	handleDocumentDidSave(doc)
end run
*)

Change comments to be proper AppleScript style


(*
	Log Page - Log categorized web page bookmarks to a text file

	Version: @@VERSION@@
	Date:    2011-02-09
	Author:  Steve Wheeler

	Get the title, URL, current date and time, and a user-definable
	category for the frontmost Safari window and log the info to a text
	file.

	This program is free software available under the terms of a
	BSD-style (3-clause) open source license detailed below.
*)

(*
Copyright (c) 2011 Steve Wheeler
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

* Neither the name of the copyright holder nor the names of
  contributors may be used to endorse or promote products derived from
  this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*)

(*
	TODO: Change the following local-only config before any public release.
	The log file should be: $GTD_IN/logs/urls/urls.YYYY.txt
	Or just: $GTD_IN/logs/urls.txt
*)

property script_name : "Log Page"
property script_version : "@@VERSION@@"

---------- USER CONFIGURATION ----------------------------------------
-- Default log directory to use if one is not read from config file:
set log_dir to POSIX path of (path to application support folder from user domain) & "Jazzhead/Log Page/"
--set log_dir to POSIX path of (path to desktop folder) & "Log Page/" -- :DEBUG:

-- Log file name:
set log_name to "urls.txt"

-- Default categories/labels if none are found in (or there is no)
-- URL file. Modify as desired:
set default_cats to "Development
Development:AppleScript
Development:AppleScript:Mail
Design
Productivity:GTD
Apple:Mac OS X
Apple:iOS
Career
Education
Health
Health:Diet
Health:Fitness
General"
---------- END User Configuration ----------------------------------------

---------- ADVANCED (EXPERIMENTAL) ---------------------------------------------
-- For advanced users familiar with the command-line, override the default log
-- directory path. This probably won't be in a public release.
--
-- Grab an exported shell environment variable from a config file to use as the
-- log directory path. For this example, I have a "~/.gtdrc" config file that I
-- source from my "~/.bash_profile" file so that it exportss environment
-- variables relating to my GTD system. That makes those variables available to
-- any of the shell scripts and tools that I use. For instance, when I'm
-- editing files in Vim, I can write paths to other files using one of the
-- environment variables rather than a full or relative path and the 'gf'
-- command will work for jumping to that file. The config file looks like this:
--
--         # ~/.gtdrc
--         #
--         # File locations for GTD documents
--
--         export GTD_DIR=$HOME/Documents/org  # GTD root directory
--         export GTD_IN=$GTD_DIR/content      # source/input files
--         export GTD_OUT=$GTD_DIR/html        # generated HTML output files
--         export GTD_LIB=$GTD_DIR/lib         # code library files
--         export GTD_BIN=$GTD_LIB/script      # scripts
--
-- Remove (or comment out) the "(*" and "*)" comment markers below to use this
-- section. Make sure you also configure the two variables for your system.
--(*
--------------- USER CONFIGURATION ----------
-- Path to your config file:
set cfg_file to POSIX path of (path to home folder) & ".gtdrc"
-- The environment variable you're interested in:
set env_var to "GTD_IN"
--------------- END User Configuration ---------

-- Check for environment variable in config file:
set s to "egrep '\\<" & env_var & "=' " & quoted form of cfg_file &
	" > /dev/null 2>&1; echo $?"
set shell_status to (do shell script s) as integer
-- Source the config file and echo the desired variable:
if shell_status is 0 then -- (means that grep found a match)
	set s to ". " & quoted form of cfg_file & " && echo $" & env_var
	set log_dir to (do shell script s) & "/logs/"
end if
---------- END Advanced --------------------------------------------------------
--*)

--return log_dir -- :DEBUG:

--
-- Get URL and title from front browser window
--
tell application "Safari"
	--activate
	try
		set this_url to URL of front document
		set this_title to name of first tab of front window whose visible is true
	on error
		return false
	end try
end tell
-- Transliterate non-ASCII characters to ASCII
set this_title to convert_to_ascii(this_title)

--return this_title -- :DEBUG:

--
-- Format the record separator between log entries
--
set rule_char to "-"
set rule_width to 80
set field_width to 7
set field_sep to " | "
set rec_sep to "" & multiply_text(rule_char, field_width - 1) &
	"+" & multiply_text(rule_char, rule_width - field_width)

--
-- Format date-time string as "YYYY-MM-DD HH:MM:SS"
--
set {year:y, month:m, day:d, hours:hh, minutes:mm, seconds:ss} to current date
set m to m as integer -- coerce month string
-- Pad numbers with leading zeros:
set tmp_list to {}
repeat with this_item in {m, d, hh, mm, ss}
	set this_item to text 2 thru -1 of (100 + this_item as text)
	set end of tmp_list to this_item
end repeat
set {m, d, hh, mm, ss} to tmp_list
-- Final string:
set date_time to join_list({y, m, d}, "-") & " " & join_list({hh, mm, ss}, ":")

-- Log file name
--set log_name to "urls." & y & ".txt"

--
-- Create log directory if it doesn't already exist. (Go ahead and use a shell
-- command since it's easy to create intermediate directories all in one step.):
--
try
	set s to "mkdir -pm700 " & quoted form of log_dir
	do shell script s
on error err_msg number err_num
	error "Can't create log directory: " & err_msg number err_num
	return "Fatal Error: Can't create log directory"
end try

set log_file_posix to "" & log_dir & log_name
set log_file to POSIX file log_file_posix

--
-- Add header to new or empty log file
--
set should_init to false
tell application "Finder"
	if (not (exists log_file)) or (_IO's read_file(log_file) is "") then
		set should_init to true
	end if
end tell

set head_sep to multiply_text("#", 80)
if should_init then
	set file_header to head_sep & "
# urls.txt - Timestamped and categorized URL archive
# ==================================================
# Optionally list some categories/labels of URLs below that might not yet
# be used. Any categories/lables listed here or in the web page records
# will be presented as a list to select from when saving new URLs.
" & head_sep & linefeed & default_cats & linefeed & head_sep & "
# END: category/label list
" & head_sep & linefeed
	tell _IO to write_file(log_file, file_header)
	set cat_txt to default_cats
else
	-- Read categories from file
	(*
		:TODO: Error handling.
	*)
	set cat_txt to text 2 thru -2 of (item 3 of split_text(_IO's read_file(log_file), head_sep))
end if

-- Parse any existing labels from the "Label" fields of the URLs file:
set s to "egrep '^Label ' " & quoted form of log_file_posix &
	" | sed 's/^Label | //' | sort | uniq"
--return s
set used_cats to do shell script s without altering line endings
-- Sort those along with the manually entered categories/labels:
set s to "echo \"" & cat_txt & linefeed & used_cats & "\" | egrep -v '^$' | sort | uniq"
set cat_txt to do shell script s
-- Coerce the lines into a list:
set cat_list to paragraphs of cat_txt
--return cat_list -- :DEBUG:

--
-- Prompt for category/subcategory of URL
--

-- Select an existing category
set msg to "Please select a category for the URL you want to log. You will have a chance to edit your choice."
set cat_choice to choose from list cat_list with title script_name with prompt msg OK button name "Select"
--if cat_choice is false then return false
if cat_choice is false then set cat_choice to "Please enter a category..."

-- Modify or enter a new category
set btns to {"Cancel", "TODO: Edit Log File", "Append URL to File"}
set msg to "To log the URL for:" & return & return
	& tab & "\"" & this_title & "\"" & return & return &
	"please provide a category and any optional subcategories (or edit your selected category) for the URL. Example: \"Development:AppleScript:Mail\""
display dialog msg default answer cat_choice with title script_name buttons btns default button last item of btns
set {this_label, btn_pressed} to {text returned of result, button returned of result}

--
-- Append or edit the log file
--
if btn_pressed is last item of btns then
	set final_text to join_list({
		"Date " & field_sep & date_time,
		"Label" & field_sep & this_label,
		"Title" & field_sep & this_title,
		"URL  " & field_sep & this_url,
		rec_sep}, linefeed) & linefeed
	_IO's append_file(log_file, final_text)
else
	edit_log()
end if

(************************************************************
 *	Subroutines
 ************************************************************)

-- ===== Main Functions =====

on edit_log()
	(*
		TODO:MAYBE:
		Have a configuration variable in the main script to specify which text
		editor to use. Have another variable for configuring whether or not
		it's a GUI application. Then this function would use 'open' to launch a
		GUI app or script the Terminal to launch a command-line editor.
		Optionally use 'do shell script' to launch a compatible GUI app from a
		command line (so that the working directory can be changed to that of
		the file first), but I don't know if that will really be necessary
		since I have a Vim shortcut for quickly changing the working directory
		if need be.
	*)
	set t to script_name
	set m to ":TODO: Implement edit_log() function."
	set b to {"Cancel"}
	display alert t message m buttons b cancel button 1 as critical
	return false
end edit_log

-- ===== Utility Functions =====

on convert_to_ascii(non_ascii_txt)
	set s to "iconv -f UTF-8 -t US-ASCII//TRANSLIT <<<" & quoted form of non_ascii_txt
	do shell script s
end convert_to_ascii

on multiply_text(str, n)
	if n < 1 or str = "" then return ""
	set lst to {}
	repeat n times
		set end of lst to str
	end repeat
	return lst as string
end multiply_text

on split_text(txt, delim)
	set old_tids to AppleScript's text item delimiters
	try
		set AppleScript's text item delimiters to (delim as string)
		set lst to every text item of (txt as string)
		set AppleScript's text item delimiters to old_tids
		return lst
	on error err_msg number err_num
		set AppleScript's text item delimiters to old_tids
		error "Can't split_text(): " & err_msg number err_num
	end try
end split_text

on join_list(lst, delim)
	set old_tids to AppleScript's text item delimiters
	try
		set AppleScript's text item delimiters to (delim as string)
		set txt to lst as string
		set AppleScript's text item delimiters to old_tids
		return txt
	on error err_msg number err_num
		set AppleScript's text item delimiters to old_tids
		error "Can't join_list(): " & err_msg number err_num
	end try
end join_list

(************************************************************
 *	Script Objects
 ************************************************************)

script _IO

	(* == PUBLIC == *)

	on write_file(file_path, this_data)
		_write_file(file_path, this_data, string, false) -- overwrite existing file
	end write_file

	on append_file(file_path, this_data)
		_write_file(file_path, this_data, string, true) -- append new data to end of existing file
	end append_file

	on read_file(file_path)
		_read_file(file_path, string)
	end read_file

	(* == PRIVATE == *)

	on _write_file(file_path, this_data, data_class, should_append_data)
		try
			set file_path to file_path as text
			set file_handle to
				open for access file file_path with write permission
			if not should_append_data then
				set eof of the file_handle to 0
			write this_data as data_class to file_handle starting at eof
			close access file_handle
			return true
		on error err_msg number err_num
			try
				close access file file_path
			end try
			error err_msg number err_num
			return false
		end try
	end _write_file

	on _read_file(file_path, data_class)
		try
			set file_path to file_path as text
			if (get eof file file_path) is 0 then
				set file_contents to ""
			else
				set file_contents to read file file_path as data_class
			end if
			return file_contents
		on error
			return 0
		end try
	end _read_file
end script

(*
	Log Page - Log categorized web page bookmarks to a text file

	Version: @@VERSION@@
	Date:    2011-02-09
	Author:  Steve Wheeler

	Get the title, URL, current date and time, and a user-definable
	category for the frontmost Safari window and log the info to a text
	file.

	This program is free software available under the terms of a
	BSD-style (3-clause) open source license detailed below.
*)

(*
Copyright (c) 2011 Steve Wheeler
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

* Neither the name of the copyright holder nor the names of
  contributors may be used to endorse or promote products derived from
  this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*)

(*
	TODO: Change the following local-only config before any public release.
	The log file should be: $GTD_IN/logs/urls/urls.YYYY.txt
	Or just: $GTD_IN/logs/urls.txt

	TODO: The edit_log() function is currently incomplete. It will only launch
	an editor from the shell and only if that editor is a GUI editor (in this
	case, MacVim). If I release this script publicly, I will still need to
	implement funtionality to launch a GUI editor normally (with the 'open'
	AppleScript commmand) as well as a command-line editor run in the Terminal.
*)

property script_name : "Log Page"
property script_version : "@@VERSION@@"

---------- USER CONFIGURATION ----------------------------------------
-- Default log directory to use if one is not read from config file:
--set log_dir to POSIX path of (path to application support folder from user domain) & "Jazzhead/Log Page/"
set log_dir to POSIX path of (path to desktop folder) & "Log Page/" -- :DEBUG:

-- Log file name:
set log_name to "urls.txt"

-- Default categories/labels if none are found in (or there is no)
-- URL file. Modify as desired:
set default_cats to "Development
Development:AppleScript
Development:AppleScript:Mail
Design
Productivity:GTD
Apple:Mac OS X
Apple:iOS
Career
Education
Health
Health:Diet
Health:Fitness
General"

-- Text editor to use if manually editing the log file.
--
-- This example:
--	1. Opens the file using MacVim ('mvim' as installed by MacPorts)
--	2. Switches the local working directory for just that buffer to the
--	    directory containing the file ('lcd')
--	3. Gives the MacVim window a name ('--servername').
--
set text_editor to "/opt/local/bin/mvim \"+lcd %:p:h\" --servername LOG_PAGE"

-- Should the specified editor be launched from the unix shell?
set should_use_shell to true
---------- END User Configuration ----------------------------------------

---------- ADVANCED (EXPERIMENTAL) ---------------------------------------------
-- For advanced users familiar with the command-line, override the default log
-- directory path. This probably won't be in a public release.
--
-- Grab an exported shell environment variable from a config file to use as the
-- log directory path. For this example, I have a "~/.gtdrc" config file that I
-- source from my "~/.bash_profile" file so that it exportss environment
-- variables relating to my GTD system. That makes those variables available to
-- any of the shell scripts and tools that I use. For instance, when I'm
-- editing files in Vim, I can write paths to other files using one of the
-- environment variables rather than a full or relative path and the 'gf'
-- command will work for jumping to that file. The config file looks like this:
--
--         # ~/.gtdrc
--         #
--         # File locations for GTD documents
--
--         export GTD_DIR=$HOME/Documents/org  # GTD root directory
--         export GTD_IN=$GTD_DIR/content      # source/input files
--         export GTD_OUT=$GTD_DIR/html        # generated HTML output files
--         export GTD_LIB=$GTD_DIR/lib         # code library files
--         export GTD_BIN=$GTD_LIB/script      # scripts
--
-- Remove (or comment out) the "(*" and "*)" comment markers below to use this
-- section. Make sure you also configure the two variables for your system.
--(*
--------------- USER CONFIGURATION ----------
-- Path to your config file:
set cfg_file to POSIX path of (path to home folder) & ".gtdrc"
-- The environment variable you're interested in:
set env_var to "GTD_IN"
--------------- END User Configuration ---------

-- Check for environment variable in config file:
set s to "egrep '\\<" & env_var & "=' " & quoted form of cfg_file &
	" > /dev/null 2>&1; echo $?"
set shell_status to (do shell script s) as integer
-- Source the config file and echo the desired variable:
if shell_status is 0 then -- (means that grep found a match)
	set s to ". " & quoted form of cfg_file & " && echo $" & env_var
	set gtd_in_dir to do shell script s
	set log_dir to gtd_in_dir & "/logs/"

	--------------------
	-- OPTIONAL: Override the Text editor to integrate with my GTD system.
	--
	-- This example:
	--	1. Opens the file using MacVim ('mvim' as installed by MacPorts)
	--	2. Switches the local working directory ('lcd') for just that buffer to
	--	    my GTD content directory ($GTD_IN after escaping potential spaces)
	--	3. Gives the MacVim window a name ('--servername').

	----- First, escape any potential spaces in the directory path:
	--
	--set gtd_in_dir to gtd_in_dir & " foo    bar" -- :DEBUG: spaces in path
	--
	set s to "echo " & quoted form of gtd_in_dir & " | sed 's/ \\{1,\\}/\\\\ /g'" -- escape spaces
	set gtd_in_dir to do shell script s
	--
	--log gtd_in_dir -- :DEBUG: need to use 'log' to see the value w/o AppleScript escapes

	----- Finally, set the editor with all of the options:
	--
	set text_editor to "/opt/local/bin/mvim \"+lcd " & gtd_in_dir & "\" --servername GTD --remote-silent"
	--
	--log text_editor -- :DEBUG:
	--return text_editor -- :DEBUG:
	--------------------
end if
---------- END Advanced --------------------------------------------------------
--*)

--return log_dir -- :DEBUG:

--
-- Get URL and title from front browser window
--
tell application "Safari"
	--activate
	try
		set this_url to URL of front document
		set this_title to name of first tab of front window whose visible is true
	on error
		return false
	end try
end tell
-- Transliterate non-ASCII characters to ASCII
set this_title to convert_to_ascii(this_title)

--return this_title -- :DEBUG:

--
-- Format the record separator between log entries
--
set rule_char to "-"
set rule_width to 80
set field_width to 7
set field_sep to " | "
set rec_sep to "" & multiply_text(rule_char, field_width - 1) &
	"+" & multiply_text(rule_char, rule_width - field_width)

--
-- Format date-time string as "YYYY-MM-DD HH:MM:SS"
--
set {year:y, month:m, day:d, hours:hh, minutes:mm, seconds:ss} to current date
set m to m as integer -- coerce month string
-- Pad numbers with leading zeros:
set tmp_list to {}
repeat with this_item in {m, d, hh, mm, ss}
	set this_item to text 2 thru -1 of (100 + this_item as text)
	set end of tmp_list to this_item
end repeat
set {m, d, hh, mm, ss} to tmp_list
-- Final string:
set date_time to join_list({y, m, d}, "-") & " " & join_list({hh, mm, ss}, ":")

-- Log file name
--set log_name to "urls." & y & ".txt"

--
-- Create log directory if it doesn't already exist. (Go ahead and use a shell
-- command since it's easy to create intermediate directories all in one step.):
--
try
	set s to "mkdir -pm700 " & quoted form of log_dir
	do shell script s
on error err_msg number err_num
	error "Can't create log directory: " & err_msg number err_num
	return "Fatal Error: Can't create log directory"
end try

set log_file_posix to "" & log_dir & log_name
set log_file to POSIX file log_file_posix

--
-- Add header to new or empty log file
--
set should_init to false
tell application "Finder"
	if (not (exists log_file)) or (_IO's read_file(log_file) is "") then
		set should_init to true
	end if
end tell

set head_sep to multiply_text("#", 80)
if should_init then
	set file_header to head_sep & "
# urls.txt - Timestamped and categorized URL archive
# ==================================================
# Optionally list some categories/labels of URLs below that might not yet
# be used. Any categories/lables listed here or in the web page records
# will be presented as a list to select from when saving new URLs.
" & head_sep & linefeed & default_cats & linefeed & head_sep & "
# END: category/label list
" & head_sep & linefeed
	tell _IO to write_file(log_file, file_header)
	set cat_txt to default_cats
else
	-- Read categories from file
	(*
		:TODO: Error handling.
	*)
	set cat_txt to text 2 thru -2 of (item 3 of split_text(_IO's read_file(log_file), head_sep))
end if

-- Parse any existing labels from the "Label" fields of the URLs file:
set s to "egrep '^Label ' " & quoted form of log_file_posix &
	" | sed 's/^Label | //' | sort | uniq"
--return s
set used_cats to do shell script s without altering line endings
-- Sort those along with the manually entered categories/labels:
set s to "echo \"" & cat_txt & linefeed & used_cats & "\" | egrep -v '^$' | sort | uniq"
set cat_txt to do shell script s
-- Coerce the lines into a list:
set cat_list to paragraphs of cat_txt
--return cat_list -- :DEBUG:

--
-- Prompt for category/subcategory of URL
--

-- Select an existing category
set msg to "Please select a category for the URL you want to log. You will have a chance to edit your choice."
set cat_choice to choose from list cat_list with title script_name with prompt msg OK button name "Select"
--if cat_choice is false then return false
if cat_choice is false then set cat_choice to "Please enter a category..."

-- Modify or enter a new category
set btns to {"Cancel", "Manually Edit Log File", "Append URL to Log File"}
set msg to "To log the URL for:" & return & return
	& tab & "\"" & this_title & "\"" & return & return &
	"please provide a category and any optional subcategories (or edit your selected category) for the URL. Example: \"Development:AppleScript:Mail\""
display dialog msg default answer cat_choice with title script_name buttons btns default button last item of btns
set {this_label, btn_pressed} to {text returned of result, button returned of result}

--
-- Append or edit the log file
--
if btn_pressed is last item of btns then
	set final_text to join_list({
		"Date " & field_sep & date_time,
		"Label" & field_sep & this_label,
		"Title" & field_sep & this_title,
		"URL  " & field_sep & this_url,
		rec_sep}, linefeed) & linefeed
	_IO's append_file(log_file, final_text)
else
	if should_use_shell then
		set this_log_file to quoted form of log_file_posix
	else
		set this_log_file to log_file
	end if
	edit_log(this_log_file, text_editor, should_use_shell)
end if

--display alert "Log Page" message "DEBUG: Script complete."

(************************************************************
 *	Subroutines
 ************************************************************)

-- ===== Main Functions =====

on edit_log(log_file, text_editor, should_use_shell)
	(*
		TODO:MAYBE:
		Have a configuration variable in the main script to specify which text
		editor to use. Have another variable for configuring whether or not
		it's a GUI application. Then this function would use 'open' to launch a
		GUI app or script the Terminal to launch a command-line editor.
		Optionally use 'do shell script' to launch a compatible GUI app from a
		command line (so that the working directory can be changed to that of
		the file first), but I don't know if that will really be necessary
		since I have a Vim shortcut for quickly changing the working directory
		if need be.
	*)
	if should_use_shell then
		set s to text_editor & space & log_file & space & "> /dev/null 2>&1"
		do shell script s
		return
	else
		set t to script_name
		set m to ":TODO: edit_log() function: use non-shell-invoked editor."
		set b to {"Cancel"}
		display alert t message m buttons b cancel button 1 as critical
		return false
	end if
end edit_log

-- ===== Utility Functions =====

on convert_to_ascii(non_ascii_txt)
	set s to "iconv -f UTF-8 -t US-ASCII//TRANSLIT <<<" & quoted form of non_ascii_txt
	do shell script s
end convert_to_ascii

on multiply_text(str, n)
	if n < 1 or str = "" then return ""
	set lst to {}
	repeat n times
		set end of lst to str
	end repeat
	return lst as string
end multiply_text

on split_text(txt, delim)
	set old_tids to AppleScript's text item delimiters
	try
		set AppleScript's text item delimiters to (delim as string)
		set lst to every text item of (txt as string)
		set AppleScript's text item delimiters to old_tids
		return lst
	on error err_msg number err_num
		set AppleScript's text item delimiters to old_tids
		error "Can't split_text(): " & err_msg number err_num
	end try
end split_text

on join_list(lst, delim)
	set old_tids to AppleScript's text item delimiters
	try
		set AppleScript's text item delimiters to (delim as string)
		set txt to lst as string
		set AppleScript's text item delimiters to old_tids
		return txt
	on error err_msg number err_num
		set AppleScript's text item delimiters to old_tids
		error "Can't join_list(): " & err_msg number err_num
	end try
end join_list

(************************************************************
 *	Script Objects
 ************************************************************)

script _IO

	(* == PUBLIC == *)

	on write_file(file_path, this_data)
		_write_file(file_path, this_data, string, false) -- overwrite existing file
	end write_file

	on append_file(file_path, this_data)
		_write_file(file_path, this_data, string, true) -- append new data to end of existing file
	end append_file

	on read_file(file_path)
		_read_file(file_path, string)
	end read_file

	(* == PRIVATE == *)

	on _write_file(file_path, this_data, data_class, should_append_data)
		try
			set file_path to file_path as text
			set file_handle to
				open for access file file_path with write permission
			if not should_append_data then
				set eof of the file_handle to 0
			write this_data as data_class to file_handle starting at eof
			close access file_handle
			return true
		on error err_msg number err_num
			try
				close access file file_path
			end try
			error err_msg number err_num
			return false
		end try
	end _write_file

	on _read_file(file_path, data_class)
		try
			set file_path to file_path as text
			if (get eof file file_path) is 0 then
				set file_contents to ""
			else
				set file_contents to read file file_path as data_class
			end if
			return file_contents
		on error
			return 0
		end try
	end _read_file
end script

Add "Edit Log" action

Add "Edit Log" action


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

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

set text item delimiters to "
"

set theChapters to text items of theChaptersStr

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

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

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

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

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

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

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

on downloadPdf(theChapterName)
  tell application "System Events"

    tell process "Safari"
      set frontmost to true

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

      delay 1

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

      tell window 1
        repeat until sheet 1 exists
        end repeat

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

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

      end tell

      delay 2

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

    end tell

  end tell
end downloadPdf

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

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

set text item delimiters to "
"

set theChapters to text items of theChaptersStr

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

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

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

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

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

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

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

on downloadPdf(theChapterName)
  tell application "System Events"

    tell process "Safari"
      set frontmost to true

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

      delay 1

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

      tell window 1
        repeat until sheet 1 exists
        end repeat

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

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

      end tell

      delay 2

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

    end tell

  end tell
end downloadPdf

Update chapter list in pdf generation script


activate application "SystemUIServer"
tell application "System Events"
    tell process "SystemUIServer"
        set btMenu to (menu bar item 1 of menu bar 1 whose description contains "bluetooth")
        tell btMenu
            click
            try
                tell (menu item "WH-1000XM3" of menu 1)
                    click
                    if exists menu item "Connect" of menu 1 then
                        click menu item "Connect" of menu 1
                        return "Connecting..."
                    else if exists menu item "Disconnect" of menu 1 then
                        click menu item "Disconnect" of menu 1
                        return "Disconnecting..."
                    end if
                end tell
            end try
        end tell
    end tell
    key code 53
    return "Device not found or Bluetooth turned off"
end tell

activate application "SystemUIServer"
tell application "System Events"
    tell process "SystemUIServer"
        set btMenu to (menu bar item 1 of menu bar 1 whose description contains "bluetooth")
        tell btMenu
            click
            try
                tell (menu item "Rosco's Headphones" of menu 1)
                    click
                    if exists menu item "Connect" of menu 1 then
                        click menu item "Connect" of menu 1
                        return "Connecting..."
                    else if exists menu item "Disconnect" of menu 1 then
                        click menu item "Disconnect" of menu 1
                        return "Disconnecting..."
                    end if
                end tell
            end try
        end tell
    end tell
    key code 53
    return "Device not found or Bluetooth turned off"
end tell

Rename headphones

Rename headphones


set broker to "h8.opera.com"
set workers to {"h6.opera.com", "h8.opera.com", "h9.opera.com", "h10.opera.com"}
tell application "iTerm"
    activate
    set myterm to (make new terminal)
    tell myterm
        set number of columns to 80
        set number of rows to 50
        repeat with workerhost in workers
            set worker to (make new session at the end of sessions)
            tell worker
                set name to workerhost
                set foreground color to "white"
                set background color to "black"
                set transparency to 0.1
                exec command "/bin/sh -i"
                write text "ssh root@" & workerhost & " 'tail -f /var/log/celeryd.log'"
            end tell
        end repeat
        set rabbit to (make new session at the end of sessions)
        tell rabbit
            set name to "rabbit.log"
            set foreground color to "white"
            set background color to "black"
            set transparency to 0.1
            exec command "/bin/sh -i"
            write text "ssh root@" & broker & " 'tail -f /var/log/rabbitmq/rabbit.log'"
        end tell
        tell the first session
            activate
        end tell
    end tell
end tell

set broker to "h8.opera.com"
set workers to {"h6.opera.com", "h8.opera.com", "h9.opera.com", "h10.opera.com"}
set clock to "h6.opera.com"
tell application "iTerm"
    activate
    set myterm to (make new terminal)
    tell myterm
        set number of columns to 80
        set number of rows to 50
        repeat with workerhost in workers
            set worker to (make new session at the end of sessions)
            tell worker
                set name to workerhost
                set foreground color to "white"
                set background color to "black"
                set transparency to 0.1
                exec command "/bin/sh -i"
                write text "ssh root@" & workerhost & " 'tail -f /var/log/celeryd.log'"
            end tell
        end repeat
        set celerybeat to (make new session at the end of sessions)
        tell celerybeat
            set name to "celerybeat.log"
            set foreground color to "white"
            set background color to "black"
            set transparency to 0.1
            exec command "/bin/sh -i"
            write text "ssh root@" & clock & " 'tail -f /var/log/celerybeat.log'"
        end tell
        set rabbit to (make new session at the end of sessions)
        tell rabbit
            set name to "rabbit.log"
            set foreground color to "white"
            set background color to "black"
            set transparency to 0.1
            exec command "/bin/sh -i"
            write text "ssh root@" & broker & " 'tail -f /var/log/rabbitmq/rabbit.log'"
        end tell
        tell the first session
            activate
        end tell
    end tell
end tell

Update the watch workers applescript to watch the celerybeat log file.


on newPresentation(themeName)
	tell application "Keynote"
		activate
		-- FIXME: Make this selectable?
		set targetWidth to 1024 -- 1440 <-- higher resolution
		set targetHeight to 768 -- 1080 <-- higher resolution

		set props to {document theme:theme (themeName as string), width:targetWidth, height:targetHeight}

		set thisDocument to make new document with properties props
		return name of thisDocument
	end tell
end newPresentation

on openPresentation(posixPath)
	tell application "Keynote"
		open posixPath
	end tell
end openPresentation

on savePresentation(docname, posixPath)
	tell application "Keynote"
		save document named docname in POSIX file posixPath
	end tell
end savePresentation

on createSlide(docname, masterSlideName)
	try
		tell application "Keynote"
			tell document named docname
				set thisSlide to make new slide with properties {base slide:master slide masterSlideName}
			end tell
	  return thisSlide
		end tell
	on error
		return 0
	end try
end createSlide

on finalize(docname)
	tell application "Keynote"
		tell document named docname to delete slide 1
	end tell
end finalize

on themeMasters(docname)
	--	  tell application "Keynote" to get the name of every master slide of thisDocument
	tell application "Keynote"
		set names to the name of every master slide of document named docname
		return names
	end tell
end themeMasters

on addImage(docname, filepath)
  (*
	FIXME: Use slide ID to adress slide instead of "current slide"
  *)
  tell application "Keynote"
	tell document named docname
		tell the current slide

			-- TO REPLACE A PLACEHOLDER OR EXISTING IMAGE:
			set thisPlaceholderImageItem to image 1
			-- change the value of the “file name” property of the image to be an HFS file reference to the replacement image file
		set macPath to POSIX file filepath as Unicode text
			set file name of thisPlaceholderImageItem to ¬
				alias macPath

		end tell
	end tell
  end tell
end addImage

on addTitle(docname, thisSlideTitle)
  (*
	FIXME: Use slide ID to adress slide instead of "current slide"
  *)
	tell application "Keynote"
		tell document named docname
			tell the current slide
				if title showing is true then
					set the object text of the default title item to thisSlideTitle
				end if
			end tell
		end tell
	end tell
end addTitle

on addBody(docname, thisSlideBody)
  (*
	FIXME: Use slide ID to adress slide instead of "current slide"
  *)
	tell application "Keynote"
		tell document named docname
			tell the current slide
				if body showing is true then
					set the object text of the default body item to thisSlideBody
				end if
			end tell
		end tell
	end tell
end addTitle

on newPresentation(themeName)
	tell application "Keynote"
		activate
		-- FIXME: Make this selectable?
		set targetWidth to 1024 -- 1440 <-- higher resolution
		set targetHeight to 768 -- 1080 <-- higher resolution

		set props to {document theme:theme (themeName as string), width:targetWidth, height:targetHeight}

		set thisDocument to make new document with properties props
		return name of thisDocument
	end tell
end newPresentation

on openPresentation(posixPath)
	tell application "Keynote"
		open posixPath
	end tell
end openPresentation

on savePresentation(docname, posixPath)
	tell application "Keynote"
		save document named docname in POSIX file posixPath
	end tell
end savePresentation

on createSlide(docname, masterSlideName)
	try
		tell application "Keynote"
			tell document named docname
				set thisSlide to make new slide with properties {base slide:master slide masterSlideName}
			end tell
	  return thisSlide
		end tell
	on error
		return 0
	end try
end createSlide

on deleteAllSlides(docname)
	tell application "Keynote"
		tell document named docname to delete every slide
	end tell
end deleteAllSlides

on finalize(docname)
	tell application "Keynote"
		tell document named docname to delete slide 1
	end tell
end finalize

on themeMasters(docname)
	--	  tell application "Keynote" to get the name of every master slide of thisDocument
	tell application "Keynote"
		set names to the name of every master slide of document named docname
		return names
	end tell
end themeMasters

on addImage(docname, filepath)
  (*
	FIXME: Use slide ID to adress slide instead of "current slide"
  *)
  tell application "Keynote"
	tell document named docname
		tell the current slide

			-- TO REPLACE A PLACEHOLDER OR EXISTING IMAGE:
			set thisPlaceholderImageItem to image 1
			-- change the value of the “file name” property of the image to be an HFS file reference to the replacement image file
		set macPath to POSIX file filepath as Unicode text
			set file name of thisPlaceholderImageItem to ¬
				alias macPath

		end tell
	end tell
  end tell
end addImage

on addTitle(docname, thisSlideTitle)
  (*
	FIXME: Use slide ID to adress slide instead of "current slide"
  *)
	tell application "Keynote"
		tell document named docname
			tell the current slide
				if title showing is true then
					set the object text of the default title item to thisSlideTitle
				end if
			end tell
		end tell
	end tell
end addTitle

on addBody(docname, thisSlideBody)
  (*
	FIXME: Use slide ID to adress slide instead of "current slide"
  *)
	tell application "Keynote"
		tell document named docname
			tell the current slide
				if body showing is true then
					set the object text of the default body item to thisSlideBody
				end if
			end tell
		end tell
	end tell
end addTitle

Add deleteAllSlides

Add deleteAllSlides


try
    display dialog "Are you sure you want to remove NoEjectDelay?" buttons {"Cancel", "OK"}
    if the button returned of the result is "OK" then
        try
            do shell script "test -f '/Library/Application Support/org.pqrs/NoEjectDelay/uninstall.sh'"
            try
                do shell script "sh '/Library/Application Support/org.pqrs/NoEjectDelay/uninstall.sh'" with administrator privileges
                display alert "NoEjectDelay has been uninstalled. Please restart OS X."
            on error
                display alert "Failed to uninstall NoEjectDelay."
            end try
        on error
            display alert "NoEjectDelay is not installed."
        end try
    end if
on error
    display alert "NoEjectDelay uninstallation was canceled."
end try

try
    display dialog "Are you sure you want to remove NoEjectDelay?" buttons {"Cancel", "OK"}
    if the button returned of the result is "OK" then
        try
            do shell script "test -f '/Library/Application Support/org.pqrs/NoEjectDelay/uninstall.sh'"
            try
                do shell script "sh '/Library/Application Support/org.pqrs/NoEjectDelay/uninstall.sh'" with administrator privileges
                display alert "NoEjectDelay has been uninstalled. Please restart OS X."
                do shell script "killall 'NoEjectDelay Utility'"
            on error
                display alert "Failed to uninstall NoEjectDelay."
            end try
        on error
            display alert "NoEjectDelay is not installed."
        end try
    end if
on error
    display alert "NoEjectDelay uninstallation was canceled."
end try

add killall at uninstaller.applescript

add killall at uninstaller.applescript


--
--  AppDelegate.applescript
--  PerianOpener
--
--  Created by C.W. Betts on 9/25/13.
--  Copyright (c) 2013 Perian Team. All rights reserved.
--

script AppDelegate
	property parent : class "NSObject"

	on isMavericksOrLater()
		-- TODO: Implement
		return yes
	end isMavericksOrLater

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

	on applicationDidFinishLaunching_(aNotification)
		-- Insert code here to initialize your application before any files are opened
		tell current application's NSTimer to set theTimer to scheduledTimerWithTimeInterval_target_selector_userInfo_repeats_(10, me, "timerFired:", missing value, false)
	end applicationDidFinishLaunching_

	on timerFired_(timer)
		quit
	end timerFired_

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

	on application_openFiles_(appl, theFiles)

		set mavericks to isMavericksOrLater()
		if mavericks is true
		tell application "com.apple.quicktimeplayer"
			repeat with theFile in theFiles's allObjects()
				set theFilePox to (theFile's fileSystemRepresentation())
				open theFilePox as POSIX file
			end repeat

			activate
		end tell

		else

		tell application "QuickTime Player"
			repeat with theFile in theFiles's allObjects()
				set theFilePox to (theFile's fileSystemRepresentation())
				open theFilePox as POSIX file
			end repeat

			activate
		end tell
		end
		quit

		return yes
	end application_openFiles_

end script

--
--  AppDelegate.applescript
--  PerianOpener
--
--  Created by C.W. Betts on 9/25/13.
--  Copyright (c) 2013 Perian Team. All rights reserved.
--

script AppDelegate
	property parent : class "NSObject"

	on isMavericksOrLater()
		set osver to system version of (system info)
		(* skip the first three characters: We don't run on pre-OS X systems,
		 and we won't reach Mac OS version 100 any time soon. *)
		set osList to characters 4 thru 6 of osver
		(* If we get a decimal as the last item, the second version value is greater than 10.
		 We're looking for Mac versions greater than nine. *)
		if (osList's item 3) is equal to "." then
			return yes
			else
			set preTen to osList's as text as real
			if preTen is greater than or equal to 9.0 then
				return yes
				else
				return no
			end if
		end if
	end isMavericksOrLater

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

	on applicationDidFinishLaunching_(aNotification)
		-- Insert code here to initialize your application before any files are opened
		tell current application's NSTimer to set theTimer to scheduledTimerWithTimeInterval_target_selector_userInfo_repeats_(10, me, "timerFired:", missing value, false)
	end applicationDidFinishLaunching_

	on timerFired_(timer)
		quit
	end timerFired_

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

	on application_openFiles_(appl, theFiles)

		set mavericks to isMavericksOrLater()
		if mavericks is true
		(* TODO: check for QuickTime 7, and point the user to the download location if they don't *)
		tell application id "com.apple.quicktimeplayer"
			repeat with theFile in theFiles's allObjects()
				set theFilePox to (theFile's fileSystemRepresentation())
				open theFilePox as POSIX file
			end repeat

			activate
		end tell

		else

		tell application "QuickTime Player"
			repeat with theFile in theFiles's allObjects()
				set theFilePox to (theFile's fileSystemRepresentation())
				open theFilePox as POSIX file
			end repeat

			activate
		end tell
		end
		quit

		return yes
	end application_openFiles_

end script

Implement isMavericksOrLater on the updater.


(*
  Script object to make calling a defined function easier while in the
  iTunes and System Events name space.
*)
script remoteSpeakerFinder
  -- Given a list of buttons, find the remote speakers button
  -- by finding the first button with a name that isn't in a
  -- rejection list.
  on findCorrectButton (in_buttons)
    set buttons_to_skip to {"Burn Disc"}

    repeat with a_button in in_buttons
      try -- some buttons don't have names
        set the_name to name of a_button
        if buttons_to_skip does not contain {the_name} then
          return the_name
        end if
      end try
    end repeat

    return 16 -- default response
  end findCorrectButton
end script

(*
  Tell iTunes to use the "Mobile" set of remote speakers.
*)
tell application "System Events"
  tell process "iTunes"
     set the_buttons to (get buttons of window 1)
     set the_speaker_button to (remoteSpeakerFinder's findCorrectButton(the_buttons))

     -- Switch to the speakers in my bedroom
     set frontmost to true
     click button the_speaker_button of window 1
     key code 115                -- Home Key (first speaker in list)
     key code 125                -- Down Arrow
     key code 125                -- Down Arrow
     key code 36                 -- Return Key
  end tell
end tell

(*
  Script object to make calling a defined function easier while in the
  iTunes and System Events name space.
*)
script remoteSpeakerFinder
  -- Given a list of buttons, find the remote speakers button
  -- by finding the first button with a name that isn't in a
  -- rejection list.
  on findCorrectButton (in_buttons)
    set buttons_to_skip to {"Burn Disc"}

    repeat with a_button in in_buttons
      try -- some buttons don't have names
        set the_name to name of a_button
        if buttons_to_skip does not contain {the_name} then
          return the_name
        end if
      end try
    end repeat

    return 16 -- default response
  end findCorrectButton
end script

(*
  Tell iTunes to use the "Mobile" set of remote speakers.
*)
tell application "System Events"
  tell process "iTunes"
     set the_buttons to (get buttons of window 1)
     set the_speaker_button to (remoteSpeakerFinder's findCorrectButton(the_buttons))

     -- Switch to the speakers in my bedroom
     set frontmost to true
     click button the_speaker_button of window 1
     key code 115                -- Home Key (first speaker in list)
     key code 125                -- Down Arrow
     key code 125                -- Down Arrow
     key code 36                 -- Return Key

     -- Wait for iTunes to connect to the speakers
     delay 5
  end tell
end tell

Work around an issue with iTunes 9 that causes it to delay a connection to remote speakers


#!/usr/bin/osascript
(*
Copyright 2012 Software Freedom Conservancy. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*)

(*
This script can be used to quickly re-install the SafariDriver extension
during development.

Requirements:
- The extension must be manually installed before use
- This script must be run from the trunk.
*)

-- Keep this in sync with the name of the extension in the Info.plist
set EXTENSION to "WebDriver"

tell application "System Events"
	set ui_elements_enabled to UI elements enabled
end tell

if ui_elements_enabled is false then
	tell application "System Preferences"
		activate
		set current pane to pane id "com.apple.preference.universalaccess"
		display dialog "Please \"Enable access for assistive devices\" " & ¬
		    "and try again..."
		error number -128
	end tell
end if

tell application "Safari" to activate

tell application "System Events"
	tell process "Safari"
		tell menu bar 1
			tell menu "Develop"
				click menu item "Show Extension Builder"
				delay 1
			end tell
		end tell

		-- https://discussions.apple.com/thread/2726674?start=0&tstart=0
		tell UI element 1 of scroll area 1 of window "Extension Builder"
			set found_extension to false
			set tc to (count (groups whose its images is not {}))
			repeat with i from 1 to tc
				if exists (static text 1 of group i) then
					set t_name to name of static text 1 of group i
					if t_name is EXTENSION then
						set found_extension to true
						click button "Reload" of UI element ("ReloadUninstall" & t_name)
						exit repeat
					end if
				end if
				keystroke (character id 31)
				delay 0.2
			end repeat

			if found_extension is false then
				display dialog "Was unable to locate the extension \"" & EXTENSION ¬
				    & "\"" & return & return ¬
				    & "It must be manually installed before this script may be used."
				error number -128
			end if
		end tell
	end tell
end tell

tell application "Safari" to quit

#!/usr/bin/osascript
(*
Copyright 2012 Software Freedom Conservancy. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*)

(*
This script can be used to quickly re-install the SafariDriver extension
during development.

Requirements:
- The extension must be manually installed before use
- This script must be run from the trunk.
*)

-- Keep this in sync with the name of the extension in the Info.plist
set EXTENSION to "WebDriver"

tell application "System Events"
	set ui_elements_enabled to UI elements enabled
end tell

if ui_elements_enabled is false then
	tell application "System Preferences"
		activate
		set current pane to pane id "com.apple.preference.universalaccess"
		display dialog "Please \"Enable access for assistive devices\" " & ¬
			"and try again..."
		error number -128
	end tell
end if

tell application "Safari" to activate

tell application "System Events"
	tell process "Safari"
		tell menu bar 1
			-- tell menu "Develop"
			tell menu bar item 8
				tell menu 1
					-- click menu item "Show Extension Builder"
					click menu item 7
				end tell
			end tell
		end tell

		delay 0.2

		-- https://discussions.apple.com/thread/2726674?start=0&tstart=0
		-- tell UI element 1 of scroll area 1 of window "Extension Builder"
		tell UI element 1 of scroll area 1 of window 1
			set found_extension to false
			set tc to (count (groups whose its images is not {}))
			repeat with i from 1 to tc
				if exists (static text 1 of group i) then
					set t_name to name of static text 1 of group i
					if t_name is EXTENSION then
						set found_extension to true
						-- click button "Reload" of UI element ("ReloadUninstall" & t_name)
						click button 1 of UI element 4
						exit repeat
					end if
				end if
				keystroke (character id 31)
				delay 0.2
			end repeat

			if found_extension is false then
				display dialog "Was unable to locate the extension \"" & EXTENSION ¬
					& "\"" & return & return ¬
					& "It must be manually installed before this script may be used."
				error number -128
			end if
		end tell
	end tell
end tell

tell application "Safari" to quit

JasonLeyba: Make reinstall.scpt system language independent.

r16964


use scripting additions
use framework "Foundation"
property NSString : a reference to current application's NSString

-- Helper

on myRemoveLastPath(myPath)
set myString to NSString's stringWithString:myPath
set removedLastPathString to myString's stringByDeletingLastPathComponent
removedLastPathString as text
end myRemoveLastPath

on myFolderExists(myFolder) -- (String) as Boolean
tell application "System Events"
if exists folder myFolder then
return true
else
return false
end if
end tell
end myFolderExists

on myGetRemote(myText)
set myString to NSString's stringWithString:myText
set myParts to myString's componentsSeparatedByString:"\t"
set myFirstParts to item 1 of myParts
myFirstParts as text
end myGetRemote

-- Path

on myHomePath()
tell application "System Events"
"/Users/" & (name of current user)
end tell
end myHomePath

on myLibraryPath()
myHomePath() & "/Library"
end myLibraryPath

on myXcodePath()
myLibraryPath() & "/Developer/Xcode"
end myXcodePath

on myUserDataPath()
myXcodePath() & "/UserData"
end myUserDataPath

on myProjectPath()
tell application "Xcode"
tell active workspace document
set myPath to path
end tell
end tell
myRemoveLastPath(myPath)
end myProjectPath

-- Generic Open

on myOpenFolder(myPath)
tell application "Finder"
activate
open myPath as POSIX file
end tell
end myOpenFolder

on myOpeniTerm(myPath)
tell application "Finder"
do shell script "open -a iTerm " & quoted form of myPath
end tell
end myOpeniTerm

-- Open

on myOpenThemesFolder()
set myPath to myUserDataPath() & "/FontAndColorThemes/"
myOpenFolder(myPath)
end myOpenThemesFolder

on myOpenCodeSnippetsFolder()
set myPath to myUserDataPath() & "/CodeSnippets/"
myOpenFolder(myPath)
end myOpenCodeSnippetsFolder

on myOpenDeviceSupportFolder()
set myPath to "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport"
myOpenFolder(myPath)
end myOpenDeviceSupportFolder

on myOpenArchivesFolder()
set myPath to myXcodePath() & "/Archives/"
myOpenFolder(myPath)
end myOpenArchivesFolder

on myOpenProvisioningProfileFolder()
set myPath to myLibraryPath() & "/MobileDevice/Provisioning Profiles"
myOpenFolder(myPath)
end myOpenProvisioningProfileFolder

on myOpenProjectFolder()
set myPath to myProjectPath()
myOpenFolder(myPath)
end myOpenProjectFolder

on myOpeniTermForCurrentProject()
set myPath to myProjectPath()
myOpeniTerm(myPath)
end myOpeniTermForCurrentProject

on myOpenDerivedDataFolder()
set myRelativePath to myProjectPath() & "/DerivedData/"
if myFolderExists(myRelativePath) then
myOpenFolder(myRelativePath)
else
myOpenFolder(myXcodePath() & "/DerivedData/")
end if
end myOpenDerivedDataFolder

on myOpenGitHub()
set myPath to myProjectPath()
set myConsoleOutput to (do shell script "cd " & quoted form of myPath & "; git remote -v")
set myRemote to myGetRemote(myConsoleOutput)
set myUrl to (do shell script "cd " & quoted form of myPath & "; git config --get remote." & quoted form of myRemote & ".url")
open location myUrl
end myOpenGitHub

on myOpenDocument()
set command1 to "cd ~/Library/Developer/CoreSimulator/Devices/;"
set command2 to "cd `ls -t | head -n 1`/data/Containers/Data/Application;"
set command3 to "cd `ls -t | head -n 1`/Documents;"
set command4 to "open ."
do shell script command1 & command2 & command3 & command4
end myOpenDocument

on myOpenAbout()
open location "https://github.com/onmyway133/XcodeWay"
end myOpenAbout

use scripting additions
use framework "Foundation"
property NSString : a reference to current application's NSString

-- Helper

on myRemoveLastPath(myPath)
set myString to NSString's stringWithString:myPath
set removedLastPathString to myString's stringByDeletingLastPathComponent
removedLastPathString as text
end myRemoveLastPath

on myFolderExists(myFolder) -- (String) as Boolean
tell application "System Events"
if exists folder myFolder then
return true
else
return false
end if
end tell
end myFolderExists

on myRemoveSubString(oldString, subString)
set myString to NSString's stringWithString:oldString
set newString to myString's stringByReplacingOccurrencesOfString:subString withString:""
newString as text
end myRemoveSubString

on myGetRemote(myText)
set myString to NSString's stringWithString:myText
set myParts to myString's componentsSeparatedByString:"\t"
set myFirstParts to item 1 of myParts
myFirstParts as text
end myGetRemote

-- Path

on myHomePath()
tell application "System Events"
"/Users/" & (name of current user)
end tell
end myHomePath

on myLibraryPath()
myHomePath() & "/Library"
end myLibraryPath

on myXcodePath()
myLibraryPath() & "/Developer/Xcode"
end myXcodePath

on myUserDataPath()
myXcodePath() & "/UserData"
end myUserDataPath

on myProjectPath()
tell application "Xcode"
tell active workspace document
set myPath to path
end tell
end tell
myRemoveLastPath(myPath)
end myProjectPath

on myCurrentFilePath()
tell application "Xcode"
set activeDocument to document 1 whose name ends with (word -1 of (get name of window 1))
path of activeDocument
end tell
end myCurrentFilePath

-- Generic Open

on myOpenFolder(myPath)
tell application "Finder"
activate
open myPath as POSIX file
end tell
end myOpenFolder

on myOpeniTerm(myPath)
tell application "Finder"
do shell script "open -a iTerm " & quoted form of myPath
end tell
end myOpeniTerm

-- Open

on myOpenThemesFolder()
set myPath to myUserDataPath() & "/FontAndColorThemes/"
myOpenFolder(myPath)
end myOpenThemesFolder

on myOpenCodeSnippetsFolder()
set myPath to myUserDataPath() & "/CodeSnippets/"
myOpenFolder(myPath)
end myOpenCodeSnippetsFolder

on myOpenDeviceSupportFolder()
set myPath to "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport"
myOpenFolder(myPath)
end myOpenDeviceSupportFolder

on myOpenArchivesFolder()
set myPath to myXcodePath() & "/Archives/"
myOpenFolder(myPath)
end myOpenArchivesFolder

on myOpenProvisioningProfileFolder()
set myPath to myLibraryPath() & "/MobileDevice/Provisioning Profiles"
myOpenFolder(myPath)
end myOpenProvisioningProfileFolder

on myOpenProjectFolder()
set myPath to myProjectPath()
myOpenFolder(myPath)
end myOpenProjectFolder

on myOpeniTermForCurrentProject()
set myPath to myProjectPath()
myOpeniTerm(myPath)
end myOpeniTermForCurrentProject

on myOpenDerivedDataFolder()
set myRelativePath to myProjectPath() & "/DerivedData/"
if myFolderExists(myRelativePath) then
myOpenFolder(myRelativePath)
else
myOpenFolder(myXcodePath() & "/DerivedData/")
end if
end myOpenDerivedDataFolder

on myGitHubURL()
set myPath to myProjectPath()
set myConsoleOutput to (do shell script "cd " & quoted form of myPath & "; git remote -v")
set myRemote to myGetRemote(myConsoleOutput)
set myUrl to (do shell script "cd " & quoted form of myPath & "; git config --get remote." & quoted form of myRemote & ".url")
set myUrlWithOutDotGit to myRemoveSubString(myUrl, ".git")
end myGitHubURL

on myOpenGitHub()
set myUrl to myGitHubUrlOnMaster()
open location myUrl
end myOpenGitHub

on myGitHubUrlOnMaster()
set gitHubPath to myGitHubURL()
set myUrl to gitHubPath & "/blob/master"
end myGitHubUrlOnMaster

on myOpenFileInGitHub()
set currentFilePath to myCurrentFilePath()
set projectPath to myProjectPath()
set gitHubPath to myGitHubUrlOnMaster()
set relativePath to myRemoveSubString(currentFilePath, projectPath)
set fullUrl to gitHubPath & relativePath
open location fullUrl
end myOpenFileInGitHub

on myOpenDocument()
set command1 to "cd ~/Library/Developer/CoreSimulator/Devices/;"
set command2 to "cd `ls -t | head -n 1`/data/Containers/Data/Application;"
set command3 to "cd `ls -t | head -n 1`/Documents;"
set command4 to "open ."
do shell script command1 & command2 & command3 & command4
end myOpenDocument

on myOpenAbout()
open location "https://github.com/onmyway133/XcodeWay"
end myOpenAbout

Update script for open current document

Update script for open current document


tell application "Safari"
  repeat with t in tabs of windows
    tell t
      -- If you open lots of windows in Safari, some of this book-
      -- keeping goes wrong.  It will try to look up tab N, except
      -- tab N was already closed -- error!
      --
      -- For safety, we just catch and discard all errors.
      {% for condition in conditionss %}
      try
        tell t
          if (URL {{ condition}}) then close
        end tell
      end try
      {% endfor %}
    end tell
  end repeat
end tell

tell application "Safari"
  repeat with t in tabs of windows
    tell t
      -- If you open lots of windows in Safari, some of this book-
      -- keeping goes wrong.  It will try to look up tab N, except
      -- tab N was already closed -- error!
      --
      -- For safety, we just catch and discard all errors.
      {% for condition in conditions %}
      try
        tell t
          if (URL {{ condition}}) then close
        end tell
      end try
      {% endfor %}
    end tell
  end repeat
end tell

Fix typo in script

Fix typo in script


#!/usr/bin/env osascript

set journal to "~/ia/Journal/Journal.txt"
tell application "Terminal"
	set lineCount to (do shell script "wc -l < " & journal) as integer
	set randomLine to (random number from 1 to lineCount) as integer
	activate
	do script "vim -c ':Goyo' -c ':set bg=light' " & journal & ":" & randomLine
	set current settings of first window to settings set "Solarized Light"
	tell application "System Events" to keystroke "f" using {command down, control down}
end tell

#!/usr/bin/env osascript

set journal to "~/ia/Journal/Journal.txt"
tell application "Terminal"
	set lineCount to (do shell script "wc -l < " & journal) as integer
	set randomLine to (random number from 1 to lineCount) as integer
	activate
	do script "vim -c ':Goyo | set bg=light | " & randomLine & "' " & journal
	set current settings of first window to settings set "Solarized Light"
	tell application "System Events" to keystroke "f" using {command down, control down}
end tell

Update recall script so it works with nvim


on newPresentation(themeName)
	tell application "Keynote"
		activate
		-- FIXME: Make this selectable?
		set targetWidth to 1024 -- 1440 <-- higher resolution
		set targetHeight to 768 -- 1080 <-- higher resolution

		set props to {document theme:theme (themeName as string), width:targetWidth, height:targetHeight}

		set thisDocument to make new document with properties props
		return name of thisDocument
	end tell
end newPresentation

on openPresentation(posixPath)
	tell application "Keynote"
		open posixPath
	end tell
end openPresentation

on savePresentation(docname, posixPath)
	tell application "Keynote"
		save document named docname in POSIX file posixPath
	end tell
end savePresentation

on createSlide(docname, masterSlideName)
	try
		tell application "Keynote"
			tell document named docname
				set thisSlide to make new slide with properties {base slide:master slide masterSlideName}
			end tell
	  return thisSlide
		end tell
	on error
		return 0
	end try
end createSlide

on deleteAllSlides(docname)
	tell application "Keynote"
		tell document named docname to delete every slide
	end tell
end deleteAllSlides

on finalize(docname)
	tell application "Keynote"
		tell document named docname to delete slide 1
	end tell
end finalize

on themeMasters(docname)
	--	  tell application "Keynote" to get the name of every master slide of thisDocument
	tell application "Keynote"
		set names to the name of every master slide of document named docname
		return names
	end tell
end themeMasters

on addImage(docname, filepath)
  (*
	FIXME: Use slide ID to adress slide instead of "current slide"
  *)
  tell application "Keynote"
	tell document named docname
		tell the current slide

			-- TO REPLACE A PLACEHOLDER OR EXISTING IMAGE:
			set thisPlaceholderImageItem to image 1
			-- change the value of the “file name” property of the image to be an HFS file reference to the replacement image file
		set macPath to POSIX file filepath as Unicode text
			set file name of thisPlaceholderImageItem to ¬
				alias macPath

		end tell
	end tell
  end tell
end addImage

on addTitle(docname, thisSlideTitle)
  (*
	FIXME: Use slide ID to adress slide instead of "current slide"
  *)
	tell application "Keynote"
		tell document named docname
			tell the current slide
				if title showing is true then
					set the object text of the default title item to thisSlideTitle
				end if
			end tell
		end tell
	end tell
end addTitle

on addBody(docname, thisSlideBody)
  (*
	FIXME: Use slide ID to adress slide instead of "current slide"
  *)
	tell application "Keynote"
		tell document named docname
			tell the current slide
				if body showing is true then
					set the object text of the default body item to thisSlideBody
				end if
			end tell
		end tell
	end tell
end addTitle

on newPresentation(themeName)
	tell application "Keynote"
		activate
		-- FIXME: Make this selectable?
		set targetWidth to 1024 -- 1440 <-- higher resolution
		set targetHeight to 768 -- 1080 <-- higher resolution

		set props to {document theme:theme (themeName as string), width:targetWidth, height:targetHeight}

		set thisDocument to make new document with properties props
		return name of thisDocument
	end tell
end newPresentation

on openPresentation(posixPath)
	tell application "Keynote"
		open posixPath
	end tell
end openPresentation

on savePresentation(docname, posixPath)
	tell application "Keynote"
		save document named docname in POSIX file posixPath
	end tell
end savePresentation

on createSlide(docname, masterSlideName)
	try
		tell application "Keynote"
			tell document named docname
				set thisSlide to make new slide with properties {base slide:master slide masterSlideName}
			end tell
	  return thisSlide
		end tell
	on error
		return 0
	end try
end createSlide

on deleteAllSlides(docname)
	tell application "Keynote"
		tell document named docname to delete every slide
	end tell
end deleteAllSlides

on finalize(docname)
	tell application "Keynote"
		tell document named docname to delete slide 1
	end tell
end finalize

on themeMasters(docname)
	--	  tell application "Keynote" to get the name of every master slide of thisDocument
	tell application "Keynote"
		set names to the name of every master slide of document named docname
		return names
	end tell
end themeMasters

on addImage(docname, n, filepath)
  (*
	FIXME: Use slide ID to adress slide instead of "current slide"
  *)
  tell application "Keynote"
	tell document named docname
		tell the current slide

			-- TO REPLACE A PLACEHOLDER OR EXISTING IMAGE:
			set thisPlaceholderImageItem to image n
			-- change the value of the “file name” property of the image to be an HFS file reference to the replacement image file
		set macPath to POSIX file filepath as Unicode text
			set file name of thisPlaceholderImageItem to ¬
				alias macPath

		end tell
	end tell
  end tell
end addImage

on addTitle(docname, thisSlideTitle)
  (*
	FIXME: Use slide ID to adress slide instead of "current slide"
  *)
	tell application "Keynote"
		tell document named docname
			tell the current slide
				if title showing is true then
					set the object text of the default title item to thisSlideTitle
				end if
			end tell
		end tell
	end tell
end addTitle

on addBody(docname, thisSlideBody)
  (*
	FIXME: Use slide ID to adress slide instead of "current slide"
  *)
	tell application "Keynote"
		tell document named docname
			tell the current slide
				if body showing is true then
					set the object text of the default body item to thisSlideBody
				end if
			end tell
		end tell
	end tell
end addTitle

Select placeholder for images

Select placeholder for images