--
--  slideshow -- Observe and Control Slideshow Applications
--  Copyright (c) 2014 Ralf S. Engelschall <http://engelschall.com>
--
--  This Source Code Form is subject to the terms of the Mozilla Public
--  License (MPL), version 2.0. If a copy of the MPL was not distributed
--  with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
--
--  File:     connector-osx-ppt.js
--  Purpose:  connector engine for Microsoft PowerPoint under Mac OS X
--  Language: AppleScript
--

--  utility function
on filterText(this_text, allowed_chars)
   set new_text to ""
   repeat with this_char in this_text
       set x to the offset of this_char in allowed_chars
       if x is not 0 then
           set new_text to (new_text & this_char) as string
       end if
   end repeat
   return new_text
end filterText

--  utility function
on replaceText(this_text, search_string, replacement_string)
   set AppleScript's text item delimiters to the search_string
   set the item_list to every text item of this_text
   set AppleScript's text item delimiters to the replacement_string
   set this_text to the item_list as string
   set AppleScript's text item delimiters to ""
   return this_text
end replace_chars

--  utility function
on asciiCharset()
    set charset to " \"'!#$%()*+,-./:;<=>?@[\\]^_{|}~"
    set charset to (charset & "0123456789")
    set charset to (charset & "ABCDEFGHIJKLMNOPQRSTUVWXYZ")
    set charset to (charset & "abcdefghijklmnopqrstuvwxyz")
    return charset
end asciiCharset

--  get application state
on is_running(appName)
    tell application "System Events" to (name of processes) contains appName
end is_running
on pptGetState()
    set state to "closed"
    if is_running("Microsoft PowerPoint") then
       try
            set state to "running"
            tell application "Microsoft PowerPoint"
                set theState to (slide state of slide show view of slide show window of active presentation)
                if theState is (slide show state running) or theState is (slide show state paused) then
                    set state to "viewing"
                else if (exists active presentation) then
                    set state to "editing"
                end if
            end tell
        on error errMsg
        end try
    end if
    return state
end pptGetState

--  get current slide
on pptGetCurSlide()
    try
        tell application "Microsoft PowerPoint"
            if slide state of slide show view of slide show window of active presentation is slide show state running then
                --  currently in running slide show mode (for production)
                set curSlide to (slide number of slide of slide show view of slide show window of active presentation)
            else
                --  currently in editing mode (for testing)
                set curSlide to (slide number of slide range of selection of document window 1)
            end if
            return curSlide
        end tell
    on error errMsg
        return 0
    end try
end pptGetCurSlide

--  get maximum slide
on pptGetMaxSlide()
    try
        tell application "Microsoft PowerPoint"
            set maxSlide to (get count of slides of presentation of document window 1)
            return maxSlide
        end tell
    on error errMsg
        return 0
    end try
end pptGetMaxSlide

--  the STATE command
on cmdSTATE()
    set state to pptGetState()
    if state is "closed" then
        set position to 0
        set slides to 0
    else
        set position to pptGetCurSlide()
        set slides to pptGetMaxSlide()
    end if
    return ("{ \"response\": { " & ¬
        "\"state\": \"" & state & "\", " & ¬
        "\"position\": " & position & ", " & ¬
        "\"slides\": " & slides & " " & ¬
    "} }")
end cmdSTATE

--  the INFO command
on cmdINFO()
    set output to ""
    if pptGetMaxSlide() is 0 then
        error "still no active presentation"
    end if
    tell application "Microsoft PowerPoint"
        set thePresentation to presentation of document window 1
        set theTitles to ""
        set theNotes to ""
        set slideCount to (get count of slides of thePresentation)
        repeat with slideNum from 1 to slideCount
            set theSlide to slide slideNum of thePresentation

            set theTitle to ""
            repeat with t_shape in (get shapes of theSlide)
                set aType to (placeholder type of t_shape)
                if (aType is placeholder type center title placeholder) or (aType is placeholder type title placeholder) then
                    tell t_shape to if has text frame then tell its text frame to if has text then
                        set theText to (content of its text range as string) as string
                        set theText to (my filterText(theText, my asciiCharset()))
                        if theTitle is not "" then
                            set theTitle to (theTitle & " ")
                        end if
                        set theTitle to (theTitle & theText)
                    end if
                end if
            end repeat
            if theTitles is not "" then
                set theTitles to (theTitles & ", ")
            end if
            set theTitles to (theTitles & "\"" & (my replaceText(theTitle, "\"", "\\\"")) & "\"")

            set theNote to ""
            repeat with t_shape in (get shapes of notes page of theSlide)
                set aType to (placeholder type of t_shape)
                if (aType is placeholder type body placeholder) then
                    tell t_shape to if has text frame then tell its text frame to if has text then
                        set theText to (content of its text range as string) as string
                        set theText to (my filterText(theText, my asciiCharset()))
                        if theNote is not "" then
                            set theNote to (theNote & " ")
                        end if
                        set theNote to (theNote & theText)
                    end if
                end if
            end repeat
            if theNotes is not "" then
                set theNotes to (theNotes & ", ")
            end if
            set theNotes to (theNotes & "\"" & (my replaceText(theNote, "\"", "\\\"")) & "\"")

        end repeat
        set theTitles to ("[ " & theTitles & " ]")
        set theNotes to ("[ " & theNotes & " ]")
        set output to ("{ \"response\": { \"titles\": " & theTitles & ", \"notes\": " & theNotes & " } }")
    end tell
    return output
end cmdINFO

--  the control commands
on cmdCTRL(command, arg)
    set state to pptGetState()
    if command is "BOOT" then
        if state is not "closed" then
            error "application already running"
        end if
        tell application "Microsoft PowerPoint"
            activate
        end tell
    else if command is "QUIT" then
        if state is "closed" then
            error "application already closed"
        end if
        tell application "Microsoft PowerPoint"
            quit
        end tell
    else if command is "OPEN" then
        if state is "editing" or state is "viewing" then
            error "active presentation already existing"
        end if
        tell application "Microsoft PowerPoint"
            tell application "Finder" to set thePath to ¬
                POSIX file (POSIX path of (container of (path to me) as string) & (arg)) as alias
            open thePath
        end tell
    else if command is "CLOSE" then
        if state is "closed" or state is "running" then
            error "still no active presentation"
        end if
        tell application "Microsoft PowerPoint"
            close active presentation
        end tell
    else if command is "START" then
        if state is "closed" or state is "running" then
            error "still no active presentation"
        end if
        if state is "viewing" then
            error "active presentation already viewing"
        end if
        tell application "Microsoft PowerPoint"
            set slideShowSettings to slide show settings of active presentation
            set slideShowSettings's starting slide to 1
            set slideShowSettings's ending slide to 1
            set slideShowSettings's range type to slide show range
            set slideShowSettings's show type to slide show type speaker
            set slideShowSettings's advance mode to slide show advance manual advance
            run slide show slideShowSettings -- BUGGY: starts blank
        end tell
    else if command is "STOP" then
        if state is not "viewing" then
            error "no active slideshow"
        end if
        tell application "Microsoft PowerPoint"
            exit slide show (slideshow view of slide show window 1)
        end tell
    else if command is "BLACK" then
        if state is not "viewing" then
            error "no active slideshow"
        end if
        tell application "Microsoft PowerPoint"
            set slide state of (slideshow view of slide show window 1) to (slide show state black screen)
        end tell
    else if command is "NORMAL" then
        if state is not "viewing" then
            error "no active slideshow"
        end if
        tell application "Microsoft PowerPoint"
            -- set slide state of (slideshow view of slide show window 1) to (slide show state paused)
            go to slide (view of document window 1) number ¬
                (slide number of slide of slide show view of slide show window of active presentation)
        end tell
    else if command is "FIRST" then
        if state is not "viewing" then
            error "no active slideshow"
        end if
        tell application "Microsoft PowerPoint"
            go to first slide (slideshow view of slide show window 1)
        end tell
    else if command is "LAST" then
        if state is not "viewing" then
            error "no active slideshow"
        end if
        tell application "Microsoft PowerPoint"
            go to last slide (slideshow view of slide show window 1)
        end tell
    else if command is "GOTO" then
        if state is not "viewing" then
            error "no active slideshow"
        end if
        tell application "Microsoft PowerPoint"
            go to slide (view of document window 1) number (arg as integer) -- BUGGY: does not do anything
        end tell
    else if command is "PREV" then
        if state is not "viewing" then
            error "no active slideshow"
        end if
        tell application "Microsoft PowerPoint"
            go to previous slide (slideshow view of slide show window 1)
        end tell
    else if command is "NEXT" then
        if state is not "viewing" then
            error "no active slideshow"
        end if
        tell application "Microsoft PowerPoint"
            go to next slide (slideshow view of slide show window 1)
        end tell
    end if
    return "{ \"result\": \"OK\" }"
end cmdCTRL

--  main procedure
on run argv
    set cmd to item 1 of argv
    set arg to ""
    if count of argv is 2 then
        set arg to item 2 of argv
    end if
    try
        if cmd is "STAT" then
            set output to cmdSTATE()
        else if cmd is "INFO" then
            set output to cmdINFO()
        else if cmd is "BOOT" ¬
            or cmd is "QUIT" ¬
            or cmd is "OPEN" ¬
            or cmd is "CLOSE" ¬
            or cmd is "START" ¬
            or cmd is "STOP" ¬
            or cmd is "BLACK" ¬
            or cmd is "NORMAL" ¬
            or cmd is "FIRST" ¬
            or cmd is "LAST" ¬
            or cmd is "GOTO" ¬
            or cmd is "PREV" ¬
            or cmd is "NEXT" then
            set output to cmdCTRL(cmd, arg)
        else
            set output to "{ \"error\": \"invalid command\" }"
        end if
    on error errMsg
        set output to ("{ \"error\": \"" & errMsg & "\" }")
    end try
    copy output to stdout
end run

--
--  slideshow -- Observe and Control Slideshow Applications
--  Copyright (c) 2014 Ralf S. Engelschall <http://engelschall.com>
--
--  This Source Code Form is subject to the terms of the Mozilla Public
--  License (MPL), version 2.0. If a copy of the MPL was not distributed
--  with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
--
--  File:     connector-osx-ppt.js
--  Purpose:  connector engine for Microsoft PowerPoint under Mac OS X
--  Language: AppleScript
--

--  utility function
on filterText(this_text, allowed_chars)
   set new_text to ""
   repeat with this_char in this_text
       set x to the offset of this_char in allowed_chars
       if x is not 0 then
           set new_text to (new_text & this_char) as string
       end if
   end repeat
   return new_text
end filterText

--  utility function
on replaceText(this_text, search_string, replacement_string)
   set AppleScript's text item delimiters to the search_string
   set the item_list to every text item of this_text
   set AppleScript's text item delimiters to the replacement_string
   set this_text to the item_list as string
   set AppleScript's text item delimiters to ""
   return this_text
end replace_chars

--  utility function
on asciiCharset()
    set charset to " \"'!#$%()*+,-./:;<=>?@[\\]^_{|}~"
    set charset to (charset & "0123456789")
    set charset to (charset & "ABCDEFGHIJKLMNOPQRSTUVWXYZ")
    set charset to (charset & "abcdefghijklmnopqrstuvwxyz")
    return charset
end asciiCharset

--  get application state
on pptGetState()
    set state to "closed"
    tell application "System Events"
        set is_running to (exists (some process whose name is "Microsoft PowerPoint"))
    end tell
    if is_running then
       try
            set state to "running"
            tell application "Microsoft PowerPoint"
                set theState to (slide state of slide show view of slide show window of active presentation)
                if theState is (slide show state running) or theState is (slide show state paused) then
                    set state to "viewing"
                else if (exists active presentation) then
                    set state to "editing"
                end if
            end tell
        on error errMsg
        end try
    end if
    return state
end pptGetState

--  get current slide
on pptGetCurSlide()
    try
        tell application "Microsoft PowerPoint"
            if slide state of slide show view of slide show window of active presentation is slide show state running then
                --  currently in running slide show mode (for production)
                set curSlide to (slide number of slide of slide show view of slide show window of active presentation)
            else
                --  currently in editing mode (for testing)
                set curSlide to (slide number of slide range of selection of document window 1)
            end if
            return curSlide
        end tell
    on error errMsg
        return 0
    end try
end pptGetCurSlide

--  get maximum slide
on pptGetMaxSlide()
    try
        tell application "Microsoft PowerPoint"
            set maxSlide to (get count of slides of presentation of document window 1)
            return maxSlide
        end tell
    on error errMsg
        return 0
    end try
end pptGetMaxSlide

--  the STATE command
on cmdSTATE()
    set state to pptGetState()
    if state is "closed" then
        set position to 0
        set slides to 0
    else
        set position to pptGetCurSlide()
        set slides to pptGetMaxSlide()
    end if
    return ("{ \"response\": { " & ¬
        "\"state\": \"" & state & "\", " & ¬
        "\"position\": " & position & ", " & ¬
        "\"slides\": " & slides & " " & ¬
    "} }")
end cmdSTATE

--  the INFO command
on cmdINFO()
    set output to ""
    if pptGetMaxSlide() is 0 then
        error "still no active presentation"
    end if
    tell application "Microsoft PowerPoint"
        set thePresentation to presentation of document window 1
        set theTitles to ""
        set theNotes to ""
        set slideCount to (get count of slides of thePresentation)
        repeat with slideNum from 1 to slideCount
            set theSlide to slide slideNum of thePresentation

            set theTitle to ""
            repeat with t_shape in (get shapes of theSlide)
                set aType to (placeholder type of t_shape)
                if (aType is placeholder type center title placeholder) or (aType is placeholder type title placeholder) then
                    tell t_shape to if has text frame then tell its text frame to if has text then
                        set theText to (content of its text range as string) as string
                        set theText to (my filterText(theText, my asciiCharset()))
                        if theTitle is not "" then
                            set theTitle to (theTitle & " ")
                        end if
                        set theTitle to (theTitle & theText)
                    end if
                end if
            end repeat
            if theTitles is not "" then
                set theTitles to (theTitles & ", ")
            end if
            set theTitles to (theTitles & "\"" & (my replaceText(theTitle, "\"", "\\\"")) & "\"")

            set theNote to ""
            repeat with t_shape in (get shapes of notes page of theSlide)
                set aType to (placeholder type of t_shape)
                if (aType is placeholder type body placeholder) then
                    tell t_shape to if has text frame then tell its text frame to if has text then
                        set theText to (content of its text range as string) as string
                        set theText to (my filterText(theText, my asciiCharset()))
                        if theNote is not "" then
                            set theNote to (theNote & " ")
                        end if
                        set theNote to (theNote & theText)
                    end if
                end if
            end repeat
            if theNotes is not "" then
                set theNotes to (theNotes & ", ")
            end if
            set theNotes to (theNotes & "\"" & (my replaceText(theNote, "\"", "\\\"")) & "\"")

        end repeat
        set theTitles to ("[ " & theTitles & " ]")
        set theNotes to ("[ " & theNotes & " ]")
        set output to ("{ \"response\": { \"titles\": " & theTitles & ", \"notes\": " & theNotes & " } }")
    end tell
    return output
end cmdINFO

--  the control commands
on cmdCTRL(command, arg)
    set state to pptGetState()
    if command is "BOOT" then
        if state is not "closed" then
            error "application already running"
        end if
        tell application "Microsoft PowerPoint"
            activate
        end tell
    else if command is "QUIT" then
        if state is "closed" then
            error "application already closed"
        end if
        tell application "Microsoft PowerPoint"
            quit
        end tell
    else if command is "OPEN" then
        if state is "editing" or state is "viewing" then
            error "active presentation already existing"
        end if
        tell application "Microsoft PowerPoint"
            tell application "Finder" to set thePath to ¬
                POSIX file (POSIX path of (container of (path to me) as string) & (arg)) as alias
            open thePath
        end tell
    else if command is "CLOSE" then
        if state is "closed" or state is "running" then
            error "still no active presentation"
        end if
        tell application "Microsoft PowerPoint"
            close active presentation
        end tell
    else if command is "START" then
        if state is "closed" or state is "running" then
            error "still no active presentation"
        end if
        if state is "viewing" then
            error "active presentation already viewing"
        end if
        tell application "Microsoft PowerPoint"
            set slideShowSettings to slide show settings of active presentation
            set slideShowSettings's starting slide to 1
            set slideShowSettings's ending slide to 1
            set slideShowSettings's range type to slide show range
            set slideShowSettings's show type to slide show type speaker
            set slideShowSettings's advance mode to slide show advance manual advance
            run slide show slideShowSettings -- BUGGY: starts blank
        end tell
    else if command is "STOP" then
        if state is not "viewing" then
            error "no active slideshow"
        end if
        tell application "Microsoft PowerPoint"
            exit slide show (slideshow view of slide show window 1)
        end tell
    else if command is "BLACK" then
        if state is not "viewing" then
            error "no active slideshow"
        end if
        tell application "Microsoft PowerPoint"
            set slide state of (slideshow view of slide show window 1) to (slide show state black screen)
        end tell
    else if command is "NORMAL" then
        if state is not "viewing" then
            error "no active slideshow"
        end if
        tell application "Microsoft PowerPoint"
            -- set slide state of (slideshow view of slide show window 1) to (slide show state paused)
            go to slide (view of document window 1) number ¬
                (slide number of slide of slide show view of slide show window of active presentation)
        end tell
    else if command is "FIRST" then
        if state is not "viewing" then
            error "no active slideshow"
        end if
        tell application "Microsoft PowerPoint"
            go to first slide (slideshow view of slide show window 1)
        end tell
    else if command is "LAST" then
        if state is not "viewing" then
            error "no active slideshow"
        end if
        tell application "Microsoft PowerPoint"
            go to last slide (slideshow view of slide show window 1)
        end tell
    else if command is "GOTO" then
        if state is not "viewing" then
            error "no active slideshow"
        end if
        tell application "Microsoft PowerPoint"
            go to slide (view of document window 1) number (arg as integer) -- BUGGY: does not do anything
        end tell
    else if command is "PREV" then
        if state is not "viewing" then
            error "no active slideshow"
        end if
        tell application "Microsoft PowerPoint"
            go to previous slide (slideshow view of slide show window 1)
        end tell
    else if command is "NEXT" then
        if state is not "viewing" then
            error "no active slideshow"
        end if
        tell application "Microsoft PowerPoint"
            go to next slide (slideshow view of slide show window 1)
        end tell
    end if
    return "{ \"result\": \"OK\" }"
end cmdCTRL

--  main procedure
on run argv
    set cmd to item 1 of argv
    set arg to ""
    if count of argv is 2 then
        set arg to item 2 of argv
    end if
    try
        if cmd is "STAT" then
            set output to cmdSTATE()
        else if cmd is "INFO" then
            set output to cmdINFO()
        else if cmd is "BOOT" ¬
            or cmd is "QUIT" ¬
            or cmd is "OPEN" ¬
            or cmd is "CLOSE" ¬
            or cmd is "START" ¬
            or cmd is "STOP" ¬
            or cmd is "BLACK" ¬
            or cmd is "NORMAL" ¬
            or cmd is "FIRST" ¬
            or cmd is "LAST" ¬
            or cmd is "GOTO" ¬
            or cmd is "PREV" ¬
            or cmd is "NEXT" then
            set output to cmdCTRL(cmd, arg)
        else
            set output to "{ \"error\": \"invalid command\" }"
        end if
    on error errMsg
        set output to ("{ \"error\": \"" & errMsg & "\" }")
    end try
    copy output to stdout
end run

simplify the process check

simplify the process check


(*
Copyright (c) 2015-present, Facebook, Inc.
All rights reserved.

This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree. An additional grant
of patent rights can be found in the PATENTS file in the same directory.
*)

on run argv
  set theURL to item 1 of argv

  tell application "Chrome"

    if (count every window) = 0 then
      make new window
    end if

    -- Find a tab currently running the debugger
    set found to false
    set theTabIndex to -1
    repeat with theWindow in every window
      set theTabIndex to 0
      repeat with theTab in every tab of theWindow
        set theTabIndex to theTabIndex + 1
        if theTab's URL is theURL then
          set found to true
          exit repeat
        end if
      end repeat

      if found then
        exit repeat
      end if
    end repeat

    if found then
      tell theTab to reload
      set index of theWindow to 1
      set theWindow's active tab index to theTabIndex
    else
      tell window 1
        activate
        make new tab with properties {URL:theURL}
      end tell
    end if
  end tell
end run

(*
Copyright (c) 2015-present, Facebook, Inc.
All rights reserved.

This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree. An additional grant
of patent rights can be found in the PATENTS file in the same directory.
*)

property targetTab: null
property targetTabIndex: -1
property targetWindow: null

on run argv
  set theURL to item 1 of argv

  tell application "Chrome"

    if (count every window) = 0 then
      make new window
    end if

    -- 1: Looking for tab running debugger
    -- then, Reload debugging tab if found
    -- then return
    set found to my lookupTabWithUrl(theURL)
    if found then
      set targetWindow's active tab index to targetTabIndex
      tell targetTab to reload
      tell targetWindow to activate
      set index of targetWindow to 1
      return
    end if

    -- 2: Looking for Empty tab
    -- In case debugging tab was not found
    -- We try to find an empty tab instead
    set found to my lookupTabWithUrl("chrome://newtab/")
    if found then
      set targetWindow's active tab index to targetTabIndex
      set URL of targetTab to theURL
      tell targetWindow to activate
      return
    end if

    -- 3: Create new tab
    -- both debugging and empty tab were not found
    -- make a new tab with url
    tell window 1
      activate
      make new tab with properties {URL:theURL}
    end tell
  end tell
end run

-- Function:
-- Lookup tab with given url
-- if found, store tab, index, and window in properties
-- (properties were declared on top of file)
on lookupTabWithUrl(lookupUrl)
  tell application "Chrome"
    -- Find a tab with the given url
    set found to false
    set theTabIndex to -1
    repeat with theWindow in every window
      set theTabIndex to 0
      repeat with theTab in every tab of theWindow
        set theTabIndex to theTabIndex + 1
        if (theTab's URL as string) contains lookupUrl then
          -- assign tab, tab index, and window to properties
          set targetTab to theTab
          set targetTabIndex to theTabIndex
          set targetWindow to theWindow
          set found to true
          exit repeat
        end if
      end repeat

      if found then
        exit repeat
      end if
    end repeat
  end tell
  return found
end lookupTabWithUrl

Upgrade apple script

Upgrade apple script


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

-- 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 myUrl to (do shell script "cd /Users/khoa/XcodeProject2/XcodeWay; git config --get remote.origin.url")
end myOpenGitHub

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

-- 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 myUrl to (do shell script "cd " & quoted form of myPath & "; git config --get remote.origin.url")
open location myUrl
end myOpenGitHub

Fix myOpenGitHub

Fix myOpenGitHub


-- This script creates a new Safari window with all the starred articles in a NetNewsWire instance, each in its own tab

-- declare the safariWindow property here so we can use is throughout the whole script

property safariWindow : missing value

-- the openTabInSafari() function opens a new tab in the appropriate window

to openTabInSafari(theUrl)
	tell application "Safari"
		-- test if this is the first call to openTabInSafari()
		if (my safariWindow is missing value) then
			-- first time through, make a new window with the given url in the only tab
			set newdoc to make new document at front with properties {URL:theUrl}
			-- because we created the doucument "at front", we know it is window 1
			set safariWindow to window 1
		else
			-- after the first time, make a new tab in the wndow we created the first tim
			tell safariWindow
				make new tab with properties {URL:theUrl}
			end tell
		end if
	end tell
end openTabInSafari

-- the script starts here
-- First, initialize safariWindow to be missing value, so that the first time through
-- openTabInSafari() we'll make a new window to hold all our articles

set safariWindow to missing value

-- Then we loop though all the feeds of all the accounts
-- for each feed, we find all the starred articles
--for each one of those, open a new tab in Safari

tell application "NetNewsWire"
	set allAccounts to every account
	repeat with nthAccount in allAccounts
    set userFeeds to allFeeds of nthAccount
		repeat with nthFeed in userFeeds
			set starredArticles to (get every article of nthFeed where starred is true)
			repeat with nthArticle in starredArticles
				my openTabInSafari(url of nthArticle)
			end repeat
		end repeat
	end repeat
end tell

Align indentation in AppleScript example file


FasdUAS 1.101.10
k
l
r
J

m

puma -p 3000
mJruby script/websocket-server.rb start
m&guard -P livereload
mgulp
	o0commandlistcommandList
l
l
O
k
!!"#
"I

.miscactvnullobj #$
$r%&
%c'(
'l)
)n*+
*1

fvtg
+4,

brow
,m
(m

ctxt
&o0
currentdir
currentDir
 m
--MACSalisrSolid Stone3H+8
Finder.app(	 CoreServices3d8765Solid Stone:System:Library:CoreServices:Finder.app
Finder.appSolid Stone&System/Library/CoreServices/Finder.app/./
.l/01
0l$2
2I$3
.sysodelanullnmbr
3m 145
4l56
6l%7
7O%89
8k)::;<
;I).
.miscactvnullobj <=>
=I/I?@
.coredoscnullctxt
?b/8AB
Ab/4CD
Cm/0EEFFcd
Dl03G
Gn03HI
H113

psxp
Io010
currentdir
currentDir
Bm47JJKK..@L

kfil
Ln;EMN
M1AE

tcnt
Nl;AO
O4;AP

cwin
Pm?@>QR
QlJJRST
SIJOU
.sysodelanullnmbr
UmJKTVW
VlPPWX
XYPYZ[
Yk^\\]^
]Z^_`
_?^aab
ao^_0n
bm_`
`kdccde
dIdif
.sysodelanullnmbr
fmdeeg
gOjhi
hIpjk
.prcskprsnullctxt
jmpsllmmtkn

faal
nJv{oop
pmvy
eMdsKcmd
imjmqqsevsalisSolid Stone3H+8System Events.appl	 CoreServices3d876<Solid Stone:System:Library:CoreServices:System Events.app$System Events.appSolid Stone-System/Library/CoreServices/System Events.app/^rs
rItu
.coredoscnullctxt
tlv
vnwx
w4y

cobj
yo0n
xo0commandlistcommandListuz

kfil
zn{|
{1

tcnt
|l}
}4~

cwin
~ms
I
.sysodelanullnmbr
m0n
ZmST
[ITY
.corecnte********
oTU0commandlistcommandList
9m%&@alisjSolid Stone3H+ITerminal.appB	 	Utilities3d"IW1Solid Stone:Applications:Utilities:Terminal.appTerminal.appSolid Stone#Applications/Utilities/Terminal.app/
.aevtoappnull****0commandlistcommandList0
currentdir
currentDir
.aevtoappnull****
k060n
-EJql0commandlistcommandList
.miscactvnullobj

brow

fvtg

ctxt0
currentdir
currentDir
.sysodelanullnmbr

psxp

kfil

cwin

tcnt
.coredoscnullctxt
.corecnte********

faal
eMdsKcmd
.prcskprsnullctxt

cobjvEO*jO*k/,&EUOkjO*jO,%a%a*ak/a,lOkjOVkjkhk!kjOaaaakvlUYhOa/a*ak/a,lOkj[OYU
jSolid Stone:Users:mrflix:Projects:git:zammad:contrib:ascr
ޭ

FasdUAS 1.101.10
k
l
r
J

m

puma -p 3000
mJruby script/websocket-server.rb start
m&guard -P livereload
mgulp
	o0commandlistcommandList
l
l
O
k
!!"#
"I

.miscactvnullobj #$
$r%&
%c'(
'l)
)n*+
*1

fvtg
+4,

brow
,m
(m

ctxt
&o0
currentdir
currentDir
 m
--MACSalisrSolid Stone3H+k
Finder.appJ	 CoreServices3drkji5Solid Stone:System:Library:CoreServices:Finder.app
Finder.appSolid Stone&System/Library/CoreServices/Finder.app/./
.l/01
0l$2
2I$3
.sysodelanullnmbr
3m 145
4l56
6l%7
7O%89
8k)::;<
;I).
.miscactvnullobj <=>
=I/I?@
.coredoscnullctxt
?b/8AB
Ab/4CD
Cm/0EEFFcd
Dl03G
Gn03HI
H113

psxp
Io010
currentdir
currentDir
Bm47JJKK..@L

kfil
Ln;EMN
M1AE

tcnt
Nl;AO
O4;AP

cwin
Pm?@>QR
QlJJRST
SIJOU
.sysodelanullnmbr
UmJKTVW
VlPPWX
XYPYZ[
Yk^\\]^
]Z^_`
_?^aab
ao^_0n
bm_`
`kdccde
dIdif
.sysodelanullnmbr
fmdeeg
gOjhi
hIpjk
.prcskprsnullctxt
jmpsllmmtkn

faal
nJv{oop
pmvy
eMdsKcmd
imjmqqsevsalisSolid Stone3H+kSystem Events.app	 CoreServices3dkji<Solid Stone:System:Library:CoreServices:System Events.app$System Events.appSolid Stone-System/Library/CoreServices/System Events.app/^rs
rItu
.coredoscnullctxt
tlv
vnwx
w4y

cobj
yo0n
xo0commandlistcommandListuz

kfil
zn{|
{1

tcnt
|l}
}4~

cwin
~ms
I
.sysodelanullnmbr
m0n
ZmST
[ITY
.corecnte********
oTU0commandlistcommandList
9m%&@alisjSolid Stone3H+Terminal.appB	 	Utilities3d"1Solid Stone:Applications:Utilities:Terminal.appTerminal.appSolid Stone#Applications/Utilities/Terminal.app/
.aevtoappnull****0commandlistcommandList0
currentdir
currentDir
.aevtoappnull****
k060n
-EJql0commandlistcommandList
.miscactvnullobj

brow

fvtg

ctxt0
currentdir
currentDir
.sysodelanullnmbr

psxp

kfil

cwin

tcnt
.coredoscnullctxt
.corecnte********

faal
eMdsKcmd
.prcskprsnullctxt

cobjvEO*jO*k/,&EUOkjO*jO,%a%a*ak/a,lOkjOVkjkhk!kjOaaaakvlUYhOa/a*ak/a,lOkj[OYU
jSolid Stone:Users:mrflix:Projects:git:zammad:contrib:ascr
ޭ

update dev autostart script

update dev autostart script


-- core configuration --

-- configurable options --

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

-- workflow parameters --

property homeFolder : (path to home folder as text)
property libraryFolder : (path to library folder from user domain as text)
property cacheFolder : (libraryFolder & "Caches:")
property alfredWorkflowDataFolder : (cacheFolder & "com.runningwithcrayons.Alfred-3:Workflow Data:")
property bundleId : "com.calebevans.playsong"
property workflowCacheFolder : (alfredWorkflowDataFolder & bundleId & ":") as text
property artworkCacheFolderName : "Album Artwork"
property artworkCachePath : (workflowCacheFolder & artworkCacheFolderName & ":")
property songArtworkNameSep : " | "
property defaultIconName : "resources/icon-noartwork.png"
-- the name of the playlist used by the workflow for playing songs
property workflowPlaylistName : "Alfred Play Song"
-- the text used to determine if a track is an audio file
property songDescriptor : "audio"
-- list of Alfred results
property resultList : {}

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

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

end replace

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

	if theNumber is 1 then

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

	else

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

	end if

	return theString

end quantifyNumber

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

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

end encodeFeedbackChars

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

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

end decodeFeedbackChars

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

	copy theResult to the end of resultList

end addResult

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

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

end addNoResultsItem

on resultListIsFull()

	return (length of resultList is resultLimit)

end resultListIsFull

on resultListIsEmpty()

	return (length of resultList is 0)

end resultListIsFull

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

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

	if (icon of theResult) contains ":" then

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

	else

		set resultIcon to icon of theResult

	end if

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

end getResultFeedback

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

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

	repeat with theResult in resultList

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

	end repeat

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

end getResultListFeedback

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

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

end fileWrite

-- builds path to album art for the given song
on getSongArtworkPath(theSong)

	if albumArtEnabled is false then return defaultIconName

	tell application "iTunes"

		set songArtist to artist of theSong
		set songAlbum to album of theSong
		-- generate a unique identifier for that album
		set songArtworkName to (songArtist & songArtworkNameSep & songAlbum) as text
		-- remove forbidden path characters
		set songArtworkName to replace(":", "", songArtworkName) of me
		set songArtworkName to replace("/", "", songArtworkName) of me
		set songArtworkName to replace(".", "", songArtworkName) of me
		set songArtworkPath to (artworkCachePath & songArtworkName & ".jpg")

	end tell

	tell application "Finder"

		-- cache artwork if it's not already cached
		if not (songArtworkPath exists) then

			tell application "iTunes"

				set songArtworks to artworks of theSong
				-- only save artwork if artwork exists for this song
				if (length of songArtworks) is 0 then

					-- use default iTunes icon if song has no artwork
					set songArtworkPath to defaultIconName

				else

					-- save artwork to file
					set songArtwork to data of (item 1 of songArtworks)
					fileWrite(songArtworkPath, songArtwork) of me

				end if

			end tell

		end if

	end tell

	return songArtworkPath

end getSongArtworkPath

-- creates album artwork cache
on createWorkflowPlaylist()

	tell application "iTunes"

		if not (user playlist workflowPlaylistName exists) then

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

		end if

	end tell

end createWorkflowPlaylist

on clearQueue()

	tell application "iTunes"

		if user playlist workflowPlaylistName exists then

			delete tracks of user playlist workflowPlaylistName

		end if

	end tell

end clearQueue

on queueSongs(theSongs)

	tell application "iTunes"

		repeat with theSong in theSongs

			duplicate theSong to user playlist workflowPlaylistName

		end repeat

	end tell

end queueSongs

on playQueue()

	tell application "iTunes"

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

			play user playlist workflowPlaylistName

		end if

	end tell

end playQueue

-- brings queue into view in iTunes window
on focusQueue()

	tell application "iTunes"

		reveal user playlist workflowPlaylistName

	end tell

end focusQueue

on getPlaylistSongs(playlistId)

	tell application "iTunes"

		set thePlaylist to first user playlist whose id is playlistId
		set theSongs to every track of thePlaylist

	end tell

	return theSongs

end getPlaylistSongs

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

	tell application "iTunes"

		set theSongs to every track of playlist 2 whose genre is genreName and kind contains songDescriptor
		set artistNames to {}

		repeat with theSong in theSongs

			if (artist of theSong) is not in artistNames then

				set artistNames to artistNames & (artist of theSong)

			end if

		end repeat

	end tell

	return artistNames

end getGenreArtists

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

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

	repeat with artistName in artistNames

		set theSongs to theSongs & getArtistSongs(artistName) of me

	end repeat

	return theSongs

end getGenreSongs

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

	tell application "iTunes"

		set theSongs to every track of playlist 2 whose artist is artistName and kind contains songDescriptor
		set albumNames to {}

		repeat with theSong in theSongs

			if (album of theSong) is not in albumNames then

				set albumNames to albumNames & (album of theSong)

			end if

		end repeat

	end tell

	return albumNames

end getArtistAlbums

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

	tell application "iTunes"

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

		repeat with albumName in albumNames

			set albumSongs to (every track of playlist 2 whose artist is artistName and album is albumName and kind contains songDescriptor)
			set albumSongs to sortSongsByAlbumOrder(albumSongs) of me
			set theSongs to theSongs & albumSongs

		end repeat

	end tell

	return theSongs

end getArtistSongs

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

	tell application "iTunes"

		set theSongs to every track of playlist 2 whose album is albumName and kind contains songDescriptor
		set theSongs to sortSongsByAlbumOrder(theSongs) of me

	end tell

	return theSongs

end getAlbumSongs

-- sorts songs from the same album by track number
on sortSongsByAlbumOrder(theSongs)

	tell application "iTunes"

		set theSongsSorted to theSongs

		if length of theSongs is greater than 1 then

			set trackCount to track count of (item 1 of theSongs)
			set discCount to disc count of (item 1 of theSongs)

			if trackCount is not 0 and discCount is not 0 then

				set theSongsSorted to {} as list

				repeat with discIndex from 1 to discCount

					repeat with songIndex from 1 to trackCount

						repeat with theSong in theSongs

							if disc number of theSong is discIndex and track number of theSong is songIndex then

								set nextSong to theSong
								copy nextSong to the end of theSongsSorted

							end if

						end repeat

					end repeat

				end repeat

			end if

		end if

	end tell

	return theSongsSorted

end sortSongsByAlbumOrder

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

	tell application "iTunes"

		set theSong to first track of playlist 2 whose database ID is songId and kind contains songDescriptor

	end tell

	return theSong

end getSong

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

	set evalScript to run script "
	script

		on findResults(query, queryType, resultLimit, songDescriptor)

			tell application \"iTunes\"

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

				if length of theSongs < resultLimit then

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

				end if

				if length of theSongs < resultLimit then

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

				end if

				if length of theSongs < resultLimit then

					set searchSongs to {}

					if queryType is \"name\" then

						set searchSongs to (search playlist 2 for query only songs)

					else if queryType is not \"genre\" then

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

					end if

					repeat with searchSong in searchSongs

						set duplicateSong to false

						repeat with theSong in theSongs

							if theSong is searchSong then

								set duplicateSong to true
								exit repeat

							end if

						end repeat

						if duplicateSong is false then

							copy searchSong to end of theSongs

						end if

					end repeat

				end if

				if queryType is \"name\" then

					if length of theSongs > resultLimit then

						set theSongs to items 1 thru resultLimit of theSongs

					end if

					set theResults to theSongs

				else

					set theResults to {}

					repeat with theSong in theSongs

						if length of theResults is resultLimit then exit repeat

						set theResult to " & queryType & " of theSong

						if theResult is not in theResults then

							set theResults to theResults & theResult

						end if

					end repeat

				end if

			end tell

			return theResults

		end findResults

	end script
	"

	evalScript's findResults(query, queryType, resultLimit, songDescriptor)

end getResultsFromQuery

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

	-- trim leading whitespace
	repeat while theString begins with space

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

	end repeat

	-- trim trailing whitespace
	repeat while theString ends with space

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

	end repeat

	return theString

end trimWhitespace

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

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

end queueSong

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

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

end queueAlbum

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

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

end queueArtist

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

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

end queueGenre

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

	set theSongs to getPlaylistSongs(playlistId)
	queueSongs(theSongs)

end queuePlaylist

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

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

end parseResultQuery

on queue(query)

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

	createWorkflowPlaylist()

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

	focusQueue()

end queue

on play(query)

	clearQueue()
	queue(query)
	focusQueue()
	playQueue()

end play

-- core configuration --

-- configurable options --

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

-- workflow parameters --

property homeFolder : (path to home folder as text)
property libraryFolder : (path to library folder from user domain as text)
property cacheFolder : (libraryFolder & "Caches:")
property alfredWorkflowDataFolder : (cacheFolder & "com.runningwithcrayons.Alfred-3:Workflow Data:")
property bundleId : "com.calebevans.playsong"
property workflowCacheFolder : (alfredWorkflowDataFolder & bundleId & ":") as text
property artworkCacheFolderName : "Album Artwork"
property artworkCachePath : (workflowCacheFolder & artworkCacheFolderName & ":")
property songArtworkNameSep : " | "
property defaultIconName : "resources/icon-noartwork.png"
-- the name of the playlist used by the workflow for playing songs
property workflowPlaylistName : "Alfred Play Song"
-- the text used to determine if a track is an audio file
property songDescriptor : "audio"
-- list of Alfred results
property resultList : {}

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

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

end replace

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

	if theNumber is 1 then

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

	else

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

	end if

	return theString

end quantifyNumber

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

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

end encodeFeedbackChars

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

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

end decodeFeedbackChars

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

	copy theResult to the end of resultList

end addResult

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

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

end addNoResultsItem

on resultListIsFull()

	return (length of resultList is resultLimit)

end resultListIsFull

on resultListIsEmpty()

	return (length of resultList is 0)

end resultListIsFull

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

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

	if (icon of theResult) contains ":" then

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

	else

		set resultIcon to icon of theResult

	end if

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

end getResultFeedback

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

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

	repeat with theResult in resultList

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

	end repeat

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

end getResultListFeedback

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

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

end fileWrite

-- builds path to album art for the given song
on getSongArtworkPath(theSong)

	if albumArtEnabled is false then return defaultIconName

	tell application "iTunes"

		set songArtist to artist of theSong
		set songAlbum to album of theSong
		-- generate a unique identifier for that album
		set songArtworkName to (songArtist & songArtworkNameSep & songAlbum) as text
		-- remove forbidden path characters
		set songArtworkName to replace(":", "", songArtworkName) of me
		set songArtworkName to replace("/", "", songArtworkName) of me
		set songArtworkName to replace(".", "", songArtworkName) of me
		set songArtworkPath to (artworkCachePath & songArtworkName & ".jpg")

	end tell

	tell application "Finder"

		-- cache artwork if it's not already cached
		if not (songArtworkPath exists) then

			tell application "iTunes"

				set songArtworks to artworks of theSong
				-- only save artwork if artwork exists for this song
				if (length of songArtworks) is 0 then

					-- use default iTunes icon if song has no artwork
					set songArtworkPath to defaultIconName

				else

					-- save artwork to file
					set songArtwork to data of (item 1 of songArtworks)
					fileWrite(songArtworkPath, songArtwork) of me

				end if

			end tell

		end if

	end tell

	return songArtworkPath

end getSongArtworkPath

-- creates album artwork cache
on createWorkflowPlaylist()

	tell application "iTunes"

		if not (user playlist workflowPlaylistName exists) then

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

		end if

	end tell

end createWorkflowPlaylist

on clearQueue()

	tell application "iTunes"

		if user playlist workflowPlaylistName exists then

			delete tracks of user playlist workflowPlaylistName

		end if

	end tell

end clearQueue

on queueSongs(theSongs)

	tell application "iTunes"

		repeat with theSong in theSongs

			duplicate theSong to user playlist workflowPlaylistName

		end repeat

	end tell

end queueSongs

on playQueue()

	tell application "iTunes"

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

			play user playlist workflowPlaylistName

		end if

	end tell

end playQueue

-- brings queue into view in iTunes window
on focusQueue()

	tell application "iTunes"

		reveal user playlist workflowPlaylistName

	end tell

end focusQueue

on getPlaylistSongs(playlistId)

	tell application "iTunes"

		set thePlaylist to first user playlist whose id is playlistId
		set theSongs to every track of thePlaylist

	end tell

	return theSongs

end getPlaylistSongs

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

	tell application "iTunes"

		set theSongs to every track of playlist 2 whose genre is genreName and kind contains songDescriptor
		set artistNames to {}

		repeat with theSong in theSongs

			if (artist of theSong) is not in artistNames then

				set artistNames to artistNames & (artist of theSong)

			end if

		end repeat

	end tell

	return artistNames

end getGenreArtists

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

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

	repeat with artistName in artistNames

		set theSongs to theSongs & getArtistSongs(artistName) of me

	end repeat

	return theSongs

end getGenreSongs

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

	tell application "iTunes"

		set theSongs to every track of playlist 2 whose artist is artistName and kind contains songDescriptor
		set albumNames to {}

		repeat with theSong in theSongs

			if (album of theSong) is not in albumNames then

				set albumNames to albumNames & (album of theSong)

			end if

		end repeat

	end tell

	return albumNames

end getArtistAlbums

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

	tell application "iTunes"

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

		repeat with albumName in albumNames

			set albumSongs to (every track of playlist 2 whose artist is artistName and album is albumName and kind contains songDescriptor)
			set albumSongs to sortSongsByAlbumOrder(albumSongs) of me
			set theSongs to theSongs & albumSongs

		end repeat

	end tell

	return theSongs

end getArtistSongs

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

	tell application "iTunes"

		set theSongs to every track of playlist 2 whose album is albumName and kind contains songDescriptor
		set theSongs to sortSongsByAlbumOrder(theSongs) of me

	end tell

	return theSongs

end getAlbumSongs

-- sorts songs from the same album by track number
on sortSongsByAlbumOrder(theSongs)

	tell application "iTunes"

		set theSongsSorted to theSongs

		if length of theSongs is greater than 1 then

			set trackCount to track count of (item 1 of theSongs)
			set discCount to disc count of (item 1 of theSongs)

			if trackCount is not 0 and discCount is not 0 then

				set theSongsSorted to {} as list

				repeat with discIndex from 1 to discCount

					repeat with songIndex from 1 to trackCount

						repeat with theSong in theSongs

							if disc number of theSong is discIndex and track number of theSong is songIndex then

								set nextSong to theSong
								copy nextSong to the end of theSongsSorted

							end if

						end repeat

					end repeat

				end repeat

			end if

		end if

	end tell

	return theSongsSorted

end sortSongsByAlbumOrder

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

	tell application "iTunes"

		set theSong to first track of playlist 2 whose database ID is songId and kind contains songDescriptor

	end tell

	return theSong

end getSong

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

	set evalScript to run script "
	script

		on findResults(query, queryType, resultLimit, songDescriptor)

			tell application \"iTunes\"

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

				if length of theSongs < resultLimit then

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

				end if

				if length of theSongs < resultLimit then

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

				end if

				if length of theSongs < resultLimit then

					set searchSongs to {}

					if queryType is \"name\" then

						set searchSongs to (search playlist 2 for query only songs)

					else if queryType is not \"genre\" then

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

					end if

					repeat with searchSong in searchSongs

						set duplicateSong to false

						repeat with theSong in theSongs

							if (database ID of theSong) is (database ID of searchSong) then

								set duplicateSong to true
								exit repeat

							end if

						end repeat

						if duplicateSong is false then

							copy searchSong to end of theSongs

						end if

					end repeat

				end if

				if queryType is \"name\" then

					if length of theSongs > resultLimit then

						set theSongs to items 1 thru resultLimit of theSongs

					end if

					set theResults to theSongs

				else

					set theResults to {}

					repeat with theSong in theSongs

						if length of theResults is resultLimit then exit repeat

						set theResult to " & queryType & " of theSong

						if theResult is not in theResults then

							set theResults to theResults & theResult

						end if

					end repeat

				end if

			end tell

			return theResults

		end findResults

	end script
	"

	evalScript's findResults(query, queryType, resultLimit, songDescriptor)

end getResultsFromQuery

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

	-- trim leading whitespace
	repeat while theString begins with space

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

	end repeat

	-- trim trailing whitespace
	repeat while theString ends with space

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

	end repeat

	return theString

end trimWhitespace

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

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

end queueSong

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

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

end queueAlbum

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

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

end queueArtist

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

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

end queueGenre

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

	set theSongs to getPlaylistSongs(playlistId)
	queueSongs(theSongs)

end queuePlaylist

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

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

end parseResultQuery

on queue(query)

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

	createWorkflowPlaylist()

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

	focusQueue()

end queue

on play(query)

	clearQueue()
	queue(query)
	focusQueue()
	playQueue()

end play

Fix bug with previous fix; duplicates are now gone


on run argv
	set simulatedDevice to (item 1 of argv)
	tell application "iPhone Simulator"
		activate
	end tell

	tell application "System Events"
		tell process "iPhone Simulator"
			tell menu bar 1
				tell menu bar item "Hardware"
					tell menu "Hardware"
						tell menu item "Device"
							tell menu "Device"
								click menu item simulatedDevice
							end tell
						end tell
					end tell
				end tell
			end tell
		end tell
	end tell
end run

fix apple script to select device

fix apple script to select device


#!/usr/bin/osascript

set awakeTime to date "8:00:00"

set {hours: remainHours, minutes: remainMinutes} to (date "0:0") + (awakeTime - (current date))
set messageTitle to "Remaining " & remainHours & " hours " & remainMinutes & " minutes"
set messageDescription to "now " & time string of (current date)

display notification messageDescription with title messageTitle

#!/usr/bin/osascript

-- awake time in next morning
set awakeTime to date "8:00:00"

-- calculate and notify remaining time
set {hours: remainHours, minutes: remainMinutes} to (date "0:0") + (awakeTime - (current date))

set messageTitle to "Remaining " & remainHours & " hours " & remainMinutes & " minutes"
set messageDescription to "now " & time string of (current date)

display notification messageDescription with title messageTitle

Add comment

Add comment


property pTitle : "OmniFocus: Quick Stats"
property pVersion : "2.07"

property pstrDBPath : "$HOME/Library/Caches/com.omnigroup.OmniFocus/OmniFocusDatabase2"
property pstrMinOSX : "10.6"

property pTimeOut : 20

-- Ver 0.8 adds clipboard option to dialogue
-- Ver 0.9 gives an error message if the cache schema has changed, leading to an SQL error in the script
-- Ver 1.0 slight simplification of the code
-- Ver 1.1 added count of Pending projects
-- Ver 1.2 added a count of available actions
-- Ver 1.3 added a break-down of unavailable actions
-- Ver 1.4 added count of Current projects to complement Pending projects
-- ver 1.5 replaced Applescript time function with SQL time expression
-- Ver 1.7 Reorganizes menu, and attempts to enable access for .macappstore installations of OF
--Ver 1.8 Adjusts handling of variant bundle identifiers generally
-- Ver 2.00 Redraft of task breakdown, with progressive narrowing of criteria ...

property pToClipboard : "Copy list to clipboard"

if not FileExists(pstrDBPath) then set pstrDBPath to GetCachePath()

tell application "Finder"
	if (version < pstrMinOSX) then
		display dialog "This script requires OSX " & pstrMinOSX & " or higher" buttons {"OK"} default button 1 with title pTitle & "Ver. " & pVersion
		return
	end if
end tell

if pstrDBPath  "" then
	set strCmd to "sqlite3 -separator ': ' \"" & pstrDBPath & "\" " & quoted form of ("
	select \"INBOX GROUPS & ACTIONS\", count(*) from task where (inInbox=1);
	select \"    Inbox action groups\", count(*) from task where (inInbox=1) and (childrenCount>0);
	select \"    Inbox actions\", count(*) from task where (inInbox=1) and (childrenCount=0);
	select null;
	select \"FOLDERS\"	, count(*) from folder;
	select \"    Active folders\", count(*) from folder where effectiveActive=1;
	select \"    Dropped folders\", count(*) from folder where effectiveActive=0;
	select null;
	select \"PROJECTS\", count(*) from projectInfo where containsSingletonActions=0;
	select \"    Active projects\", count(*) from projectInfo where (containsSingletonActions=0) and (status=\"active\");
	select \"            Current projects\", count(*) from projectInfo p join task t on t.projectinfo=p.pk where (p.containsSingletonActions=0) and (p.folderEffectiveActive=1) and (p.status=\"active\") and (t.dateToStart is null or t.dateToStart < (strftime('%s','now') - strftime('%s','2001-01-01')));
	select \"            Pending projects\", count(*) from projectInfo p join task t on t.projectinfo=p.pk where (p.containsSingletonActions=0) and (p.folderEffectiveActive=1) and (p.status=\"active\") and (t.dateToStart > (strftime('%s','now') - strftime('%s','2001-01-01')));
	select \"    On-hold projects\", count(*) from projectInfo where (containsSingletonActions=0) and (status=\"inactive\");
	select \"    Completed projects\", count(*) from projectInfo where (containsSingletonActions=0) and (status=\"done\");
	select \"    Dropped projects\", count(*) from projectInfo where (containsSingletonActions=0) and (( status=\"dropped\") or (folderEffectiveActive=0));
	select null;
	select \"SINGLE ACTION LISTS\", count(*) from projectInfo where containsSingletonActions=1;
	select \"    Active single action lists\", count(*) from projectInfo where (containsSingletonActions=1) and (status=\"active\");
	select \"    On-hold single action lists\", count(*) from projectInfo where (containsSingletonActions=1) and (status=\"inactive\");
	select \"    Completed single action lists\", count(*) from projectInfo where (containsSingletonActions=1) and (status=\"done\");
	select \"    Dropped single action lists\", count(*) from projectInfo where (containsSingletonActions=1) and (( status=\"dropped\") or (folderEffectiveActive=0));
	select null;
	select \"CONTEXTS\", count(*) from context;
	select \"    Active contexts\", count(*) from context where (effectiveActive=1) and (allowsNextAction=1);
	select \"    On-hold contexts\", count(*) from context where (effectiveActive=1) and allowsNextAction=0;
	select \"    Dropped contexts\", count(*) from context where effectiveActive=0;
	select null;
	select \"ACTION GROUPS\", count(*) from task where (projectinfo is null) and (childrenCount>0);
	select \"    Remaining action groups\", count(*) from task where (projectinfo is null) and (dateCompleted is null) and (childrenCount>0);
	select \"    Completed action groups\", count(dateCompleted) from task where (projectinfo is null) and (childrenCount>0);
	select null;
	select \"ACTIONS\", count(*) from task where (projectinfo is null) and (childrenCount=0);
	select \"    Completed actions\", count(dateCompleted) from task where (projectinfo is null) and (childrenCount=0);
	select \"    Dropped project actions\", count(*) from (task t left join projectinfo p on t.containingProjectinfo=p.pk) tp where (projectinfo is null) and (childrenCount=0)  and (dateCompleted is null)
				and (tp.containingProjectinfo is not null and (tp.status=\"dropped\" or tp.folderEffectiveActive=0));
	select \"    Dropped context actions\", count(*) from (task t left join projectinfo p on t.containingProjectinfo=p.pk) tp left join context c on tp.context=c.persistentIdentifier where (projectinfo is null) and (tp.childrenCount=0)  and (dateCompleted is null)
				and (tp.containingProjectinfo is null or (tp.status !=\"dropped\" and tp.folderEffectiveActive=1))
				and c.effectiveActive= 0;
	select \"    Remaining actions\", count(*) from (task t left join projectinfo p on t.containingProjectinfo=p.pk) tp left join context c on tp.context=c.persistentIdentifier where (projectinfo is null) and (tp.childrenCount=0)  and (dateCompleted is null)
				and (tp.containingProjectinfo is null or (tp.status !=\"dropped\" and tp.folderEffectiveActive=1))
				and (tp.context is null or c.effectiveActive= 1);
	select \"        Actions in Projects on hold\", count(*) from (task t left join projectinfo p on t.containingProjectinfo=p.pk) tp left join context c on tp.context=c.persistentIdentifier where (projectinfo is null) and (tp.childrenCount=0)  and (dateCompleted is null)
				and (tp.containingProjectinfo is null or (tp.status !=\"dropped\" and tp.folderEffectiveActive=1))
				and (tp.context is null or c.effectiveActive= 1)
				and (tp.containingProjectInfo is not null and tp.status=\"inactive\");
	select \"        Actions in Contexts on hold\", count(*) from (task t left join projectinfo p on t.containingProjectinfo=p.pk) tp left join context c on tp.context=c.persistentIdentifier where (projectinfo is null) and (tp.childrenCount=0)  and (dateCompleted is null)
				and (tp.containingProjectinfo is null or (tp.status !=\"dropped\" and tp.folderEffectiveActive=1))
				and (tp.context is null or c.effectiveActive= 1)
				and (tp.containingProjectInfo is null or tp.status!=\"inactive\")
				and (tp.context is not null and c.allowsNextAction=0);
	select \"        Blocked actions\", count(*) from (task t left join projectinfo p on t.containingProjectinfo=p.pk) tp left join context c on tp.context=c.persistentIdentifier where (projectinfo is null) and (tp.childrenCount=0)  and (dateCompleted is null)
				and (tp.containingProjectinfo is null or (tp.status !=\"dropped\" and tp.folderEffectiveActive=1))
				and (tp.context is null or c.effectiveActive= 1)
				and (tp.containingProjectInfo is null or tp.status!=\"inactive\")
				and (tp.context is null or c.allowsNextAction=1)
				and tp.blocked=1;
	select \"        	Blocked by future start date\", count(*) from (task t left join projectinfo p on t.containingProjectinfo=p.pk) tp left join context c on tp.context=c.persistentIdentifier where (projectinfo is null) and (tp.childrenCount=0)  and (dateCompleted is null)
				and (tp.containingProjectinfo is null or (tp.status !=\"dropped\" and tp.folderEffectiveActive=1))
				and (tp.context is null or c.effectiveActive= 1)
				and (tp.containingProjectInfo is null or tp.status!=\"inactive\")
				and (tp.context is null or c.allowsNextAction=1)
				and tp.blocked=1
				and tp.blockedByFutureStartDate=1;
	select \"        	Sequentially blocked\", count(*) from (task t left join projectinfo p on t.containingProjectinfo=p.pk) tp left join context c on tp.context=c.persistentIdentifier where (projectinfo is null) and (tp.childrenCount=0)  and (dateCompleted is null)
				and (tp.containingProjectinfo is null or (tp.status !=\"dropped\" and tp.folderEffectiveActive=1))
				and (tp.context is null or c.effectiveActive= 1)
				and (tp.containingProjectInfo is null or tp.status!=\"inactive\")
				and (tp.context is null or c.allowsNextAction=1)
				and tp.blocked=1
				and tp.blockedByFutureStartDate=0;
	select \"        Available actions\", count(*) from (task t left join projectinfo p on t.containingProjectinfo=p.pk) tp left join context c on tp.context=c.persistentIdentifier where (projectinfo is null) and (tp.childrenCount=0)  and (dateCompleted is null)
				and (tp.containingProjectinfo is null or (tp.status !=\"dropped\" and tp.folderEffectiveActive=1))
				and (tp.context is null or c.effectiveActive= 1)
				and (tp.containingProjectInfo is null or tp.status!=\"inactive\")
				and (tp.context is null or c.allowsNextAction=1)
				and tp.blocked=0;

	")

	-- 		try
	set strList to do shell script strCmd
	-- 		on error
	-- 			display dialog "The SQL schema for the OmniFocus cache may have changed in a recent update of OF." & return & return &
	-- 				"Look on the OmniFocus user forums for an updated version of this script." buttons {"OK"} with title pTitle & "Ver. " & pVersion
	-- 			return
	-- 		end try
	tell application id "sevs"
		activate
		if button returned of (display dialog strList buttons {pToClipboard, "OK"} default button "OK" giving up after pTimeOut with title pTitle & " Ver. " & pVersion)
			is pToClipboard then tell application id "com.apple.finder" to set the clipboard to strList
	end tell
else
	tell application id "sevs"
		activate
		display dialog "OmniFocus cache not found ..." buttons {"OK"} default button 1 with title pTitle & " Ver. " & pVersion
	end tell
end if

on FileExists(strPath)
	(do shell script "test -e " & strPath & " ; echo $?") = "0"
end FileExists

on GetCachePath()
	try
		tell application "Finder" to tell (application file id "OFOC") to "$HOME/Library/Caches/" & its id & "/OmniFocusDatabase2"
	on error
		error "OmniFocus not installed ..."
	end try
end GetCachePath

property pTitle : "OmniFocus: Quick Stats"
property pVersion : "2.07"

property pstrDBPath : "$HOME/Library/Caches/com.omnigroup.OmniFocus/OmniFocusDatabase2"
property pstrMinOSX : "10.6"

property pTimeOut : 20

-- Original version: https://github.com/RobTrew/tree-tools/blob/master/OmniFocus%20scripts/Statistics/QuickStats.applescript

-- Copyright  2012, 2013, 2014 Robin Trew
--
-- Permission is hereby granted, free of charge,
-- to any person obtaining a copy of this software
-- and associated documentation files (the "Software"),
-- to deal in the Software without restriction,
-- including without limitation the rights to use, copy,
-- modify, merge, publish, distribute, sublicense,
-- and/or sell copies of the Software, and to permit persons
-- to whom the Software is furnished to do so,
-- subject to the following conditions:
--
-- *******
-- The above copyright notice and this permission notice
-- shall be included in ALL copies
-- or substantial portions of the Software.
-- *******
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-- OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
-- DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
-- OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

-- Ver 0.8 adds clipboard option to dialogue
-- Ver 0.9 gives an error message if the cache schema has changed, leading to an SQL error in the script
-- Ver 1.0 slight simplification of the code
-- Ver 1.1 added count of Pending projects
-- Ver 1.2 added a count of available actions
-- Ver 1.3 added a break-down of unavailable actions
-- Ver 1.4 added count of Current projects to complement Pending projects
-- ver 1.5 replaced Applescript time function with SQL time expression
-- Ver 1.7 Reorganizes menu, and attempts to enable access for .macappstore installations of OF
--Ver 1.8 Adjusts handling of variant bundle identifiers generally
-- Ver 2.00 Redraft of task breakdown, with progressive narrowing of criteria ...

property pToClipboard : "Copy list to clipboard"

if not FileExists(pstrDBPath) then set pstrDBPath to GetCachePath()

tell application "Finder"
	if (version < pstrMinOSX) then
		display dialog "This script requires OSX " & pstrMinOSX & " or higher" buttons {"OK"} default button 1 with title pTitle & "Ver. " & pVersion
		return
	end if
end tell

if pstrDBPath  "" then
	set strCmd to "sqlite3 -separator ': ' \"" & pstrDBPath & "\" " & quoted form of ("
	select \"INBOX GROUPS & ACTIONS\", count(*) from task where (inInbox=1);
	select \"    Inbox action groups\", count(*) from task where (inInbox=1) and (childrenCount>0);
	select \"    Inbox actions\", count(*) from task where (inInbox=1) and (childrenCount=0);
	select null;
	select \"FOLDERS\"	, count(*) from folder;
	select \"    Active folders\", count(*) from folder where effectiveActive=1;
	select \"    Dropped folders\", count(*) from folder where effectiveActive=0;
	select null;
	select \"PROJECTS\", count(*) from projectInfo where containsSingletonActions=0;
	select \"    Active projects\", count(*) from projectInfo where (containsSingletonActions=0) and (status=\"active\");
	select \"            Current projects\", count(*) from projectInfo p join task t on t.projectinfo=p.pk where (p.containsSingletonActions=0) and (p.folderEffectiveActive=1) and (p.status=\"active\") and (t.dateToStart is null or t.dateToStart < (strftime('%s','now') - strftime('%s','2001-01-01')));
	select \"            Pending projects\", count(*) from projectInfo p join task t on t.projectinfo=p.pk where (p.containsSingletonActions=0) and (p.folderEffectiveActive=1) and (p.status=\"active\") and (t.dateToStart > (strftime('%s','now') - strftime('%s','2001-01-01')));
	select \"    On-hold projects\", count(*) from projectInfo where (containsSingletonActions=0) and (status=\"inactive\");
	select \"    Completed projects\", count(*) from projectInfo where (containsSingletonActions=0) and (status=\"done\");
	select \"    Dropped projects\", count(*) from projectInfo where (containsSingletonActions=0) and (( status=\"dropped\") or (folderEffectiveActive=0));
	select null;
	select \"SINGLE ACTION LISTS\", count(*) from projectInfo where containsSingletonActions=1;
	select \"    Active single action lists\", count(*) from projectInfo where (containsSingletonActions=1) and (status=\"active\");
	select \"    On-hold single action lists\", count(*) from projectInfo where (containsSingletonActions=1) and (status=\"inactive\");
	select \"    Completed single action lists\", count(*) from projectInfo where (containsSingletonActions=1) and (status=\"done\");
	select \"    Dropped single action lists\", count(*) from projectInfo where (containsSingletonActions=1) and (( status=\"dropped\") or (folderEffectiveActive=0));
	select null;
	select \"CONTEXTS\", count(*) from context;
	select \"    Active contexts\", count(*) from context where (effectiveActive=1) and (allowsNextAction=1);
	select \"    On-hold contexts\", count(*) from context where (effectiveActive=1) and allowsNextAction=0;
	select \"    Dropped contexts\", count(*) from context where effectiveActive=0;
	select null;
	select \"ACTION GROUPS\", count(*) from task where (projectinfo is null) and (childrenCount>0);
	select \"    Remaining action groups\", count(*) from task where (projectinfo is null) and (dateCompleted is null) and (childrenCount>0);
	select \"    Completed action groups\", count(dateCompleted) from task where (projectinfo is null) and (childrenCount>0);
	select null;
	select \"ACTIONS\", count(*) from task where (projectinfo is null) and (childrenCount=0);
	select \"    Completed actions\", count(dateCompleted) from task where (projectinfo is null) and (childrenCount=0);
	select \"    Dropped project actions\", count(*) from (task t left join projectinfo p on t.containingProjectinfo=p.pk) tp where (projectinfo is null) and (childrenCount=0)  and (dateCompleted is null)
				and (tp.containingProjectinfo is not null and (tp.status=\"dropped\" or tp.folderEffectiveActive=0));
	select \"    Dropped context actions\", count(*) from (task t left join projectinfo p on t.containingProjectinfo=p.pk) tp left join context c on tp.context=c.persistentIdentifier where (projectinfo is null) and (tp.childrenCount=0)  and (dateCompleted is null)
				and (tp.containingProjectinfo is null or (tp.status !=\"dropped\" and tp.folderEffectiveActive=1))
				and c.effectiveActive= 0;
	select \"    Remaining actions\", count(*) from (task t left join projectinfo p on t.containingProjectinfo=p.pk) tp left join context c on tp.context=c.persistentIdentifier where (projectinfo is null) and (tp.childrenCount=0)  and (dateCompleted is null)
				and (tp.containingProjectinfo is null or (tp.status !=\"dropped\" and tp.folderEffectiveActive=1))
				and (tp.context is null or c.effectiveActive= 1);
	select \"        Actions in Projects on hold\", count(*) from (task t left join projectinfo p on t.containingProjectinfo=p.pk) tp left join context c on tp.context=c.persistentIdentifier where (projectinfo is null) and (tp.childrenCount=0)  and (dateCompleted is null)
				and (tp.containingProjectinfo is null or (tp.status !=\"dropped\" and tp.folderEffectiveActive=1))
				and (tp.context is null or c.effectiveActive= 1)
				and (tp.containingProjectInfo is not null and tp.status=\"inactive\");
	select \"        Actions in Contexts on hold\", count(*) from (task t left join projectinfo p on t.containingProjectinfo=p.pk) tp left join context c on tp.context=c.persistentIdentifier where (projectinfo is null) and (tp.childrenCount=0)  and (dateCompleted is null)
				and (tp.containingProjectinfo is null or (tp.status !=\"dropped\" and tp.folderEffectiveActive=1))
				and (tp.context is null or c.effectiveActive= 1)
				and (tp.containingProjectInfo is null or tp.status!=\"inactive\")
				and (tp.context is not null and c.allowsNextAction=0);
	select \"        Blocked actions\", count(*) from (task t left join projectinfo p on t.containingProjectinfo=p.pk) tp left join context c on tp.context=c.persistentIdentifier where (projectinfo is null) and (tp.childrenCount=0)  and (dateCompleted is null)
				and (tp.containingProjectinfo is null or (tp.status !=\"dropped\" and tp.folderEffectiveActive=1))
				and (tp.context is null or c.effectiveActive= 1)
				and (tp.containingProjectInfo is null or tp.status!=\"inactive\")
				and (tp.context is null or c.allowsNextAction=1)
				and tp.blocked=1;
	select \"        	Blocked by future start date\", count(*) from (task t left join projectinfo p on t.containingProjectinfo=p.pk) tp left join context c on tp.context=c.persistentIdentifier where (projectinfo is null) and (tp.childrenCount=0)  and (dateCompleted is null)
				and (tp.containingProjectinfo is null or (tp.status !=\"dropped\" and tp.folderEffectiveActive=1))
				and (tp.context is null or c.effectiveActive= 1)
				and (tp.containingProjectInfo is null or tp.status!=\"inactive\")
				and (tp.context is null or c.allowsNextAction=1)
				and tp.blocked=1
				and tp.blockedByFutureStartDate=1;
	select \"        	Sequentially blocked\", count(*) from (task t left join projectinfo p on t.containingProjectinfo=p.pk) tp left join context c on tp.context=c.persistentIdentifier where (projectinfo is null) and (tp.childrenCount=0)  and (dateCompleted is null)
				and (tp.containingProjectinfo is null or (tp.status !=\"dropped\" and tp.folderEffectiveActive=1))
				and (tp.context is null or c.effectiveActive= 1)
				and (tp.containingProjectInfo is null or tp.status!=\"inactive\")
				and (tp.context is null or c.allowsNextAction=1)
				and tp.blocked=1
				and tp.blockedByFutureStartDate=0;
	select \"        Available actions\", count(*) from (task t left join projectinfo p on t.containingProjectinfo=p.pk) tp left join context c on tp.context=c.persistentIdentifier where (projectinfo is null) and (tp.childrenCount=0)  and (dateCompleted is null)
				and (tp.containingProjectinfo is null or (tp.status !=\"dropped\" and tp.folderEffectiveActive=1))
				and (tp.context is null or c.effectiveActive= 1)
				and (tp.containingProjectInfo is null or tp.status!=\"inactive\")
				and (tp.context is null or c.allowsNextAction=1)
				and tp.blocked=0;

	")

	-- 		try
	set strList to do shell script strCmd
	-- 		on error
	-- 			display dialog "The SQL schema for the OmniFocus cache may have changed in a recent update of OF." & return & return &
	-- 				"Look on the OmniFocus user forums for an updated version of this script." buttons {"OK"} with title pTitle & "Ver. " & pVersion
	-- 			return
	-- 		end try
	tell application id "sevs"
		activate
		if button returned of (display dialog strList buttons {pToClipboard, "OK"} default button "OK" giving up after pTimeOut with title pTitle & " Ver. " & pVersion)
			is pToClipboard then tell application id "com.apple.finder" to set the clipboard to strList
	end tell
else
	tell application id "sevs"
		activate
		display dialog "OmniFocus cache not found ..." buttons {"OK"} default button 1 with title pTitle & " Ver. " & pVersion
	end tell
end if

on FileExists(strPath)
	(do shell script "test -e " & strPath & " ; echo $?") = "0"
end FileExists

on GetCachePath()
	try
		tell application "Finder" to tell (application file id "OFOC") to "$HOME/Library/Caches/" & its id & "/OmniFocusDatabase2"
	on error
		error "OmniFocus not installed ..."
	end try
end GetCachePath

paste in license

paste in license