update binary file

update binary file

FasdUAS 1.101.10
k
l& # Current Alfred-Bundler version		@# Current Alfred-Bundler version

j"0bundler_versionBUNDLER_VERSION
m

devel
l%# Path to user's home directory># Path to user's home directory
j	0_home
n

1

psxp
l

I

.earsffdralis afdr
mcusr

rtyp
m

ctxt
l!"!/)# Path to Alfred-Bundler's root directory"##R# Path to Alfred-Bundler's root directory $%
$j&0bundler_dirBUNDLER_DIR
&b'(
'b)*
)l+
+o	0_home
*m,,--Library/Application Support/Alfred 2/Workflow Data/alfred.bundler-
(o"0bundler_versionBUNDLER_VERSION%./
.j00	cache_dir	CACHE_DIR
0b12
1b34
3l5
5o	0_home
4m6677Library/Caches/com.runningwithcrayons.Alfred-2/Workflow Data/alfred.bundler-
2o"0bundler_versionBUNDLER_VERSION/89
8l9:;
:l<=< MAIN API FUNCTION =>>& MAIN API FUNCTION ;?@
?l@AB
Ai CD
CI0load_bundler
Dk/EEFG
FlHIH Load `AlfredBundler.scpt` from the Alfred-Bundler directory as a script object.
	If the Alfred-Bundler directory does not exist, install it (using `_bootstrap()`).

	:returns: the script object of `AlfredBundler.scpt`
	:rtype: ``script object``

	IJJ Load `AlfredBundler.scpt` from the Alfred-Bundler directory as a script object.
	If the Alfred-Bundler directory does not exist, install it (using `_bootstrap()`).

	:returns: the script object of `AlfredBundler.scpt`
	:rtype: ``script object``

	GKL
KlMNM,&# Check if Alfred-Bundler is installedNOOL# Check if Alfred-Bundler is installedLPQ
PZRS
R>TU
Tl
V
Vn
WX
WI
Y0_folder_existsYZ
Zo0bundler_dirBUNDLER_DIR
Xf
Um

boovtrue
Sk[[\]
\l^_^# install it if not_``&# install it if not]a
anbc
bI0
_bootstrap
cfQde
dIf
.sysodelanullnmbr
fmgg?ehi
hljkj?9# Path to `AlfredBundler.scpt` in Alfed-Bundler directorykllr# Path to `AlfredBundler.scpt` in Alfed-Bundler directoryimn
mr(op
ol&q
qb&rs
ro$0bundler_dirBUNDLER_DIR
sm$%ttuu6/bundler/AlfredBundler.scpt
po0
as_bundlernvw
vl))xyx# Return script objectyzz,# Return script objectw{
{L)/|
|I).}
.sysoloadscptfile
}o)*0
as_bundlerB~
~l
l AUTO-DOWNLOAD BUNDLER . AUTO-DOWNLOAD BUNDLER
l
i!$
I0
_bootstrap
k
l`Z Check if bundler bash bundlet is installed and install it if not.

	:returns: ``None``

	 Check if bundler bash bundlet is installed and install it if not.

	:returns: ``None``

l"# Ask to install the Bundler8# Ask to install the Bundler
Q
n
I0_install_confirmation
f
R
.ascrerr ********
k
l71# Cannot continue to install the bundler, so stopb# Cannot continue to install the bundler, so stop
L
m
boovfals
l# Download the bundler,# Download the bundler
r)
J'
b
b
mhhttps://github.com/shawnrice/alfred-bundler/archive/
o"0bundler_versionBUNDLER_VERSION
m.zip
b%
b#
mfhttps://bitbucket.org/shawnrice/alfred-bundler/get/
o""0bundler_versionBUNDLER_VERSION
m#$.zip
o0urlsURLs
l**@:# Save Alfred-Bundler zipfile to this location temporarilyt# Save Alfred-Bundler zipfile to this location temporarily
r*5
b*3
l*1
n*1
1/1

strq
o*/0	cache_dir	CACHE_DIR
m12,/installer/bundler.zip
o0_zipfile
X6h
kFc
rFU
lFS
IFS
.sysoexecTEXTTEXT
bFO
bFM
bFK
bFI
mFGZcurl -fsSL --create-dirs --connect-timeout 5
oGH0_url
mIJ -o
oKL0_zipfile
mMN && echo $?
o0_status
ZVc
=V[
oVW0_status
mWZ0
S^_0_url
o9:0urlsURLs
lii## Could not download the file:# Could not download the file
Zi
>in
oij0_status
mjm0
Rq}
.ascrerr ********
my|NCould not download bundler install file

errn
mux
lLF# Ensure directory tree already exists for bundler to be moved into it# Ensure directory tree already exists for bundler to be moved into it

	n
I
0
_check_dir

o0bundler_dirBUNDLER_DIR
f

l;5# Unzip the bundler and move it to its data directoryj# Unzip the bundler and move it to its data directory
r
b
b
b
mcd
l
 n!"
!1

strq
"o0	cache_dir	CACHE_DIR
m##$$l; cd installer; unzip -qo bundler.zip; mv ./*/bundler
l%
%n&'
&1

strq
'o0bundler_dirBUNDLER_DIR
o0_cmd()
(I~*}
~.sysoexecTEXTTEXT
*o||0_cmd})+,
+l{-.{-QK# Wait until bundler is fully unzipped and written to disk before finishing.//# Wait until bundler is fully unzipped and written to disk before finishing,01
0r23
2l4zy
4b56
5oxx0bundler_dirBUNDLER_DIR
6m77886/bundler/AlfredBundler.scptzy
3oww0
as_bundler19:
9V;<
;Iv=u
v.sysodelanullnmbr
=m>>?əu
<H?
?l@ts
@nAB
AIrCqr0_path_existsCDp
Dooo0
as_bundlerpq
Bfts:EF
ElnGHnG,&#TODO: remove bundler files from cacheHIIL#TODO: remove bundler files from cacheFJm
JLllmKL
KlkjikjiLMN
MlhOPhO;5# Function to get confirmation to install the bundlerPQQj# Function to get confirmation to install the bundlerNRS
Ri%(TU
TIgfeg0_install_confirmationfe
UkVVWX
WldYZdY Ask user for permission to install Alfred-Bundler.
	Allow user to go to website for more information, or even to cancel download.

	:returns: ``True`` or raises Error

	Z[[V Ask user for permission to install Alfred-Bundler.
	Allow user to go to website for more information, or even to cancel download.

	:returns: ``True`` or raises Error

	X\]
\lc^_c^0*# Get path to workflow's `info.plist` file_``T# Get path to workflow's `info.plist` file]ab
ar	cd
cbef
engh
gIba`b0_pwda`
hf
fmiijjinfo.plist
do__
0_plistbkl
kl

^mn^m5/# Get name of workflow's from `info.plist` filenoo^# Get name of workflow's from `info.plist` filelpq
pr
rs
rb
tu
tb

vw
vm
xxyyT/usr/libexec/PlistBuddy -c 'Print :name' '
wo]]
0_plist
um
zz{{'
so\\0_cmdq|}
|r~
~I[Z
[.sysoexecTEXTTEXT
oYY0_cmdZ
oXX	0_name}
lWW60# Get workflow's icon, or default to system icon`# Get workflow's icon, or default to system icon
r#
b!
n
IVUTV0_pwdUT
f
m icon.png
oSS	0_icon
r$,
n$*
I%*RQR0_check_iconP
o%&OO	0_iconPQ
f$%
oNN	0_icon
l--MM/)# Prepare explanation text for dialog boxR# Prepare explanation text for dialog box
r-6
b-4
b-2
b-0
o-.LL	0_name
m./ needs to install additional components, which will be placed in the Alfred storage directory and will not interfere with your system.

You may be asked to allow some components to run, depending on your security settings.

You can decline this installation, but
o01KK	0_name
m23 may not work without them. There will be a slight delay after accepting.
oJJ	0_text
l77IHGIHG
r7Y
n7W
1SWF
F
bhit
l7SED
I7SC
C.sysodlogaskrTEXT
o78BB	0_textA
A
btns
J9>
m9:More Info
m:;Cancel@
m;<Proceed@?
?
dflt
m?@>>=
=
appr
bAD
mABSetup
oBC<<	0_name;:
;
disp
4GM9
9
psxf
oKL88	0_icon:ED
o77
0	_response
lZZ660*# If permission granted, continue downloadT# If permission granted, continue download
ZZh54
=Z_
oZ[33
0	_response
m[^Proceed
Lbd
mbc2
2boovtrue54
lii1160# If more info requested, open webpage and error`# If more info requested, open webpage and error
Zi0/
=in
oij..
0	_response
mjmMore Info
kq
Oq
Iw~-,
-.GURLGURLnullTEXT
mwzhttps://github.com/shawnrice/alfred-bundler/wiki/What-is-the-Alfred-Bundler,
mqtsevsalisMacintosh HDH+ҍKSystem Events.appU'A	 CoreServices*A9ҍKҍHҍG=Macintosh HD:System:Library:CoreServices:System Events.app$System Events.appMacintosh HD-System/Library/CoreServices/System Events.app/+
R*
*.ascrerr ********
mFUser looked sought more information)(
)
errn
m''(+0/
l&&,&# If permission denied, stop and errorL# If permission denied, stop and error%
Z$#
=
o""
0	_response
mCancel
R!
!.ascrerr ********
m4User canceled installation

errn
m$#%S

	l

l

l HELPER HANDLERS " HELPER HANDLERS
l
i),
I0_pwd
k8
l Get path to "present working directory", i.e. the workflow's root directory.

	:returns: Path to this script's parent directory
	:rtype: ``string`` (POSIX path)

	J Get path to "present working directory", i.e. the workflow's root directory.

	:returns: Path to this script's parent directory
	:rtype: ``string`` (POSIX path)

l ! =7# Save default AS delimiters, and set delimiters to "/"!""n# Save default AS delimiters, and set delimiters to "/"#$
#r%&
%J''()
(n*+
*1

txdl
+1

ascr),
,m--../
&J//01
0o0astidASTID12

2n34
31

txdl
41

ascr
$56
5l787,&# Get POSIX path of script's directory899L# Get POSIX path of script's directory6:;
:r/<=
<b->?
>l+@
@c+AB
An)CD
C7)EF

citm
Em#%
Fm&(
DlG
GnHI
H1

psxp
IlJ
JIK
.earsffdralis afdr
Kf
Bm)*

TEXT
?m+,LLMM/
=o	0_path;NO
Nl00PQP.(# Reset AS delimiters to original valuesQRRP# Reset AS delimiters to original valuesOST
Sr05UV
Uo010astidASTID
VnWX
W124

txdl
X112

ascrTY
YL68Z
Zo67	0_path[\
[l\]^
]i-0_`
_Ia0_prepare_cmdab
bo0_cmd
`kccde
dlfgf,& Ensure shell `_cmd` is working from the property directory.
	For testing purposes, it also sets the `AB_BRANCH` environmental variable.

	:param _cmd: Shell command to be run in `do shell script`
	:type _cmd: ``string``
	:returns: Shell command with `pwd` set properly
	:rtype: ``string``

	ghhL Ensure shell `_cmd` is working from the property directory.
	For testing purposes, it also sets the `AB_BRANCH` environmental variable.

	:param _cmd: Shell command to be run in `do shell script`
	:type _cmd: ``string``
	:returns: Shell command with `pwd` set properly
	:rtype: ``string``

	eij
ilklk93# Ensure `pwd` is properly quoted for shell commandlmmf# Ensure `pwd` is properly quoted for shell commandjno
nr	pq
pnrs
r1

strq
slt
tnuv
uI0_pwd
vf
qo0pwdowx
wl

yzy& # Declare environmental variablez{{@# Declare environmental variablex|}
|l

~~%#TODO: remove for final release>#TODO: remove for final release}
r

m
0export AB_BRANCH=devel;
o0testing_var
l71# return shell script where `pwd` is properly setb# return shell script where `pwd` is properly set
L
b
b
b
b
o0testing_var
mcd
o0pwd
m; bash
o0_cmd^
l
i14
I0_check_icon
o	0_icon
k
l Check if `_icon` exists, and if not revert to system download icon.

	:returns: POSIX path to `_icon`
	:rtype: ``string`` (POSIX path)

	 Check if `_icon` exists, and if not revert to system download icon.

	:returns: POSIX path to `_icon`
	:rtype: ``string`` (POSIX path)

Q
k
c
4

psxf
o	0_icon
m

alis
L

o
	0_icon
R
.ascrerr ********
L
m/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/SidebarDownloadsFolder.icns
l
i58
I0
_check_dir
o0_folder
k
l Check if `_folder` exists, and if not create it, including any sub-directories.

	:returns: POSIX path to `_folder`
	:rtype: ``string`` (POSIX path)

	0 Check if `_folder` exists, and if not create it, including any sub-directories.

	:returns: POSIX path to `_folder`
	:rtype: ``string`` (POSIX path)

Z
H
n
I0_folder_exists
o0_folder
f
I

.sysoexecTEXTTEXT
b

m
mkdir -p
l
n
1

strq
o0_folder
L
o0_folder
l
l
i9<
I0_folder_exists
o0_folder
k
l Return ``true`` if `_folder` exists, else ``false``

	:param _folder: Full path to directory
	:type _folder: ``string`` (POSIX path)
	:returns: ``Boolean``

	> Return ``true`` if `_folder` exists, else ``false``

	:param _folder: Full path to directory
	:type _folder: ``string`` (POSIX path)
	:returns: ``Boolean``

Z
n
I0_path_exists
o0_folder
f
O
L

l

=

n

m

pcls
l

4

ditm
o0_folder
m

cfol
m
sevsalisMacintosh HDH+ҍKSystem Events.appU'A	 CoreServices*A9ҍKҍHҍG=Macintosh HD:System:Library:CoreServices:System Events.app$System Events.appMacintosh HD-System/Library/CoreServices/System Events.app/
L
m
boovfals
l
i=@
I0_path_exists
o	0_path
kY
l	 Return ``true`` if `_path` exists, else ``false``

	:param _path: Any POSIX path (file or folder)
	:type _path: ``string`` (POSIX path)
	:returns: ``Boolean``

D Return ``true`` if `_path` exists, else ``false``

	:param _path: Any POSIX path (file or folder)
	:type _path: ``string`` (POSIX path)
	:returns: ``Boolean``

Z

G
=
o	0_path
m

msng
n
I
0	_is_empty
o	0_path
f
L
m
boovfals
QY
kO
Z)
= !"
!n#$
#m

pcls
$o	0_path
"m

alis
 L#%%
%m#$
boovtrue&
&Z*O'()*
'E*-+,
+o*+	0_path
,m+,--..:
(k08//01
0405~2
~
alis
2o23}}	0_path13|
3L684
4m67{
{boovtrue|)56
5E;>78
7o;<zz	0_path
8m<=99::/6;y
;kAJ<<=>
=cAG?@
?4AExA
x
psxf
AoCDww	0_path
@mEFv
v
alis>Bu
BLHJC
CmHIt
tboovtrueuy
*LMOD
DmMNs
sboovfals
RrEq
r.ascrerr ********
Eopp0msgq
LWYF
FmWXo
oboovfalsGH
GlnmlnmlHIJ
IiADKL
KIkMjk
0	_is_emptyMNi
Nohh0_objij
Lk(OOPQ
PlgRSgR Return ``true`` if `_obj ` is empty, else ``false``

	:param _obj: Any Applescript type
	:type _obj: (optional)
	:returns: ``Boolean``

	STT Return ``true`` if `_obj ` is empty, else ``false``

	:param _obj: Any Applescript type
	:type _obj: (optional)
	:returns: ``Boolean``

	QUV
UlfWXfW!# Is `_obj ` a ``Boolean``?XYY6# Is `_obj ` a ``Boolean``?VZ[
ZZ\]ed
\E^_
^J``ab
amc
cboovtruebcb
cma
aboovfalsb
_o``0_obj
]L	d
dm
_
_boovfalsed[ef
el^gh^g'!# Is `_obj ` a ``missing value``?hiiB# Is `_obj ` a ``missing value``?fjk
jZlm]\
l=no
no[[0_obj
omZ
Z
msng
mLp
pmY
Yboovtrue]\kqr
qlXstXs"# Is `_obj ` a empty string?tuu8# Is `_obj ` a empty string?rvW
vL(w
w='xy
xn%z{
z1#%V
V
leng
{l#|UT
|n#}~
}I#SRS	0_trimQ
oPP0_objQR
~fUT
ym%&OOWJ
lNMLNMLK
iEH
IJIJ	0_trimH
oGG0_strHI
k
lFF Remove white space from beginning and end of `_str`

	:param _str: A text string
	:type _str: ``string``
	:returns: trimmed string

	 Remove white space from beginning and end of `_str`

	:param _str: A text string
	:type _str: ``string``
	:returns: trimmed string

Z ED
G
G
>
n
mC
C
pcls
oBB0_str
mA
A
ctxt
>

n
m	@
@
pcls
o	??0_str
m>
>
TEXT
=
o==0_str
m<
<
msng
L
o;;0_strED
Z!-:9
=!$
o!"880_str
m"#
L')
o'(770_str:9
V.W
Q6R
r9H
c9F
n9D
7:D6
6
cobj
m>@55
mAC44
o9:330_str
mDE2
2
ctxt
o110_str
R0/
0.ascrerr ********
o..0msg/
LPR
mPQ
C25
o23--0_str
m34
VX
Q`|
rcr
ccp
ncn
7dn,
,
cobj
mhj++
mkm**
ocd))0_str
mno(
(
ctxt
o''0_str
R&%$
&.ascrerr ********%$
Lz|
mz{
D\_
o\]##0_str
m]^ "
L
o!!0_str"K
 "0bundler_versionBUNDLER_VERSION	0_home0bundler_dirBUNDLER_DIR0	cache_dir	CACHE_DIR0load_bundler0
_bootstrap0_install_confirmation0_pwd0_prepare_cmd0_check_icon0
_check_dir0_folder_exists0_path_exists
0	_is_empty	0_trim"/Users/smargheim//Users/smargheim/Library/Application Support/Alfred 2/Workflow Data/alfred.bundler-devel/Users/smargheim/Library/Caches/com.runningwithcrayons.Alfred-2/Workflow Data/alfred.bundler-develD
0load_bundler0
as_bundler
g	t0_folder_exists
0
_bootstrap
	.sysodelanullnmbr
.sysoloadscptfile
0)bk+e
)j+YhOjOb%EOj0
_bootstrap0urlsURLs0_zipfile0_url0_status0_cmd0
as_bundler#7>0_install_confirmation

strq

kocl

cobj
.corecnte********
.sysoexecTEXTTEXT

errn0
_check_dir0_path_exists
.sysodelanullnmbr
)j+W	XfOb%%b%%lvEOb,%EO1[lkh%%%%jEOaYh[OYOa)aalaYhO)bk+Oab,%a%b,%EOjOba%EOh)k+ajYOhU0_install_confirmation
0_plist0_cmd	0_name	0_icon	0_text
0	_responseixz0_pwd
.sysoexecTEXTTEXT0_check_icon

btns

dflt

appr

disp

psxf
.sysodlogaskrTEXT

bhit
.GURLGURLnullTEXT

errn)j+%EO%%EOjEO)j+%EO)k+EO%%%EOmvm%a*a/aa,EOaeYhOa a	ajUO)aalaYhOa)aalaYh0_pwd0astidASTID	0_path
-L

ascr

txdl

cobj
.earsffdralis afdr

psxp

citm

TEXT9,lvE[k/EZ[l/,FZO)j,[\[Zk\Z2&%EO,FO`0_prepare_cmd0_cmd0_cmd0pwd0testing_var0_pwd

strq)j+,EOEO%%%%0_check_icon	0_icon	0_icon

psxf

alis*/&OW	X0
_check_dir0_folder0_folder0_folder_exists

strq
.sysoexecTEXTTEXT)k+,%jYhO0_folder_exists0_folder0_folder0_path_exists

ditm

pcls

cfol)k+*/,UYhOf0_path_exists	0_path	0_path0msg
-9

msng
0	_is_empty

bool

pcls

alis

psxf0msgZ

)k+&fYhO9,eYhO
*/EOeY*/&OeYfW	X	fL
0	_is_empty0_obj0_obj

msng	0_trim

leng)eflvfYhOeYhO)k+,j	0_trim0_str~0_str~0msg}|{zyxwvut
}
pcls
|
ctxt
{
TEXT
z
bool
y
msng
x
cobjw0msgvut,
	,&
&YhOYhO(h[\[Zl\Zi2&EW	X	[OYO(h[\[Zk\Z2&EW	X
	[OYOascrޭ

FasdUAS 1.101.10
k
l& # Current Alfred-Bundler version		@# Current Alfred-Bundler version

j"0bundler_versionBUNDLER_VERSION
m

devel
l%# Path to user's home directory># Path to user's home directory
j	0_home
n

1

psxp
l

I

.earsffdralis afdr
mcusr

rtyp
m

ctxt
l!"!/)# Path to Alfred-Bundler's root directory"##R# Path to Alfred-Bundler's root directory $%
$j&0bundler_dirBUNDLER_DIR
&b'(
'b)*
)l+
+o	0_home
*m,,--Library/Application Support/Alfred 2/Workflow Data/alfred.bundler-
(o"0bundler_versionBUNDLER_VERSION%./
.j00	cache_dir	CACHE_DIR
0b12
1b34
3l5
5o	0_home
4m6677Library/Caches/com.runningwithcrayons.Alfred-2/Workflow Data/alfred.bundler-
2o"0bundler_versionBUNDLER_VERSION/89
8l9:;
:l<=< MAIN API FUNCTION =>>& MAIN API FUNCTION ;?@
?l@AB
Ai CD
CI0load_bundler
Dk/EEFG
FlHIH Load `AlfredBundler.scpt` from the Alfred-Bundler directory as a script object.
	If the Alfred-Bundler directory does not exist, install it (using `_bootstrap()`).

	:returns: the script object of `AlfredBundler.scpt`
	:rtype: ``script object``

	IJJ Load `AlfredBundler.scpt` from the Alfred-Bundler directory as a script object.
	If the Alfred-Bundler directory does not exist, install it (using `_bootstrap()`).

	:returns: the script object of `AlfredBundler.scpt`
	:rtype: ``script object``

	GKL
KlMNM,&# Check if Alfred-Bundler is installedNOOL# Check if Alfred-Bundler is installedLPQ
PZRS
R>TU
Tl
V
Vn
WX
WI
Y0_folder_existsYZ
Zo0bundler_dirBUNDLER_DIR
Xf
Um

boovtrue
Sk[[\]
\l^_^# install it if not_``&# install it if not]a
anbc
bI0
_bootstrap
cfQde
dIf
.sysodelanullnmbr
fmgg?ehi
hljkj?9# Path to `AlfredBundler.scpt` in Alfed-Bundler directorykllr# Path to `AlfredBundler.scpt` in Alfed-Bundler directoryimn
mr(op
ol&q
qb&rs
ro$0bundler_dirBUNDLER_DIR
sm$%ttuu6/bundler/AlfredBundler.scpt
po0
as_bundlernvw
vl))xyx# Return script objectyzz,# Return script objectw{
{L)/|
|I).}
.sysoloadscptfile
}o)*0
as_bundlerB~
~l
l AUTO-DOWNLOAD BUNDLER . AUTO-DOWNLOAD BUNDLER
l
i!$
I0
_bootstrap
k
l`Z Check if bundler bash bundlet is installed and install it if not.

	:returns: ``None``

	 Check if bundler bash bundlet is installed and install it if not.

	:returns: ``None``

l"# Ask to install the Bundler8# Ask to install the Bundler
Q
n
I0_install_confirmation
f
R
.ascrerr ********
k
l71# Cannot continue to install the bundler, so stopb# Cannot continue to install the bundler, so stop
L
m
boovfals
l# Download the bundler,# Download the bundler
r)
J'
b
b
mhhttps://github.com/shawnrice/alfred-bundler/archive/
o"0bundler_versionBUNDLER_VERSION
m.zip
b%
b#
mfhttps://bitbucket.org/shawnrice/alfred-bundler/get/
o""0bundler_versionBUNDLER_VERSION
m#$.zip
o0urlsURLs
l**@:# Save Alfred-Bundler zipfile to this location temporarilyt# Save Alfred-Bundler zipfile to this location temporarily
r*5
b*3
l*1
n*1
1/1

strq
o*/0	cache_dir	CACHE_DIR
m12,/installer/bundler.zip
o0_zipfile
X6h
kFc
rFU
lFS
IFS
.sysoexecTEXTTEXT
bFO
bFM
bFK
bFI
mFGZcurl -fsSL --create-dirs --connect-timeout 5
oGH0_url
mIJ -o
oKL0_zipfile
mMN && echo $?
o0_status
ZVc
=V[
oVW0_status
mWZ0
S^_0_url
o9:0urlsURLs
lii## Could not download the file:# Could not download the file
Zi
>in
oij0_status
mjm0
Rq}
.ascrerr ********
my|NCould not download bundler install file

errn
mux
lLF# Ensure directory tree already exists for bundler to be moved into it# Ensure directory tree already exists for bundler to be moved into it

	n
I
0
_check_dir

o0bundler_dirBUNDLER_DIR
f

l;5# Unzip the bundler and move it to its data directoryj# Unzip the bundler and move it to its data directory
r
b
b
b
mcd
l
 n!"
!1

strq
"o0	cache_dir	CACHE_DIR
m##$$l; cd installer; unzip -qo bundler.zip; mv ./*/bundler
l%
%n&'
&1

strq
'o0bundler_dirBUNDLER_DIR
o0_cmd()
(I~*}
~.sysoexecTEXTTEXT
*o||0_cmd})+,
+l{-.{-QK# Wait until bundler is fully unzipped and written to disk before finishing.//# Wait until bundler is fully unzipped and written to disk before finishing,01
0r23
2l4zy
4b56
5oxx0bundler_dirBUNDLER_DIR
6m77886/bundler/AlfredBundler.scptzy
3oww0
as_bundler19:
9V;<
;Iv=u
v.sysodelanullnmbr
=m>>?əu
<H?
?l@ts
@nAB
AIrCqr0_path_existsCDp
Dooo0
as_bundlerpq
Bfts:En
ELmmnFG
FllkjlkjGHI
HliJKiJ;5# Function to get confirmation to install the bundlerKLLj# Function to get confirmation to install the bundlerIMN
Mi%(OP
OIhgfh0_install_confirmationgf
PkQQRS
RleTUeT Ask user for permission to install Alfred-Bundler.
	Allow user to go to website for more information, or even to cancel download.

	:returns: ``True`` or raises Error

	UVVV Ask user for permission to install Alfred-Bundler.
	Allow user to go to website for more information, or even to cancel download.

	:returns: ``True`` or raises Error

	SWX
WldYZdY0*# Get path to workflow's `info.plist` fileZ[[T# Get path to workflow's `info.plist` fileX\]
\r	^_
^b`a
`nbc
bIcbac0_pwdba
cf
amddeeinfo.plist
_o``
0_plist]fg
fl

_hi_h5/# Get name of workflow's from `info.plist` fileijj^# Get name of workflow's from `info.plist` filegkl
kr
mn
mb
op
ob

qr
qm
ssttT/usr/libexec/PlistBuddy -c 'Print :name' '
ro^^
0_plist
pm
uuvv'
no]]0_cmdlwx
wryz
yI\{[
\.sysoexecTEXTTEXT
{oZZ0_cmd[
zoYY	0_namex|}
|lX~X~60# Get workflow's icon, or default to system icon`# Get workflow's icon, or default to system icon}
r#
b!
n
IWVUW0_pwdVU
f
m icon.png
oTT	0_icon
r$,
n$*
I%*SRS0_check_iconQ
o%&PP	0_iconQR
f$%
oOO	0_icon
l--NN/)# Prepare explanation text for dialog boxR# Prepare explanation text for dialog box
r-6
b-4
b-2
b-0
o-.MM	0_name
m./ needs to install additional components, which will be placed in the Alfred storage directory and will not interfere with your system.

You may be asked to allow some components to run, depending on your security settings.

You can decline this installation, but
o01LL	0_name
m23 may not work without them. There will be a slight delay after accepting.
oKK	0_text
l77JIHJIH
r7Y
n7W
1SWG
G
bhit
l7SFE
I7SD
D.sysodlogaskrTEXT
o78CC	0_textB
B
btns
J9>
m9:More Info
m:;CancelA
m;<ProceedA@
@
dflt
m?@??>
>
appr
bAD
mABSetup
oBC==	0_name<;
<
disp
4GM:
:
psxf
oKL99	0_icon;FE
o88
0	_response
lZZ770*# If permission granted, continue downloadT# If permission granted, continue download
ZZh65
=Z_
oZ[44
0	_response
m[^Proceed
Lbd
mbc3
3boovtrue65
lii2260# If more info requested, open webpage and error`# If more info requested, open webpage and error
Zi10
=in
oij//
0	_response
mjmMore Info
kq
Oq
Iw~.-
..GURLGURLnullTEXT
mwzhttps://github.com/shawnrice/alfred-bundler/wiki/What-is-the-Alfred-Bundler-
mqtsevsalisMacintosh HDH+ҍKSystem Events.appU'A	 CoreServices*A9ҍKҍHҍG=Macintosh HD:System:Library:CoreServices:System Events.app$System Events.appMacintosh HD-System/Library/CoreServices/System Events.app/,
R+
+.ascrerr ********
mFUser looked sought more information*)
*
errn
m((),10
l'',&# If permission denied, stop and errorL# If permission denied, stop and error&
Z%$
=
o##
0	_response
mCancel
R"
".ascrerr ********
m4User canceled installation!
!
errn
m %$&N
l
l
l

 HELPER HANDLERS " HELPER HANDLERS

l
i),
I0_pwd
k8
l Get path to "present working directory", i.e. the workflow's root directory.

	:returns: Path to this script's parent directory
	:rtype: ``string`` (POSIX path)

	J Get path to "present working directory", i.e. the workflow's root directory.

	:returns: Path to this script's parent directory
	:rtype: ``string`` (POSIX path)

l=7# Save default AS delimiters, and set delimiters to "/"n# Save default AS delimiters, and set delimiters to "/"
r !
 J""#$
#n%&
%1

txdl
&1

ascr$'

'm(())/

!J**+,
+o0astidASTID,-
-n./
.1

txdl
/1

ascr01
0l232,&# Get POSIX path of script's directory344L# Get POSIX path of script's directory156
5r/78
7b-9:
9l+;
;c+<=
<n)>?
>7)@A

citm
@m#%
Am&(
?lB
BnCD
C1

psxp
DlE
EIF
.earsffdralis afdr
Ff
=m)*

TEXT
:m+,GGHH/
8o	0_path6IJ
Il00KLK.(# Reset AS delimiters to original valuesLMMP# Reset AS delimiters to original valuesJNO
Nr05PQ
Po010astidASTID
QnRS
R124

txdl
S112

ascrOT
TL68U
Uo67	0_pathVW
VlWXY
Xi-0Z[
ZI\0_prepare_cmd\]
]o0_cmd
[k^^_`
_laba,& Ensure shell `_cmd` is working from the property directory.
	For testing purposes, it also sets the `AB_BRANCH` environmental variable.

	:param _cmd: Shell command to be run in `do shell script`
	:type _cmd: ``string``
	:returns: Shell command with `pwd` set properly
	:rtype: ``string``

	bccL Ensure shell `_cmd` is working from the property directory.
	For testing purposes, it also sets the `AB_BRANCH` environmental variable.

	:param _cmd: Shell command to be run in `do shell script`
	:type _cmd: ``string``
	:returns: Shell command with `pwd` set properly
	:rtype: ``string``

	`de
dlfgf93# Ensure `pwd` is properly quoted for shell commandghhf# Ensure `pwd` is properly quoted for shell commandeij
ir	kl
knmn
m1

strq
nlo
onpq
pI0_pwd
qf
lo0pwdjrs
rl

tut& # Declare environmental variableuvv@# Declare environmental variableswx
wl

yzy%#TODO: remove for final releasez{{>#TODO: remove for final releasex|}
|r

~
~m
0export AB_BRANCH=devel;
o0testing_var}
l71# return shell script where `pwd` is properly setb# return shell script where `pwd` is properly set
L
b
b
b
b
o0testing_var
mcd
o0pwd
m; bash
o0_cmdY
l
i14
I0_check_icon
o	0_icon
k
l Check if `_icon` exists, and if not revert to system download icon.

	:returns: POSIX path to `_icon`
	:rtype: ``string`` (POSIX path)

	 Check if `_icon` exists, and if not revert to system download icon.

	:returns: POSIX path to `_icon`
	:rtype: ``string`` (POSIX path)

Q
k
c
4

psxf
o	0_icon
m

alis
L

o
	0_icon
R
.ascrerr ********
L
m/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/SidebarDownloadsFolder.icns
l
i58
I0
_check_dir
o0_folder
k
l Check if `_folder` exists, and if not create it, including any sub-directories.

	:returns: POSIX path to `_folder`
	:rtype: ``string`` (POSIX path)

	0 Check if `_folder` exists, and if not create it, including any sub-directories.

	:returns: POSIX path to `_folder`
	:rtype: ``string`` (POSIX path)

Z
H
n
I0_folder_exists
o0_folder
f
I

.sysoexecTEXTTEXT
b

m
mkdir -p
l
n
1

strq
o0_folder
L
o0_folder
l
l
i9<
I0_folder_exists
o0_folder
k
l Return ``true`` if `_folder` exists, else ``false``

	:param _folder: Full path to directory
	:type _folder: ``string`` (POSIX path)
	:returns: ``Boolean``

	> Return ``true`` if `_folder` exists, else ``false``

	:param _folder: Full path to directory
	:type _folder: ``string`` (POSIX path)
	:returns: ``Boolean``

Z
n
I0_path_exists
o0_folder
f
O
L

l

=

n

m

pcls
l

4

ditm
o0_folder
m

cfol
m
sevsalisMacintosh HDH+ҍKSystem Events.appU'A	 CoreServices*A9ҍKҍHҍG=Macintosh HD:System:Library:CoreServices:System Events.app$System Events.appMacintosh HD-System/Library/CoreServices/System Events.app/
L
m
boovfals
l
i=@
I0_path_exists
o	0_path
kY
l Return ``true`` if `_path` exists, else ``false``

	:param _path: Any POSIX path (file or folder)
	:type _path: ``string`` (POSIX path)
	:returns: ``Boolean``

	D Return ``true`` if `_path` exists, else ``false``

	:param _path: Any POSIX path (file or folder)
	:type _path: ``string`` (POSIX path)
	:returns: ``Boolean``

Z
G

=

o	0_path

m

msng
n
I
0	_is_empty
o	0_path
f
	L
m
boovfals
QY
kO
Z)
=
n
m

pcls
o	0_path
m

alis
L#%
 m#$
boovtrue!
!Z*O"#$%
"E*-&'
&o*+	0_path
'm+,(()):
#k08**+,
+405-

alis
-o23~~	0_path,.}
.L68/
/m67|
|boovtrue}$01
0E;>23
2o;<{{	0_path
3m<=4455/16z
6kAJ7789
8cAG:;
:4AEy<
y
psxf
<oCDxx	0_path
;mEFw
w
alis9=v
=LHJ>
>mHIu
uboovtruevz
%LMO?
?mMNt
tboovfals
Rs@r
s.ascrerr ********
@oqq0msgr
LWYA
AmWXp
pboovfalsBC
BlonmonmCDE
DiADFG
FIlHkl
0	_is_emptyHIj
Ioii0_objjk
Gk(JJKL
KlhMNhM Return ``true`` if `_obj ` is empty, else ``false``

	:param _obj: Any Applescript type
	:type _obj: (optional)
	:returns: ``Boolean``

	NOO Return ``true`` if `_obj ` is empty, else ``false``

	:param _obj: Any Applescript type
	:type _obj: (optional)
	:returns: ``Boolean``

	LPQ
PlgRSgR!# Is `_obj ` a ``Boolean``?STT6# Is `_obj ` a ``Boolean``?QUV
UZWXfe
WEYZ
YJ[[\]
\md
dboovtrue]^c
^mb
bboovfalsc
Zoaa0_obj
XL	_
_m
`
`boovfalsfeV`a
`l_bc_b'!# Is `_obj ` a ``missing value``?cddB# Is `_obj ` a ``missing value``?aef
eZgh^]
g=ij
io\\0_obj
jm[
[
msng
hLk
kmZ
Zboovtrue^]flm
llYnoYn"# Is `_obj ` a empty string?opp8# Is `_obj ` a empty string?mqX
qL(r
r='st
sn%uv
u1#%W
W
leng
vl#wVU
wn#xy
xI#TzST	0_trimz{R
{oQQ0_objRS
yfVU
tm%&PPXE|}
|lONMONM}~L
~iEH
IKJK	0_trimI
oHH0_strIJ
k
lGG Remove white space from beginning and end of `_str`

	:param _str: A text string
	:type _str: ``string``
	:returns: trimmed string

	 Remove white space from beginning and end of `_str`

	:param _str: A text string
	:type _str: ``string``
	:returns: trimmed string

Z FE
G
G
>
n
mD
D
pcls
oCC0_str
mB
B
ctxt
>

n
m	A
A
pcls
o	@@0_str
m?
?
TEXT
=
o>>0_str
m=
=
msng
L
o<<0_strFE
Z!-;:
=!$
o!"990_str
m"#
L')
o'(880_str;:
V.W
Q6R
r9H
c9F
n9D
7:D7
7
cobj
m>@66
mAC55
o9:440_str
mDE3
3
ctxt
o220_str
R10
1.ascrerr ********
o//0msg0
LPR
mPQ
C25
o23..0_str
m34
VX
Q`|
rcr
ccp
ncn
7dn-
-
cobj
mhj,,
mkm++
ocd**0_str
mno)
)
ctxt
o((0_str
R'&%
'.ascrerr ********&%
Lz|
mz{
D\_
o\]$$0_str
m]^ #
L
o""0_str#L!
!  "0bundler_versionBUNDLER_VERSION	0_home0bundler_dirBUNDLER_DIR0	cache_dir	CACHE_DIR0load_bundler0
_bootstrap0_install_confirmation0_pwd0_prepare_cmd0_check_icon0
_check_dir0_folder_exists0_path_exists
0	_is_empty	0_trim"/Users/smargheim//Users/smargheim/Library/Application Support/Alfred 2/Workflow Data/alfred.bundler-devel/Users/smargheim/Library/Caches/com.runningwithcrayons.Alfred-2/Workflow Data/alfred.bundler-develD0load_bundler

0
as_bundlerg
t	0_folder_exists0
_bootstrap

.sysodelanullnmbr
	.sysoloadscptfile0)bk+e
)j+YhOjOb%EOj0
_bootstrap0urlsURLs0_zipfile0_url0_status0_cmd0
as_bundler#7>0_install_confirmation

strq

kocl

cobj
.corecnte********
.sysoexecTEXTTEXT

errn0
_check_dir0_path_exists
.sysodelanullnmbr
)j+W	XfOb%%b%%lvEOb,%EO1[lkh%%%%jEOaYh[OYOa)aalaYhO)bk+Oab,%a%b,%EOjOba%EOh)k+ajYOhP0_install_confirmation
0_plist0_cmd	0_name	0_icon	0_text
0	_responsedsu0_pwd
.sysoexecTEXTTEXT0_check_icon

btns

dflt

appr

disp

psxf
.sysodlogaskrTEXT

bhit
.GURLGURLnullTEXT

errn)j+%EO%%EOjEO)j+%EO)k+EO%%%EOmvm%a*a/aa,EOaeYhOa a	ajUO)aalaYhOa)aalaYh0_pwd0astidASTID	0_path
(G

ascr

txdl

cobj
.earsffdralis afdr

psxp

citm

TEXT9,lvE[k/EZ[l/,FZO)j,[\[Zk\Z2&%EO,FO[0_prepare_cmd0_cmd0_cmd0pwd0testing_var0_pwd

strq)j+,EOEO%%%%0_check_icon	0_icon	0_icon

psxf

alis*/&OW	X0
_check_dir0_folder0_folder0_folder_exists

strq
.sysoexecTEXTTEXT)k+,%jYhO0_folder_exists0_folder0_folder0_path_exists

ditm

pcls

cfol)k+*/,UYhOf0_path_exists	0_path	0_path0msg
(4

msng
0	_is_empty

bool

pcls

alis

psxf0msgZ

)k+&fYhO9,eYhO
*/EOeY*/&OeYfW	X	fG
0	_is_empty0_obj0_obj

msng	0_trim

leng)eflvfYhOeYhO)k+,j	0_trim0_str0_str0msg~}|{zyxwvu
~
pcls
}
ctxt
|
TEXT
{
bool
z
msng
y
cobjx0msgwvu,
	,&
&YhOYhO(h[\[Zl\Zi2&EW	X	[OYO(h[\[Zk\Z2&EW	X
	[OYOascrޭ


in BBEdit SQL Query updater - fix for optional space at end of SQL_Field line in whereEqualsClause regex search.

-- BBEdit_upgrade_SQL_Query_to_newer_format({})
-- Dan Shockley, NYHTC
-- BBEdit - upgrade SQL Query to newer format

(*
HISTORY:
	1.3 - 2018-09-04 ( dshockley ): fix for optional space at end of SQL_Field line in whereEqualsClause regex search.
	1.2 - 2018-05-22 ( dshockley ): modified to also convert the query to use List to separate the components of the query.
	1.1 - 2017-12-11 ( dshockley ): disable the usually no-longer-needed SQL_EscapeString, but WARN and comment, since it might sitll be needed when using with something OTHER THAN SQL_Where criteria.
	1.0 - 2017-09-15 ( dshockley ): first created.
*)

on run
	BBEdit_upgrade_SQL_Query_to_newer_format({})
end run

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

on BBEdit_upgrade_SQL_Query_to_newer_format({})

	set regexSearch_SQL_Table to "Quote *\\( *TableNameOfField *\\( *([^\\)]+) *\\) *\\)"
	set regexReplace_SQL_Table to "SQL_Table ( \\1 )"

	set regexSearch_SQL_Field to "Quote *\\( ?FieldNameShort *\\( *([^\\)]+) *\\) *\\)"
	set regexReplace_SQL_Field to "SQL_Field ( \\1 )"

	set regexSearch_WhereEqualsClause to "^([\\t ]*)& *SQL_Field *\\( *([^\\)]+) *\\) *
[\\t ]*& \" *= *\"
[\\t ]*& ([^\\r]+)\\r"

	set regexReplace_WhereEqualsClause to "\\1\\& SQL_Where ( \\2 ; \"=\" ; \\3 )\\r"

	set regexSearch_EscapeStringWARN to "SQL_EscapeString *\\( *([^\\)]+) *\\)"

	set regexReplace_EscapeStringWARN to "\\1 /* WARNING!! Had SQL_EscapeString probably NO LONGER NEEDED, so DISABLED! */"

	tell application "BBEdit"
		activate

		tell window 1

			replace regexSearch_SQL_Table using regexReplace_SQL_Table options {search mode:grep, starting at top:true}

			replace regexSearch_SQL_Field using regexReplace_SQL_Field options {search mode:grep, starting at top:true}

			replace regexSearch_WhereEqualsClause using regexReplace_WhereEqualsClause options {search mode:grep, starting at top:true}
			replace regexSearch_EscapeStringWARN using regexReplace_EscapeStringWARN options {search mode:grep, starting at top:true}

			try
				(* convert to using List ( ) for whitespace formatting of query: *)
				set stringStartQuery to "; sqlQuery = "
				set stringEndQuery to "^([\\t]+); sqlResult = "
				set posQueryStart to characterOffset of found object of (find stringStartQuery)
				set posQueryEnd to (characterOffset of found object of (find stringEndQuery options {search mode:grep})) - 1
				select (characters posQueryStart through posQueryEnd)

				replace "\"SELECT" using "List ( \\r\\t\\t  \"SELECT" searching in selection options {search mode:grep}
				replace "^([\\t]+)& " using "\\t\\t; " searching in selection options {search mode:grep}

				set character posQueryEnd to return & tab & tab & ")" & (contents of character posQueryEnd)

			end try

		end tell

	end tell

end BBEdit_upgrade_SQL_Query_to_newer_format

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

-- BBEdit_upgrade_SQL_Query_to_newer_format({})
-- Dan Shockley, NYHTC
-- BBEdit - upgrade SQL Query to newer format

(*
HISTORY:
	1.2 - 2018-05-22 ( dshockley ): modified to also convert the query to use List to separate the components of the query.
	1.1 - 2017-12-11 ( dshockley ): disable the usually no-longer-needed SQL_EscapeString, but WARN and comment, since it might sitll be needed when using with something OTHER THAN SQL_Where criteria.
	1.0 - 2017-09-15 ( dshockley ): first created.
*)

on run
	BBEdit_upgrade_SQL_Query_to_newer_format({})
end run

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

on BBEdit_upgrade_SQL_Query_to_newer_format({})

	set regexSearch_SQL_Table to "Quote *\\( *TableNameOfField *\\( *([^\\)]+) *\\) *\\)"
	set regexReplace_SQL_Table to "SQL_Table ( \\1 )"

	set regexSearch_SQL_Field to "Quote *\\( ?FieldNameShort *\\( *([^\\)]+) *\\) *\\)"
	set regexReplace_SQL_Field to "SQL_Field ( \\1 )"

	set regexSearch_WhereEqualsClause to "^([\\t ]*)& *SQL_Field *\\( *([^\\)]+) *\\)
[\\t ]*& \" *= *\"
[\\t ]*& ([^\\r]+)\\r"

	set regexReplace_WhereEqualsClause to "\\1\\& SQL_Where ( \\2 ; \"=\" ; \\3 )\\r"

	set regexSearch_EscapeStringWARN to "SQL_EscapeString *\\( *([^\\)]+) *\\)"

	set regexReplace_EscapeStringWARN to "\\1 /* WARNING!! Had SQL_EscapeString probably NO LONGER NEEDED, so DISABLED! */"

	tell application "BBEdit"
		activate

		tell window 1

			replace regexSearch_SQL_Table using regexReplace_SQL_Table options {search mode:grep, starting at top:true}

			replace regexSearch_SQL_Field using regexReplace_SQL_Field options {search mode:grep, starting at top:true}

			replace regexSearch_WhereEqualsClause using regexReplace_WhereEqualsClause options {search mode:grep, starting at top:true}
			replace regexSearch_EscapeStringWARN using regexReplace_EscapeStringWARN options {search mode:grep, starting at top:true}

			try
				(* convert to using List ( ) for whitespace formatting of query: *)
				set stringStartQuery to "; sqlQuery = "
				set stringEndQuery to "^([\\t]+); sqlResult = "
				set posQueryStart to characterOffset of found object of (find stringStartQuery)
				set posQueryEnd to (characterOffset of found object of (find stringEndQuery options {search mode:grep})) - 1
				select (characters posQueryStart through posQueryEnd)

				replace "\"SELECT" using "List ( \\r\\t\\t  \"SELECT" searching in selection options {search mode:grep}
				replace "^([\\t]+)& " using "\\t\\t; " searching in selection options {search mode:grep}

				set character posQueryEnd to return & tab & tab & ")" & (contents of character posQueryEnd)

			end try

		end tell

	end tell

end BBEdit_upgrade_SQL_Query_to_newer_format

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


applescript.  oof

applescript.  oof

FasdUAS 1.101.10
k
l
O
r

n

1

pbnd

n
m

cwin
1

desk
o0_b
	mMACSalistMacintosh HDGpH+

Finder.appk"	 CoreServices͒

6Macintosh HD:System:Library:CoreServices:Finder.app
Finder.appMacintosh HD&System/Library/CoreServices/Finder.app/
l
lO
OO
ON
kM
r;
l
e
1

pbnd
J  !"
!o0_x"#$
#o0_y$%&
%o0_w&'
'o0_h()
(r<B*+
*n<@,-
,4=@.

cobj
.m>?
-o<=0_b
+o0_vz)/
/rCM01
0JCI2234
3oCD0_x456
5mDE678
7oEF0_w89
9oFG0_vz
11IL

pbnd
4:

cwin
:m
m;;@alislMacintosh HDGpH+

Terminal.app
1Sg	 	Utilities

2Macintosh HD:Applications:Utilities:Terminal.appTerminal.appMacintosh HD#Applications/Utilities/Terminal.app/
<=><
.aevtoappnull****0_b0_x0_y0_w0_h0_vz=?@A
.aevtoappnull****
?kOBBCC@A
;

desk

cwin

pbnd0_b

cobj0_x0_y0_w0_h0_vzP*,,,EUO=*k/5*,EE[k/EZ[l/EZ[m/EZ[/EZO/EOkv*,FUU>DD
Zascr
ޭ

FasdUAS 1.101.10
k
l
O
r

n

1

pbnd

n
m

cwin
1

desk
o0_b
	mMACSalistMacintosh HD<H+:
Finder.app)l	 CoreServices<q)f:-,6Macintosh HD:System:Library:CoreServices:Finder.app
Finder.appMacintosh HD&System/Library/CoreServices/Finder.app/
l
lO
OO
ON
kM
r;
l
e
1

pbnd
J  !"
!o0_x"#$
#o0_y$%&
%o0_w&'
'o0_h()
(r<B*+
*n<@,-
,4=@.

cobj
.m>?
-o<=0_b
+o0_vz)/
/rCM01
0JCI2234
3oCD0_x456
5mDE678
7oEF0_w89
9oFG0_vz
11IL

pbnd
4:

cwin
:m
m;;@alislMacintosh HD<H+ZTerminal.app "*a	 	Utilities<q+XZY2Macintosh HD:Applications:Utilities:Terminal.appTerminal.appMacintosh HD#Applications/Utilities/Terminal.app/
<=><
.aevtoappnull****0_b0_x0_y0_w0_h0_vz=?@A
.aevtoappnull****
?kOBBCC@A
;

desk

cwin

pbnd0_b

cobj0_x0_y0_w0_h0_vzP*,,,EUO=*k/5*,EE[k/EZ[l/EZ[m/EZ[/EZO/EOkv*,FUU>DD
0
eascr
ޭ


Siftie

Siftie

FasdUAS 1.101.10
k
i
I	0resize_app_window

o0app_name

o0win_position

o0win_size
Z=
=
n
1

prun
4

capp
o0app_name
m
boovtrue
O9
O8
k7
r&
J  !
 n"#
"4$

cobj
$m
#o0win_position!%
%n&'
&4(

cobj
(m
'o0win_position
n)*
)1#%

posn
*l #+
+2 #

cwin,
,r'7-.
-J'1//01
0n'+23
24(+4

cobj
4m)*
3o'(0win_size15
5n+/67
64,/8

cobj
8m-.
7o+,0win_size
.n9:
9146

ptsz
:l14;
;214

cwin
4<

prcs
<o0app_name
m==sevsalis\Macintosh HDBDSystem Events.app
 cuCoreServices0/:System:Library:CoreServices:System Events.app/$System Events.appMacintosh HD-System/Library/CoreServices/System Events.app/>?
>l?@A
@lB
BrCD
CJEEFG
FmGH
Hm$
Do0narrow_center_positionAIJ
Il
K
Kr
LM
LJNNOP
Om"PQ
Qm	m
Mo0narrow_center_sizeJRS
RlSTU
TlV
VrWX
WJYYZ[
Zm[\
\m$
Xo0wide_center_positionU]^
]l_
_r`a
`Jbbcd
cmde
emm
ao0wide_center_size^fg
flghi
hl$j
jI$k0resize_app_windowklm
lmnnoo1Password 7mpq
po0narrow_center_positionqr
ro 0narrow_center_sizeist
sl%-u
uI%-v0resize_app_windowvwx
wm&'yyzzApp Storex{|
{o'(0narrow_center_position|}
}o()0narrow_center_sizet~
~l.6
I.60resize_app_window
m/0Calendar
o010narrow_center_position
o120narrow_center_size
l7B
I7B0resize_app_window
m89CARROTweather
o9:0narrow_center_position
J:>
m:;"
m;<
lCM
ICM0resize_app_window
mDGFantastical
oGH0narrow_center_position
oHI0narrow_center_size
lNX
INX0resize_app_window
mORGoogle Chrome
oRS0narrow_center_position
oST0narrow_center_size
lYc
IYc0resize_app_window
mZ]Linear
o]^0narrow_center_position
o^_0narrow_center_size
ldn
Idn0resize_app_window
mehMail
ohi0narrow_center_position
oij0narrow_center_size
lo~}
Io|{|0resize_app_window
mpsMessages
Jsy
msvzzy
mvwxx$yw
Jy
my|vvu
m|}ttuw{~}
lsr
Iqpq0resize_app_window
mMicrosoft Teams
ooo0narrow_center_positionn
J
mmm"l
mkklnpsr
lji
Ihgh0resize_app_window
m
Music
off0narrow_center_positione
odd0narrow_center_sizeegji
lcb
Ia`a0resize_app_window
mNews
o__0narrow_center_position^
o]]0narrow_center_size^`cb
l\[
IZYZ0resize_app_window
m
Notes
oXX0narrow_center_positionW
oVV0narrow_center_sizeWY\[
l	UT
	IS
RS0resize_app_window

m

Notion
oQQ0narrow_center_positionP
oOO0narrow_center_sizePRUT
lNM
ILKL0resize_app_window
mPhotos
oJJ0narrow_center_positionI
oHH0narrow_center_sizeIKNM
lGF
IE DE0resize_app_window !"
!m##$$Pixelmator Pro"%&
%oCC0narrow_center_position&'B
'oAA0narrow_center_sizeBDGF()
(l*@?
*I>+=>0resize_app_window+,-
,m..//Preview-01
0o<<0narrow_center_position12;
2o::0narrow_center_size;=@?)34
3l598
5I76670resize_app_window678
7m99::RadarScope8;<
;o550narrow_center_position<=4
=o330narrow_center_size46984>?
>l@21
@I0A/00resize_app_windowABC
BmDDEESafariCFG
Fo..0narrow_center_positionGH-
Ho,,0narrow_center_size-/21?IJ
IlK+*
KI)L()0resize_app_windowLMN
MmOOPPSiftieNQR
Qo''0narrow_center_positionRS&
So%%0narrow_center_size&(+*JTU
Tl
V$#
VI
"W!"0resize_app_windowWXY
XmZZ[[
SlackY\]
\o  0narrow_center_position]^
^J	__`a
`m"ab
bm!$#Ucd
cle
eIf0resize_app_windowfgh
gmiijjSpotifyhkl
ko0narrow_center_positionlm
mo0narrow_center_sizedno
nl1p
pI1q0resize_app_windowqrs
rmttuuTextEditsvw
vJ%xxyz
ym z{
{m #]w|

|J%-}}~
~m%(R
m(+

4
o
l2F
I2F0resize_app_window
m36Tweetbot
J6<
m69
m9:$
J<B
m<?
m?@
lGT
IGT0resize_app_window
mHKzoom.us
oKL0narrow_center_position
JLP
mLM"
mMN0resize_app_window
.aevtoappnull****0resize_app_window0app_name0win_position0win_size0app_name0win_position0win_size=

capp

prun

prcs

cobj

cwin

posn

ptsz>*/,e3+*/#k/l/lv*-,FOk/l/lv*-,FUUYh
.aevtoappnull****
kT@IT]hs~(3>ITcn*ny
#.9DOZit$0narrow_center_position"m0narrow_center_size0wide_center_position0wide_center_size0resize_app_window]R4UlvEOlvEOlvEOlvEO*m+O*m+O*m+O*lvm+O*am+O*am+O*am+O*am+O*aalvalvm+O*alvm+O*am+O*am+O*am+O*am+O*am+O*am+O*am+O*am+O*a m+O*a!m+O*a"lvm+O*a#m+O*a$aa%lva&a'lvm+O*a(alvalvm+O*a)lvm+ascr
ޭ

FasdUAS 1.101.10
k
i
I	0resize_app_window

o0app_name

o0win_position

o0win_size
Z=
=
n
1

prun
4

capp
o0app_name
m
boovtrue
O9
O8
k7
r&
J  !
 n"#
"4$

cobj
$m
#o0win_position!%
%n&'
&4(

cobj
(m
'o0win_position
n)*
)1#%

posn
*l #+
+2 #

cwin,
,r'7-.
-J'1//01
0n'+23
24(+4

cobj
4m)*
3o'(0win_size15
5n+/67
64,/8

cobj
8m-.
7o+,0win_size
.n9:
9146

ptsz
:l14;
;214

cwin
4<

prcs
<o0app_name
m==sevsalis\Macintosh HDBDSystem Events.app
 cuCoreServices0/:System:Library:CoreServices:System Events.app/$System Events.appMacintosh HD-System/Library/CoreServices/System Events.app/>?
>l?@A
@lB
BrCD
CJEEFG
FmGH
Hm$
Do0narrow_center_positionAIJ
Il
K
Kr
LM
LJNNOP
Om"PQ
Qm	m
Mo0narrow_center_sizeJRS
RlSTU
TlV
VrWX
WJYYZ[
Zm[\
\m$
Xo0wide_center_positionU]^
]l_
_r`a
`Jbbcd
cmde
emm
ao0wide_center_size^fg
flghi
hl$j
jI$k0resize_app_windowklm
lmnnoo1Password 7mpq
po0narrow_center_positionqr
ro 0narrow_center_sizeist
sl%-u
uI%-v0resize_app_windowvwx
wm&'yyzzApp Storex{|
{o'(0narrow_center_position|}
}o()0narrow_center_sizet~
~l.6
I.60resize_app_window
m/0Calendar
o010narrow_center_position
o120narrow_center_size
l7B
I7B0resize_app_window
m89CARROTweather
o9:0narrow_center_position
J:>
m:;"
m;<
lCM
ICM0resize_app_window
mDGFantastical
oGH0narrow_center_position
oHI0narrow_center_size
lNX
INX0resize_app_window
mORGoogle Chrome
oRS0narrow_center_position
oST0narrow_center_size
lYc
IYc0resize_app_window
mZ]Linear
o]^0narrow_center_position
o^_0narrow_center_size
ldn
Idn0resize_app_window
mehMail
ohi0narrow_center_position
oij0narrow_center_size
lo~}
Io|{|0resize_app_window
mpsMessages
Jsy
msvzzy
mvwxx$yw
Jy
my|vvu
m|}ttuw{~}
lsr
Iqpq0resize_app_window
mMicrosoft Teams
ooo0narrow_center_positionn
J
mmm"l
mkklnpsr
lji
Ihgh0resize_app_window
m
Music
off0narrow_center_positione
odd0narrow_center_sizeegji
lcb
Ia`a0resize_app_window
mNews
o__0narrow_center_position^
o]]0narrow_center_size^`cb
l\[
IZYZ0resize_app_window
m
Notes
oXX0narrow_center_positionW
oVV0narrow_center_sizeWY\[
l	UT
	IS
RS0resize_app_window

m

Notion
oQQ0narrow_center_positionP
oOO0narrow_center_sizePRUT
lNM
ILKL0resize_app_window
mPhotos
oJJ0narrow_center_positionI
oHH0narrow_center_sizeIKNM
lGF
IE DE0resize_app_window !"
!m##$$Pixelmator Pro"%&
%oCC0narrow_center_position&'B
'oAA0narrow_center_sizeBDGF()
(l*@?
*I>+=>0resize_app_window+,-
,m..//Preview-01
0o<<0narrow_center_position12;
2o::0narrow_center_size;=@?)34
3l598
5I76670resize_app_window678
7m99::RadarScope8;<
;o550narrow_center_position<=4
=o330narrow_center_size46984>?
>l@21
@I0A/00resize_app_windowABC
BmDDEESafariCFG
Fo..0narrow_center_positionGH-
Ho,,0narrow_center_size-/21?IJ
IlK+*
KI)L()0resize_app_windowLMN
MmOOPP
SlackNQR
Qo''0narrow_center_positionRS&
SJTTUV
Um%%"VW$
Wm##$&(+*JXY
Xl
Z"!
ZI
 [ 0resize_app_window[\]
\m^^__Spotify]`a
`o0narrow_center_positionab
bo	0narrow_center_size"!Ycd
cl&e
eI&f0resize_app_windowfgh
gmiijjTextEdithkl
kJmmno
nmop
pm]lq
qJ"rrst
smRtu
um 4dvw
vl';x
xI';y
0resize_app_windowyz{
zm(+||}}Tweetbot{~
~J+1
m+.
m./

$
J17
m14
m45
w
l<I
I<I0resize_app_window
m=@zoom.us
o@A0narrow_center_position
JAE
mAB"
mBC
0resize_app_window
.aevtoappnull****0narrow_center_position0narrow_center_size0wide_center_position0wide_center_size0resize_app_window0app_name0win_position0win_size0app_name0win_position0win_size=

capp

prun

prcs

cobj

cwin

posn

ptsz>*/,e3+*/#k/l/lv*-,FOk/l/lv*-,FUUYh
.aevtoappnull****
kI@IT]hs~(3>IXcv)ny
#.9DO^i|$0narrow_center_position"m0narrow_center_size0wide_center_position0wide_center_size0resize_app_window]R4JlvEOlvEOlvEOlvEO*m+O*m+O*m+O*lvm+O*am+O*am+O*am+O*am+O*aalvalvm+O*alvm+O*am+O*am+O*am+O*am+O*am+O*am+O*am+O*am+O*a m+O*a!lvm+O*a"m+O*a#aa$lva%a&lvm+O*a'alvalvm+O*a(lvm+$"m$mascr
ޭ


convert

convert

JsOsaDAS1.001.00bplist00Vscript_var app = Application("Unity");
app.activate();
delay(0.15);
sys = Application("System Events");
sys.keystroke("p", { using: "command down"});jscrޭ


Aflred checkpoint

Aflred checkpoint

FasdUAS 1.101.10
l
i
I
.aevtoappnull****
o0argv
r
I

.sysodsct****scpt

l
b

b
mL
	tell application "System Events"
		set _app to item 1 of (every process whose frontmost is true)
	end tell

	tell application "System Events"
		tell _app
			tell
n
4

cobj
m
o0argv

m
				if (it exists) then perform action "AXPress"
			end tell
		end tell
	end tell
	o0scpt
.aevtoappnull****0scpt
.aevtoappnull****0argv0argv

cobj
.sysodsct****scpt0scptk/%%jE !"!#$#%%&
misccura

pcap&''TablePlus

mbar

mbri$((File

menE"))File

menI **Backup...

actT++AXPressascrޭ

FasdUAS 1.101.10
l
i
I
.aevtoappnull****
o0argv
r
I

.sysodsct****scpt

l
b

b
mL
	tell application "System Events"
		set _app to item 1 of (every process whose frontmost is true)
	end tell

	tell application "System Events"
		tell _app
			tell
n
4

cobj
m
o0argv

m
				if (it exists) then perform action "AXPress"
			end tell
		end tell
	end tell
	o0scpt
.aevtoappnull****0scpt
.aevtoappnull****0argv0argv

cobj
.sysodsct****scpt0scptk/%%jE !"!#$#%&%'(')*)+,+--.
misccura

pcap.//iTerm2

mbar

mbri,00Edit

menE*11Edit

menI(22*Marks and Annotations

menE&33*Marks and Annotations

menI$44Alerts

menE"55Alerts

menI 66$Alert on Next Mark

actT77AXPressascrޭ


Fix bug with previous fix; duplicates are now gone

-- 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

-- 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