TweetFollow Us on Twitter

Python For AppleScripters

Volume Number: 20 (2004)
Issue Number: 11
Column Tag: Programming

Python For AppleScripters

by Ryan Wilcox

Introduction By Comparison

A Tale of Two Languages

The advent of OS X brought with it a wealth (some might say invasion) of tools from the Unix world: the command shells, grep, sed, ls, cat, less, vi, emacs — all these utilities and countless others. It also brought with it programming languages — probably the most popular one being Perl. OS X 10.2, however, added to its repertoire a scripting language called Python.

Introduction

Python is easy to use, simple, powerful, and chock-full of great modules (similar to AppleScripts you load via the load script command). The design of the language "just makes sense," the modules are well thought out, and best of all the language has many similarities to AppleScript. Every day it seems I find more uses for Python than I could have imagined. I use Python along with BBEdit to automate all sorts of common text-based tasks: I have scripts to help me resolve CVS conflicts, to convert decimal to hexadecimal (and back), to encode selected text into URL encoded format and more. Python's readable structure and multitude of included modules lends itself to quick one-off utilities, often with less pain than a similar AppleScript - at least in this author's opinion. In this article I'll discuss how Python and AppleScript are similar, and how they differ. Then we'll walk through an example script in both languages. Finally, I'll conclude showing how you can use Python and AppleScript simultaneously in your projects.

AppleScript and Python share many similar traits

Looking at a Python script should be a vaguely familiar experience for an AppleScripter - the same indented flow, and understandable syntax. When you are creating a Python script you often try out little chunks of code first, make sure they work, then put them in a larger whole - just like you might when adding code to an AppleScript. Let's tackle these similarities in more detail:

Whitespace matters

In AppleScript whitespace is automatically added by the compiler so that nested commands (such as those in an if, repeat, try, tell, etc) are always indented properly. In Python whitespace is also important - in fact whitespace tells the compiler that a line or block of code is nested. When the indentation stops, the block of code has ended. Contrast this to AppleScript's approach, where blocks of code are ended with end statements. The key difference with Python is that it does not automatically add whitespace as AppleScript does. This isn't as much of an issues as it sounds, as most text editors auto-indent when you type a return. It's worth mentioning here that statements that mark a block of code (such as for loops, if statements, and even functions) require a colon at the end of the "parent" line. The sample script presented later in the article shows several indented blocks of code.

Having whitespace matter is both a good thing and a bad thing. The good news: every Python script you run into will have a similar style, indentation-wise. The bad news: the compiler will complain if you mix spaces and tabs to indent, and it's annoying to have to debug something you can't see. For this reason using a text editor that can Show Invisibles is so very important(maybe even a requirement) while programming in Python. As a sidenote, in cross-platform scripts, using 4 spaces to indent is recommended over using a tab, as spaces are not so easily mangled by unsavvy text editors.

"simple" syntax

Python's syntax is very straightforward, and often compared to pseudo-code. For contrast, look at the sample script later in this article, implemented first in AppleScript, then in Python. The Python version, while it is not as readable as the near-English AppleScript, reads like English plus a bit of 8th grade algebra. AppleScript's approach of English-Like-Syntax-Wherever-Possible often results in extra typing. Compare if you will AppleScript's:

 set end of myList to "the end" 
to Python's:
myList.append("the end").

Python is not AppleScript

or some, the apparent similarity stops there. Python brings its own unique flavor to the language party, differing from AppleScript in some key areas: cross-platformness, case sensitivity, and Python's (significantly) different approach to types are some of what make Python a unique scripting language when compared to AppleScript.

Python is Cross-Platform

Python runs on most major platforms - both flavors of Mac OS, Windows, Linux, Unix, even the PalmOS. Much of Python's functionality knows what platform a script is currently running under, and adjusts platform specific things. For example, the linesep attribute of the os module will return the line separator character(s) for the current platform. There are certain times when you want to use a platform specific API, and that's perfectly acceptable as well. One Python rule of thumb is "We're all consenting adults here," meaning that the language won't try to prevent you from doing something potentially "naughty" if you want to.

Case Matters

In AppleScript, the compiler changes the case of a variable to be the same as the first instance of that variable. So, while case matters, the compiler takes care of it for you. In Python case also matters, except there is no automatic correction - what you type is what you get.

What do you contain? Types Matter

As any experienced scripter knows, AppleScript plays fast-and-loose with type. Sometimes you can't be sure exactly what you will get back. This has its advantages as well as its disadvantages. Take this line of AppleScript for example:

 set firstNum to "1"
 set testVar to firstNum + 1 

If you know that firstNum can always be converted into number, this works great - it saves everybody some typing. But here's the puzzle: what is testVar? Is it a string? A number? Without a specific declaration, AppleScript will automatically coerce all of the values to the same type, but the question still remains: what type of object will you end up with? (To those of you who answered that the result will be a number, go to the head of the class.) However, as scripts grow in complexity, being explicit regarding what type a variable is becomes essential - you end up almost fighting the implicit coercion you used (and loved) with your smaller script.

With Python, there is no implicit coercion - instead, variables have a very strict sense about what type they are, and what they can do. (For those of you versed in programming terminology, Python is dynamically, but strongly, typed. You can create a variable without caring what type it will be, but Python keeps track of what kind of data that variable currently has in it. Here is that same sample in Python:

 testVar = int("1") + 1

This is how Python does coercion - instead of AppleScript's as xxxxx notation, Python uses xxxx(), as C/C++ does. Trying to run "1" + 1 in python will give a runtime error, as you can not concatenate 'str' and 'int' objects. Python has no idea what to do (it could do two things: cast "1" to an integer, or cast 1 to a string. One answer will result in 2, while the other gives "11"). One of the guidelines (Zens) of Python says: "When faced with ambiguity, resist the temptation to guess." The "Zens of Python" guide both the development of Python as a language and provide a good framework for writing your own scripts and modules. To read more about the culture of Python, and the Zen/Design Principles of Python, visit the following URL:


http: //www.python.org/dev/culture.html


Batteries Included

Like AppleScript, Python has a small core language, while external modules provide additional functionality. In AppleScript, these external modules come in the form of Scripting Additions and Scriptable Applications (created by Apple and third parties). There are a few Scripting Additions that come preinstalled with every Mac OS installation (Standard Additions, URL Access Scripting, Image Capture Scripting, among others), and several of the apps that come preinstalled are scriptable. All Scriptable Applications and Scripting Additions are written in languages like C/C++ or Objective-C. In Python the focus is not so much on applications as it is on modules - collections of Python routines or objects, usually written in Python, that perform certain tasks. These modules are similar in style to AppleScript's script libraries. While some Python modules include C/C++ code, these seem to be the exception, rather than the rule. Python comes with a huge collection of modules called the Standard Library, so instead of asking the Finder for the size of a file, you would call a function in the Standard Library.

It's in the __doc__s

In AppleScript, there is always some human readable documentation: the dictionary of the application or scripting addition. Sometimes the dictionary is not enough but it is always there, on your machine. When I am writing AppleScript, I always have at least one or two dictionaries open, referring to them as I write my script, like a cheat-sheet right there on my desktop.

Python, on the other hand, takes more of a "reference book" approach to documentation - it is available in a number of different formats, (downloadable from http://python.org), but like any reference book, you hope the documentation is up to date, complete, and that it describes the method you want to use. There have been several utilities written to reduce the risk of these mistakes in the documentation happening, and the Python documentation is usually of high quality. Still, the possibility of out of date documentation exists. The Mac Python IDE includes a module browser, letting you explore different modules like you do an AppleScript dictionary, but it's often not as helpful. As mentioned before, most Python modules are coded in Python itself, and you can usually view the source code for a module, trying to figure out what a function actually does.

The standard Python practice is to add a string literal describing the function and parameters it takes as the first line of the function. This string is called a "docstring." If you view a module in the Mac Python IDE's Module Browser, this string will be described as __doc__ (pronounced "under under doc under under") - however this __doc__ string is what is rendered for the documentation - meaning that if the documentation is poor, the __doc__ will probably be as well.

Here's an example of a function with a docstring. But first it is also important to note Python's string literal functionality. If you have a character in a string literal that you would ordinarily have to escape, for example a quote character, you can instead triple-quote the string literal - the string is considered everything enclosed in triple quotes ("""I'm in triple quotes""", for example, is a perfectly valid string literal.)

def addValues(value1, value2): 
  """addValues adds two numbers. Simple. value1 is 
  the first value to add, value2 is the second. Returns 
  these two values added together"""
  return (value1 + value2) 

This standard practice is a great practice to adopt for your own methods. Adopting this documentation convention will help you remember what a function does, why you need it, and what the parameters do when you revisit the function at a later date. AppleScript is without such a standard practice; everybody has their own styles of documenting an AppleScript method, if they do it at all.

An IDE and an example: Kicking the tires

Python makes a great multi-purpose language. Internally we use it from everything from creating shell programs, to making BBEdit Unix filters, creating throw-away one-time scripts, or designing custom CGI scripts for our clients. You can even use Python in conjunction with Apple's Cocoa application framework using PyObjC. With some additional modules, you can use Python just like you would AppleScript - to display simple GUIs, talk to other applications, and do other user administration tasks.

Starting at the beginning: Installing a GUI friendly Python

While you can use Python on the command line, the command line program gives you everything you would expect from a Unix based tool: no GUI capabilities, no IDE and no graphical debugger. In short, it's not the best environment for Mac people who are used to such niceties.

In the pre-OS X days, a Mac OS 9 version of Python, including an IDE, was provided by Jack Jansen. The IDE and all the Mac specific modules from those days still work under OS X, but their appearance has not been updated for OS X. Those looking for prettier IDEs on OS X shouldn't fret - there are several that show promise, but as of this writing most are still in the early stages of development.

You can download the MacPython package at


http://homepages.cwi.nl/ ~jack/macpython/

This package will install the PythonIDE application (found in your Applications/MacPython-2.3 folder) along with some other things. Double click on the Python IDE and you should get something similar to this:


Figure 1.

Got it? Does it look something like this? Good. Let's go to work.

A simple illustration, line by line

Let's start things off with a simple example - a script that accepts user input and appends it to a file. It should be noted here that simple AppleScript display dialog like interfaces aren't Python's strong suit. While the MacPython package helps, it's still not as easy as AppleScript's display dialog. This (and inter-application communication) are two of the things that Python does poorly, however there are two packages currently competing to become the de facto standard for inter-application communication in Python, so the tide (at least on that front) should turn rather quickly.

First, the AppleScript:

set filepath to choose file with prompt "select a file to append to"
set fileRef to open for access filepath with write permission 
repeat 
 set dialogResult to display dialog "enter a line" default answer "line" buttons -
  {"No More", "Enter"} default button 2 
 

 if button returned of dialogResult is "Enter" then 
  set textReturned to text returned of dialogResult 
  write textReturned & return to fileRef 
 else 
  exit repeat 
 end if 
end repeat 
close access fileRef 
Now, the Python: 
import EasyDialogs, os 


filepath = EasyDialogs.AskFileForOpen("select a file to append to") 


if filepath: 
 fileRef = open(filepath, 'w') 
 while True: 
  textReturned = EasyDialogs.AskString( 
   prompt = "enter a line", default = "line", 
   ok="Enter", cancel = "No more") 
  if textReturned: 
   fileRef.write(textReturned + os.linesep) 
  else: 
   break 
 fileRef.close() 

Let's take the Python sample line by line:

import EasyDialogs, os

As mentioned before, Python organizes sets of functionality into modules. Import loads these modules into your script. Here we import both the EasyDialogs module (a Mac specific module) and the cross-platform os module.

filepath = EasyDialogs.AskFileForOpen("file to append 
 to please")

This line calls the AskFileForOpen method in the EasyDialogs module, which will ask the user to select a file. By comparison, AppleScript searches all of the installed scripting additions for you, looking for the command, and sometimes it "helpfully" finds the wrong one. This is what often causes a terminology conflict. If AppleScript required you to specify where to get the terminology from, you might have to write something like set filepath to standard addition's choose file which may be more typing, but would remove any potential ambiguity. Sadly, AppleScript does not support this style of reference.

 if filepath:

In AppleScript, if the user presses cancel in a choose file dialog, AppleScript raises an error and terminates the script (unless you handle the error in an on error block). Python's AskFileForOpen function does no such thing - it just returns None and keeps on executing the script. We must explicitly test the value of filepath for its existence (filepath would be None if the user pressed the "Cancel" button on the dialog).

In Python variables that are None are simply considered false. Truth in Python is a tricky thing, but best explained by the following web page:


http://www.users.csbsju.edu/~clusena/python/fundamentals/node10.html

fileRef = open(filepath, 'w')

Again, similar looking to the AppleScript - open the file at filepath with write permissions.

while True:

Here the aforementioned Zen of Python "when faced with ambiguity, resist the temptation to guess" returns. The above line shows how deeply this statement is ingrained in the Python culture. The equivalent AppleScript statement is just "repeat" - to which Pythonistas would ask "repeat what?". Here Python explicitly says "do the following as long as this statement is true". The True must be capitalized - True means true, while true means nothing. Got it? Good.

 te xtReturned = EasyDialogs.AskString( 
  prompt = "enter a line", default = "line", 
  ok="Enter", cancel = "No more")

By reading the documentation I found this method, and figured out what parameters to pass to it. These parameters are self-explanatory, but it did take a bit of hunting in the documentation (and maybe even a read of the source) to learn exactly how to construct this line.

if textReturned:

Here again we test the value of textReturned - if it contains anything, the if executes. Same as the if filepath line above. It is worth repeating that lines that begin blocks of indented code, such as this line, need a colon at the end.

fileRef.write(textReturned + os.linesep)

Here we write the text the user entered, and a line separator (of whatever platform we're on) to the file. As mentioned before, os.linesep will return the end-of-line character(s) for whatever platform the script is on.

else: 
  break 

Here we come to the end of the if textReturned block. If textReturned is None, as belabored in more detail above, the user pressed the cancel button - we should abort our while loop.

fileRef.close()

Always close our file - in this case, by calling fileRef object's close() method. Note the indentation level of this line - it is on the same level indentation wise, as the while statement. This signals the end of the while loop - the indentation level changed. While this was mentioned previously in the article, in the "whitespace matters" section, it deserves repeating here.

Two Worlds Collide: AppleScript, meet Python

Even if you don't want to use Python as your main scripting language, you can slowly move parts of your AppleScripts into Python - for instance having your Python scripts do things that are hard to do (or slow to do) in AppleScript, but easy in Python. Here's an example that will find a string inside a string (or return 0 if it does not). This task is easy to do in AppleScript (using the offset of functionality), but it can be very slow. Instead of using offset of we use a Python script to do it.

Python script: substr.py:

#!/usr/bin/env python 
#first line tells us where to find python. 


#a # character means the rest of the 
#line is a comment, just like AppleScript's --



import sys 


findWord = sys.argv[1] #get the first command line argument 
thestring = sys.argv[2] #get the string 


print thestring.find(findWord) + 1 
#AppleScript strings start at 1, python's @ 0. Adjust the answer for AS. 

Create the above Python script your favorite text editor, and save it. Make sure the line endings are set to Unix line endings, just to be safe.

Now, create the following AppleScript, and save it in the same folder as the above Python script, in Application format.

 on run 
 display dialog ( "world has been found at character: "

  & pythonSubStr("world", "hello world") ) 
end run 


to pythonSubStr(toFind, theString) 
 set myContainer to getContainerofMe() 


 set myResult to do shell script "python " & myContainer 
  & "substr.py " & " \"" & toFind & "\"" & " \"" &

  theString & "\""



 -- tell python what script to open up, and what params to pass 
 -- also note that the quotes we put around both strings are to prevent the shell from 
 -- breaking them into lots of different arguments (the shell sees a space 
 -- as an argument separator) 
 -- this is usually not what we want to do. These will be removed 
 -- automatically by Python. 
 

 return myResult 
end pythonSubStr 


on getContainerofMe() 
 tell application "Finder"

  set dest to path to me 
  set temp_container to container of dest as alias 
  return (quoted form of POSIX path of temp_container) 
 --POSIX = unix path 
 end tell 
end getContainerofMe

However, it's worth noting here that do shell script on my test machine (400Mhz Powerbook G4) takes about .5 seconds to execute. This is not because Python is slow, but rather do shell script can take a while to do its initialization and termination routines. This slowness, however, may just beat out a vanilla AppleScript using offset of, depending on the data.

Using Python, you can sometimes build functionality into your scripts that normally would require third party OSAXen in AppleScript. Complex string manipulations, regular expressions, even sending email. Using do shell script to merge AppleScript and Python code might just provide that extra oomph for your script, or may just speed up your development process.

Conclusion

With it's familiar-feeling language, cross-platform abilities, large standard library, and simple, readable syntax, you might find Python an interesting choice for your next project - even if it's only a part of it. Feel free to experiment with the built-in Python interpreter. Fire up Terminal.app and enter the command python to be taken into the command line Python's interactive mode (Control-D to get out). For those of you of the GUI persuasion, see the Python Interactive window in the Python IDE. Learn more about Python by visiting the Python website athttp://www.python.org , in particular the Introduction section (http://www.python.org/doc/Intros.html).

References

For additional information on Python, see http://www.python.org. For additional information on using Python on the Mac, see http://www.pythonmac.org/ . Thanks go to Matthew Strange and Jared Barden for reviewing this article.


Ryan Wilcox is the founder of Wilcox Development Solutions (www.wilcoxd.com) specializing in carbonization, cross-platform application development and e-commerce solutions. He often has a hard time thinking of witty things to say in these blurbs. You can reach him at rwilcox@wilcoxd.com.

 
AAPL
$109.41
Apple Inc.
+2.67
MSFT
$45.74
Microsoft Corpora
+0.58
GOOG
$504.89
Google Inc.
+9.50

MacTech Search:
Community Search:

Software Updates via MacUpdate

Command-C 1.1.7 - Clipboard sharing tool...
Command-C is a revolutionary app which makes easy to share your clipboard between iOS and OS X using your local WiFi network, even if the app is not currently opened. Copy anything (text, pictures,... Read more
Tidy Up 4.0.2 - Find duplicate files and...
Tidy Up is a complete duplicate finder and disk-tidiness utility. With Tidy Up you can search for duplicate files and packages by the owner application, content, type, creator, extension, time... Read more
Typinator 6.3 - Speedy and reliable text...
Typinator turbo-charges your typing productivity. Type a little. Typinator does the rest. We've all faced projects that require repetitive typing tasks. With Typinator, you can store commonly used... Read more
GraphicConverter 9.5 - Graphics editor w...
GraphicConverter is an all-purpose image-editing program that can import 200 different graphic-based formats, edit the image, and export it to any of 80 available file formats. The high-end editing... Read more
Toast Titanium 12.0.1 - The ultimate med...
Toast Titanium goes way beyond the very basic burning in the Mac OS and iLife software, and sets the standard for burning CDs, DVDs, and now Blu-ray discs on the Mac. Create superior sounding audio... Read more
QuickBooks 2015 16.0.2.1422 R3 - Financi...
Save 20% on QuickBooks Pro for Mac today through this special discount link QuickBooks Pro 2013 helps you manage your business easily and efficiently. Organize your finances all in one place, track... Read more
Remotix 3.0.6 - Access all your computer...
Remotix is a fast and powerful application to easily access multiple Macs (and PCs) from your own Mac. Features: Complete Apple Screen Sharing support - including Mac OS X login, clipboard... Read more
BetterZip Quick Look Generator 1.5 - Let...
BetterZip Quick Look Generator lets you view the contents of compressed archives through OS X's Quick Look functions. Simply select an archive in the Finder, in Mail, or Spotlight and press the... Read more
Sandvox 2.9.3 - Easily build eye-catchin...
Sandvox is for Mac users who want to create a professional looking website quickly and easily. With Sandvox, you don't need to be a Web genius to build a stylish, feature-rich, standards-compliant... Read more
Pixelmator 3.3.1 - Powerful layer-based...
Pixelmator is a beautifully designed, easy-to-use, fast, and powerful image editor for OS X. It has everything you need to create, edit, and enhance your images. Pixelmator is a layer-based image... Read more

Latest Forum Discussions

See All

Hipstify Review
Hipstify Review By Jennifer Allen on December 17th, 2014 Our Rating: :: COOL FILTERSUniversal App - Designed for iPhone and iPad Add filters, quotes, and fancy frames to your images, thanks to Hipstify.   | Read more »
Mighty Smighties Gets Evolve Cards and N...
Mighty Smighties Gets Evolve Cards and New Worlds Posted by Jessica Fisher on December 17th, 2014 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »
Duckie Deck Card Wars Review
Duckie Deck Card Wars Review By Amy Solomon on December 17th, 2014 Our Rating: :: STYLISH GAME OF CARDSUniversal App - Designed for iPhone and iPad Duckie Deck Card Wars adapts the classic card game War for use on devices, complete... | Read more »
PDF Office Review
PDF Office Review By Jennifer Allen on December 17th, 2014 Our Rating: :: CONVENIENT PDF EDITINGiPad Only App - Designed for the iPad Want to create your own PDF files? Import them from elsewhere? Adapt a web page into a PDF? PDF... | Read more »
The Out There: Ω Edition Update will be...
The Out There: Ω Edition Update will be Releasing in 2015, Bringing Better Graphics and Additional Content Posted by Jessica Fisher on December 17th, 2014 [ permalink ] | Read more »
Pinball Planet Pro (Games)
Pinball Planet Pro 1.02 Device: iOS Universal Category: Games Price: $2.99, Version: 1.02 (iTunes) Description: - Our missionWe've always loved to play pinball games but we noticed most modern pinball games are simulators for the... | Read more »
Ultrakam 4k. The Professional Camera App...
Ultrakam 4k. The Professional Camera App. 3.0 Device: iOS Universal Category: Photography Price: $9.99, Version: 3.0 (iTunes) Description: In March 2014, Ultrakam brought Film Resolution for iPhone for the first time ever and now is... | Read more »
Email+ (Business)
Email+ 1.0 Device: iOS Universal Category: Business Price: $2.99, Version: 1.0 (iTunes) Description: Send email, fast! | Read more »
Mayor it up in SimCity BuildIt, Out Now
Mayor it up in SimCity BuildIt, Out Now Posted by Jessica Fisher on December 16th, 2014 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »
Crusaders Quest Review
Crusaders Quest Review By Jennifer Allen on December 16th, 2014 Our Rating: :: GOTTA HIRE EM ALLUniversal App - Designed for iPhone and iPad Hire as many heroes as possible in this fun at first but grind-heavy freemium RPG.   | Read more »

Price Scanner via MacPrices.net

Holiday sales continue: MacBook Pros for up t...
 B&H Photo has new MacBook Pros on sale for up to $300 off MSRP as part of their Holiday pricing. Shipping is free, and B&H charges NY sales tax only: - 15″ 2.2GHz Retina MacBook Pro: $1699... Read more
Google Search App For iOS Gets A Major Makeov...
Google has given iOS users an early Christmas present with a substantial update of it’s not-very-often-upgraded Google Search app. Google Search has been my go-to tool for Web searches since it was... Read more
ShopKeep Apple Pay And Chip Card Reader Avail...
ShopKeep, a cloud-based technology provider to more than 10,000 small business owners to manage retail shops and restaurants with iPads, has released its new Apple Pay and chip card reader. This... Read more
Holiday sale! 27-inch 5K iMac for $2299, save...
 B&H Photo has the 27″ 3.5GHz 5K iMac in stock today and on sale for $2299 including free shipping plus NY sales tax only. Their price is $200 off MSRP, and it’s the lowest price available for... Read more
Holiday Sale! 3.7GHz Quad Core Mac Pro availa...
 B&H Photo has the 3.7GHz Quad Core Mac Pro on sale for $2599 including free shipping plus NY sales tax only. Their price is $400 off MSRP, and it’s the lowest price for this model from any... Read more
iPhone 6 Number 3 Canadian Google Search Of 2...
CTVNews.ca reports that Apple’s iPhone 6 was the third highest-trending Google Canada search topic of 2014, exceeded only by Robin Williams largely after his death by suicide in August, and the FIFA... Read more
New iPad mini 3 Counter-Top & Wall Mount...
newMacgadgets has announced new secure all-acrylic displays for the iPad mini 3 (also works fine with the mini 2, last year’s iPad mini With Retina Display, and the original iPad mini). The new iPad... Read more
Holiday sales continue, MacBook Airs for up t...
B&H Photo has 2014 MacBook Airs on sale for up to $120 off MSRP, for a limited time, for the Thanksgiving/Christmas Holiday shopping season. Shipping is free, and B&H charges NY sales tax... Read more
B&H lowers price on 27-inch 3.2GHz iMac t...
B&H Photo has lowered their price on the 27″ 3.2GHz iMac, now on sale for $1629 including free shipping plus NY sales tax only. Their price is $170 off MSRP, and it’s the lowest price for this... Read more
15-inch 2.0GHz Retina MacBook Pro available f...
B&H Photo has lowered their price on leftover 2013 15″ 2.0GHz Retina MacBook Pros to $1499 including free shipping plus NY sales tax only. Their price is $500 off original MSRP. Read more

Jobs Board

*Apple* Retail - Multiple Positions (US) - A...
Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
*Apple* Retail - Multiple Positions (US) - A...
Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
*Apple* Retail - Multiple Positions (US) - A...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
*Apple* Retail - Multiple Positions (US) - A...
Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
Project Manager / Business Analyst, WW *Appl...
…a senior project manager / business analyst to work within our Worldwide Apple Fulfillment Operations and the Business Process Re-engineering team. This role will work Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.