TweetFollow Us on Twitter

Studio 54

Volume Number: 19 (2003)
Issue Number: 6
Column Tag: QuickTime

Studio 54

Developing QuickTime Applications with AppleScript Studio

by Tim Monroe

Introduction

In two previous articles ("The Cocoanuts" in MacTech, December 2002 and "Animal Crackers", January 2003), we took a look at developing QuickTime applications using Cocoa. Cocoa is a set of frameworks for applications that run on Mac OS X; it provides a large set of components, or classes, that we can use to build applications or other software modules. These classes handle basic tasks like event processing, memory management, and data manipulation, as well as higher-level tasks like displaying and managing the graphical user interface of an application.

In those earlier articles, we used the Objective-C language to access the various Cocoa frameworks we employed in our sample application. It's possible, however, to use other languages as well. Cocoa supports development using Java and, more recently, AppleScript. The support for AppleScript is provided by AppleScript Studio, a development environment from Apple that we can use to create Mac OS X applications that access Cocoa's classes and perform other tasks using the AppleScript scripting language. These are called AppleScript Studio applications.

In this article, we're going to see how build an AppleScript Studio application that can open and play QuickTime movies. Because it's built on top of Cocoa, our sample application (called ScripTeez) will conform to the Aqua user interface guidelines and will exhibit the behaviors typical of Cocoa applications. And because it's programmed using AppleScript, it should be simpler to write than our sample Objective-C application, MooVeez.

It turns out, however, that the vocabulary provided by AppleScript Studio for controlling the Cocoa QuickTime classes (NSMovie and NSMovieView) is currently fairly limited. Even a task as simple as resizing a window so that it fits the natural dimensions of a movie will require us to go beyond AppleScript and employ a little Objective-C. That's the bad news. The good news is that it's extremely easy to call Objective-C code from our AppleScript code. We'll be able to weave the two languages together into a seamless whole that handles QuickTime movies quite nicely.

Because we'll need to resort to Objective-C for part of our programming, it would probably be good if you were already familiar with at least the first article mentioned above ("The Cocoanuts"). This would also be good because AppleScript Studio uses the same software development tools (Project Builder and Interface Builder) that we encountered in that article. I'll step through the process of building ScripTeez as gradually as possible, but I'll try not to repeat very much of the information found in those two earlier articles on Cocoa and QuickTime.

We'll begin this article by taking a brief look at AppleScript. The AppleScript we need for this article is so simple that you can pick it up as we go along, even if you've never worked directly with AppleScript before. Then I want to take a quick look at how we handle Apple events in our Carbon sample QuickTime application, QTShell; Apple events are the underlying mechanism by which scripts are able to control other applications, and it's useful to see how QTShell handles them. Also I want to take a quick look at some of the scripting support offered by the QuickTime Player application.

We'll spend most of our time learning how to create an AppleScript Studio application that can open a single window that contains a QuickTime movie. You may notice that I've changed the goal here slightly vis-a-vis the earlier articles in this mini-series on QuickTime development environments. In previous articles, we set ourselves the task of developing multi-document QuickTime applications -- that is, applications that allow the user to open several QuickTime movies in windows on the screen, manipulate them in all the standard ways, and possibly also save any edited movies. In this article, our sample application ScripTeez will allow the user to open just one movie file; more importantly, although ScripTeez supports editing operations, it does not allow the user to save any edited movies back out into their movie files. The reason for this departure is simply that the limited vocabulary currently provided by AppleScript Studio for manipulating QuickTime movies does not provide an easy way to save edited movies. To do this, we'd need to resort to more Objective-C, and we've already seen how to do that in the earlier articles on QuickTime and Cocoa. Here I want to focus on what's distinctive about AppleScript Studio from a QuickTime programmer's point of view, which of course is the ability to open and manipulate QuickTime movies using the AppleScript language.

AppleScript Overview

AppleScript is an English-like language used to control the actions of computers and applications. It was introduced way back in Mac OS System 7.5 and has been part of the Macintosh landscape ever since. The primary appeal of AppleScript is its ability to automate workflow -- that is, to encapsulate a predefined series of steps involving one or more applications. These steps could be accomplished with the applications directly (using the mouse and keyboard) but often at the risk of tedium and error. Suppose, for instance, that we've got a large number of QuickTime movie files that need to be hinted so that they can be streamed across the Internet. We could open each file individually in QuickTime Player and select the appropriate menu items to add hint tracks to the movie; it would be far better, however, to construct a script that accomplishes this task automatically when we drop the movie files onto the script file.

Writing Scripts

A script is a sequence of lines of text (usually contained in a file) that can be executed. Here is a simple one-line script:

tell application "QTShell" to open the file "HD:Sample.mov"

This line of script will launch the application QTShell (if it's not already running) and instruct it to open the specified file. Interestingly, this line of script does not cause QTShell to become the frontmost application. If we want that to happen, we need to explicitly activate QTShell, like this:

tell application "QTShell" to open the file "HD:Sample.mov"
tell application "QTShell" to activate

And we can simplify these two lines by using a tell block, which specifies the default target for the statements it contains:

tell application "QTShell"
   open the file "HD:Sample.mov"
   activate
end tell

Words like "the" are optional, and some words can be abbreviated. (For instance, "application" can be abbreviated as "app".) AppleScript also contains facilities for executing statements conditionally, repeating statements multiple times, assigning values to variables, defining subroutines and error handlers, and so forth.

Apple provides an application called Script Editor that's useful for creating and testing scripts. Figure 1 shows a Script Editor script window.


Figure 1: A Script Editor window

As you can see, the window contains a button to run the script in the window. Typically, however, scripters want to package their work as a standalone double-clickable application, called an applet. We can create an applet using Script Editor by selecting the "Save As..." menu item and then choosing the "Application" format option, as shown in Figure 2.


Figure 2: Creating an applet

Handling Apple Events

Not all applications can respond to scripted instructions. An application that can -- called a scriptable application -- must be able to receive and process Apple events. Apple events are messages sent from one application to another that contain attributes (specifying the event class and kind) and possibly also parameters. (An application can also send Apple events to itself, and that is sometime useful.)

Classes of events that apply to specific kinds of objects are collected together into what are called suites. For example, the Text suite contains Apple events that apply to characters, words, paragraphs, text styles, and so forth. And the QuickTime suite contains Apple events that apply to QuickTime movies and tracks.

Our sample application QTShell is scriptable, but it supports only the four Apple events that must be supported by any scriptable application: Open Application, Open Documents, Print Documents, and Quit. It does not support any other events. In particular, it does not support any of the events belonging to the QuickTime suite. So we can launch QTShell and get it to open a specific movie file by executing the scripts shown above, but it does not know how to start the movie playing (for instance).

In the Carbon world, Apple events are sent to an application as high-level events. In the function QTFrame_HandleEvent, we'll see this case block:

case kHighLevelEvent:
   AEProcessAppleEvent(theEvent);
   break;

This simply passes the event to the Apple Event Manager, which dispatches it to one of QTShell's installed Apple event handlers.

It's actually quite easy to add the minimal level of scriptability to a Carbon application. When it starts up, QTShell calls the QTApp_InstallAppleEventHandlers function, defined in Listing 1, to install event handlers for the four required Apple events.

Listing 1: Installing Apple event handlers

QTApp_InstallAppleEventHandlers
void QTApp_InstallAppleEventHandlers (void)
{
   long         myAttrs;
   OSErr      myErr = noErr;
   
   // see whether the Apple Event Manager is available;
   // if it is, install handlers for the four required Apple Events
   myErr = Gestalt(gestaltAppleEventsAttr, &myAttrs);
   if (myErr == noErr) {
      if (myAttrs & (1L << gestaltAppleEventsPresent)) {
         // create routine descriptors for the Apple event handlers
         gHandleOpenAppAEUPP = NewAEEventHandlerUPP
                        (QTApp_HandleOpenApplicationAppleEvent);
         gHandleOpenDocAEUPP = NewAEEventHandlerUPP
                        (QTApp_HandleOpenDocumentAppleEvent);
         gHandlePrintDocAEUPP = NewAEEventHandlerUPP
                        (QTApp_HandlePrintDocumentAppleEvent);
         gHandleQuitAppAEUPP = NewAEEventHandlerUPP
                        (QTApp_HandleQuitApplicationAppleEvent);
         
         // install the handlers
         AEInstallEventHandler(kCoreEventClass,
          kAEOpenApplication, gHandleOpenAppAEUPP, 0L, false);
         AEInstallEventHandler(kCoreEventClass,
          kAEOpenDocuments, gHandleOpenDocAEUPP, 0L, false);
         AEInstallEventHandler(kCoreEventClass, 
          kAEPrintDocuments, gHandlePrintDocAEUPP, 0L, false);
         AEInstallEventHandler(kCoreEventClass, 
          kAEQuitApplication, gHandleQuitAppAEUPP, 0L, false);
      }
   }
}

The Apple event handlers in QTShell are fairly simple. Indeed, since our application must be launched by the operating system in order to receive the OpenApplication event, we don't need to do anything in response to that event except return noErr. Listing 2 shows the nugatory OpenApplication event handler.

Listing 2: Handling the OpenApplication Apple event

QTApp_HandleOpenApplicationAppleEvent
PASCAL_RTN OSErr QTApp_HandleOpenApplicationAppleEvent 
         (const AppleEvent *theMessage, AppleEvent *theReply, 
            long theRefcon)         
{
#pragma unused(theMessage, theReply, theRefcon)
   
   // we don't need to do anything special when opening the application
   return(noErr);
}

And our PrintDocuments handler (Listing 3) is just as simple, since QTShell does not support printing. In this case, we return a suitable error.

Listing 3: Handling the PrintDocuments Apple event

QTApp_HandlePrintDocumentAppleEvent
PASCAL_RTN OSErr QTApp_HandlePrintDocumentAppleEvent 
         (const AppleEvent *theMessage, AppleEvent *theReply, 
            long theRefcon)         
{
#pragma unused(theMessage, theReply, theRefcon)
   return(errAEEventNotHandled);
}

QTShell's handler for the QuitApplication Apple event is only slightly less trivial. It just calls the QTFrame_QuitFramework function, as shown in Listing 4.

Listing 4: Handling the QuitApplication Apple event

QTApp_HandleQuitApplicationAppleEvent
PASCAL_RTN OSErr QTApp_HandleQuitApplicationAppleEvent 
         (const AppleEvent *theMessage, AppleEvent *theReply, 
            long theRefcon)         
{
#pragma unused(theMessage, theReply, theRefcon)
   // close down the entire framework and application
   QTFrame_QuitFramework();
   return(noErr);
}

The only really interesting Apple event handler in QTShell is the OpenDocuments handler, shown in Listing 5.

Listing 5: Handling the QuitApplication Apple event

QTApp_HandleQuitApplicationAppleEvent
PASCAL_RTN OSErr QTApp_HandleOpenDocumentAppleEvent 
         (const AppleEvent *theMessage, AppleEvent *theReply, 
            long theRefcon)         
{
#pragma unused(theReply, theRefcon)
   long               myIndex;
   long               myItemsInList;
   AEKeyword          myKeyWd;
   AEDescList         myDocList;
   long               myActualSize;
   DescType           myTypeCode;
   FSSpec             myFSSpec;
   OSErr              myIgnoreErr = noErr;
   OSErr              myErr = noErr;
   
   // get the direct parameter and put it into myDocList
   myDocList.dataHandle = NULL;
   myErr = AEGetParamDesc(theMessage, keyDirectObject, 
                                          typeAEList, &myDocList);
   
   // count the descriptor records in the list
   if (myErr == noErr)
      myErr = AECountItems(&myDocList, &myItemsInList);
   else {
      myErr = noErr;
      myItemsInList = 0;
   }
   
   // open each specified file
   for (myIndex = 1; myIndex <= myItemsInList; myIndex++)
      if (myErr == noErr) {
         myErr = AEGetNthPtr(&myDocList, myIndex, typeFSS, 
                           &myKeyWd, &myTypeCode, (Ptr)&myFSSpec, 
                           sizeof(myFSSpec), &myActualSize);
         if (myErr == noErr) {
            FInfo      myFinderInfo;
         
            // verify that the file type is MovieFileType
            myErr = FSpGetFInfo(&myFSSpec, &myFinderInfo);   
            if (myErr == noErr) {
               if (myFinderInfo.fdType == MovieFileType)
                  // we've got a movie file; just open it
                  QTFrame_OpenMovieInWindow(NULL, &myFSSpec);
            }
         }
      }
   if (myDocList.dataHandle)
      myIgnoreErr = AEDisposeDesc(&myDocList);
   
   return(myErr);
}

Notice that we reset the local variable myErr to noErr if AEGetParamDesc returns an error. That's because, whenever our application receives the OpenApplication event, it also receives an OpenDocuments event, even if no files were explicitly specified to be opened. In that case, AEGetParamDesc would return an error, which would otherwise be returned to the Apple Event Manager.

Scripting QuickTime Player

QTShell is fairly uninteresting from a scripting point of view: we can launch it, get it to open movies files, and later tell it to quit. On the other end of the scriptability spectrum is the application QuickTime Player, which (from version 5.0.2 onward) supports an extensive vocabulary of commands and object specifiers for controlling movies and their elements. For instance, we can tell QuickTime Player to open a specific movie and play it from the beginning with the script shown in Listing 6.

Listing 6: Playing a movie from the beginning

playMovieFromStart
tell application "QuickTime Player"
   open file "HD:Sample.mov"
   activate
   tell movie 1
      rewind
      play
   end tell
end tell

Notice that we specify the movie to be played by providing its index. This works nicely, even if QuickTime Player is already launched and already has one or movie movies open, because the most recently-opened movie will have index 1. We could also specify the movie by name, but the name we specify needs to be the name of the movie window (which, in QuickTime Player, is not always the basename of the movie file).

Or, we can tell QuickTime Player to delete every disabled track by executing the script shown in Listing 7.

Listing 7: Deleting all disabled tracks

deleteDisabledTracks
tell application "QuickTime Player"
   open file "HD:Sample.mov"
   activate
   if not (exists movie 1) then return
   stop every movie
   delete (every track of movie 1 whose enabled is false)
end tell

Note the parentheses in several of these statements. The parentheses indicate that the result of the code inside the parentheses is to be used as an input value to the statement that contains the parenthetical code. For example, the code "exists movie 1" is evaluated and its result, which is a Boolean value, is used as the input of the conditional expression "if not". Similarly, the result of evaluating the expression "every track of..." is a list of disabled tracks; the delete command takes that list as input and (lo and behold) deletes each item in that list.

As I mentioned, the scripting vocabulary supported by QuickTime Player is quite extensive, and we could easily spend an entire article investigating it. But let's move on to our main task, building a QuickTime application using AppleScript Studio.

The Project

AppleScript Studio applications are Cocoa applications in which the Cocoa classes are manipulated using AppleScript scripts. Accordingly, we'll use the same tools, Project Builder and Interface Builder, that we use to develop Cocoa applications driven by Objective-C or Java code.

Creating a New Project

To get started, we'll launch Project Builder and select "New Project..." in the File menu. In the list of available projects, select "AppleScript Application", as in Figure 3.


Figure 3: The New Project window

Let's save the project with the name "ScripTeez" in our home directory (the default location). Figure 4 shows the new project window, with the top-level disclosure triangles opened.


Figure 4: The ScripTeez project window

The "Product" -- that is, our application -- is shown in red because it hasn't been built yet. Let's build and run the application; when we do that, we'll see the window shown in Figure 5.


Figure 5: The default application window

Eventually we'll need to add a movie player view (of type NSMovieView) to this window; but before we do that, let's take a look at a couple of the files in the project. The file main.m is shown in Listing 8. It's just like the main.m file that we encountered in our Objective-C Cocoa application except that it adds a call to the ASKInitialize function, to initialize the AppleScript Kit (a framework that provides the AppleScript support for our application).

Listing 8: Running the application

main.m
extern void ASKInitialize();
extern int NSApplicationMain(int argc, const char *argv[]);
int main(int argc, const char *argv[])
{
   ASKInitialize();
   
   return NSApplicationMain(argc, argv);
}

For present purposes, we will not need to modify main.m.

The file ScripTeez.applescript is where we'll place our AppleScript code. Out of the box, it's empty except for a few lines of comments.

Modifying the Application Window

Let's put a movie view into the default window. Open the MainMenu.nib file with Interface Builder. (The easiest way to do this is just to double-click the entry in the project window.) Figure 6 shows the main window for this nib file.


Figure 6: The nib file

Select the icon labeled "Window" and then choose the "Show Info" menu item in the Tools menu; in the window that appears, unselect the "Deferred" attribute (as in Figure 7).


Figure 7: The window attributes

Now select the GraphicsViews icon in the toolbar of the palette window. The palette window should then look like Figure 8.


Figure 8: The graphics views panel

Drag a QuickTime icon from the palette into the movie window and resize it so that it looks like Figure 9. There is a 20-pixel border around each edge of the movie view.


Figure 9: The revised application window

Next we need to configure the movie view so that it resizes correctly to maintain that border when the application window is resized. Select the "Size" panel in the Info window and set the springs so that they look like those in Figure 10.


Figure 10: The movie view size attributes

In our Objective-C Cocoa application MooVeez, we needed to make some connections between the movie view and our custom document class, but that isn't necessary here. Instead, we'll refer to the movie view by name in our AppleScript code. So we need to give the movie view a name. Select the "AppleScript" panel in the Info window and set the name of the movie view to "movieView", as in Figure 11.


Figure 11: The movie view name

We are now almost done configuring the application window. The final thing we need to do is attach some event handlers to the application window. These handlers specify some AppleScript code that will be executed when certain specific events occur to that window. In ScripTeez, we care about only two events for the window, namely when it is opened and when it is closed. All other events that pertain to the window will be handled automatically by the underlying Cocoa frameworks.

To attach event handlers to the window, select it and then select the "AppleScript" panel in the Info window. In the top pane of that panel are listed the events to which we can attach AppleScript code. Figure 12 shows how to select the handlers we want to attach, the "awake from nib" handler and the "will close" handler. It also indicates that the AppleScript code for those handlers is to be contained in the file ScripTeez.applescript.


Figure 12: The window event handlers

If we click the "Edit Script" button in the Info window, that file open and we'll see skeletal event handlers already included in it, as in Listing 9. Later on, we'll add some meat to these event handlers.

Listing 9: The skeletal event handlers

ScripTeez.applescript
-- ScripTeez.applescript
-- ScripTeez
-- Created by Tim Monroe on Thu May 08 2003.
-- Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
on will close theObject
   (*Add your script here.*)
end will close
on awake from nib theObject
   (*Add your script here.*)
end awake from nib

Conclusion

Well, that's all we have time for this month. In the next QuickTime Toolkit article, we'll set up the application's menu and see how to get ScripTeez to open and display QuickTime movies.

Credits

Thanks are due to Scott Bongiorno for reviewing this article and providing some useful comments.

Some of the scripts for driving QuickTime Player are modeled on scripts available at http://www.apple.com/applescript/quicktime.


Tim Monroe is a member of the QuickTime engineering team. You can contact him at monroe@apple.com. The views expressed here are not necessarily shared by his employer.

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

BusyContacts 1.6.4 - Fast, efficient con...
BusyContacts is a contact manager for OS X that makes creating, finding, and managing contacts faster and more efficient. It brings to contact management the same power, flexibility, and sharing... Read more
Steam 4.0 - Multiplayer and communicatio...
Steam is a digital distribution, digital rights management, multiplayer and communications platform developed by Valve Corporation. It is used to distribute a large number of games and related media... Read more
OmniGraffle Pro 7.19.3 - Create diagrams...
OmniGraffle Pro helps you draw beautiful diagrams, family trees, flow charts, org charts, layouts, and (mathematically speaking) any other directed or non-directed graphs. We've had people use... Read more
OmniGraffle 7.19.3 - Create diagrams, fl...
OmniGraffle helps you draw beautiful diagrams, family trees, flow charts, org charts, layouts, and (mathematically speaking) any other directed or non-directed graphs. We've had people use Graffle to... Read more
Hopper Disassembler 5.3.3- - Binary disa...
Hopper Disassembler is a binary disassembler, decompiler, and debugger for 32- and 64-bit executables. It will let you disassemble any binary you want, and provide you all the information about its... Read more
calibre 5.35.0 - Complete e-book library...
Calibre is a complete e-book library manager. Organize your collection, convert your books to multiple formats, and sync with all of your devices. Let Calibre be your multi-tasking digital librarian... Read more
Sound Studio 4.10.0 - Robust audio recor...
Sound Studio lets you easily record and professionally edit audio on your Mac. Easily rip vinyls and digitize cassette tapes, or record lectures and voice memos. Prepare for live shows with live... Read more
Sparkle Pro 4.0 - Visual website creator...
Sparkle Pro will change your mind if you thought building websites wasn't for you. Sparkle is the intuitive site builder that lets you create sites for your online portfolio, team or band pages, or... Read more
Dropbox 140.4.1951 - Cloud backup and sy...
Dropbox for Mac is a file hosting service that provides cloud storage, file synchronization, personal cloud, and client software. It is a modern workspace that allows you to get to all of your files... Read more
FotoMagico 6.0.5 - Powerful slideshow cr...
FotoMagico lets you create professional slideshows from your photos and music with just a few, simple mouse clicks. It sports a very clean and intuitive yet powerful user interface. High image... Read more

Latest Forum Discussions

See All

Best iPhone Game Updates: ‘Garena Free F...
Hello everyone, and welcome to the week! It’s time once again for our look back at the noteworthy updates of the last seven days. I got busted last week for not including the obligatory free-to-play matching puzzle game update of the week, and my... | Read more »
‘Horizon Chase’ China Spirit DLC Release...
Following the release of the excellent reveal of the Horizon Chase Senna Forever expansion, the game will be getting a new DLC on mobile platforms today. Today, the Horizon Chase China Spirit DLC pack will release on iOS and Android bringing in 9... | Read more »
‘PUZZLED’ from SNK and Hamster Is Out No...
Following ZED BLADE ACA NeoGeo earlier this month, SNK has brought over another game in the ACA NeoGeo series to both iOS and Android in the form of PUZZLED. SNK and Hamster originally brought the series to mobile with Samurai Shodown IV, Alpha... | Read more »
A House Full of Covid – The TouchArcade...
It’s been a rough week as both of our young children tested positive for Covid, and since recording this early on Friday my wife has tested positive now too. Thankfully the kids seemed to recover fairly quickly and are mostly back to normal, and I... | Read more »
TouchArcade Game of the Week: ‘Krispee S...
Krispee Street is a new hidden object game from Frosty Pop that is based on their popular and almost painfully sweet webcomic Krispee. This is one of the latest titles to be added to the Netflix Games catalog, which means you’ll need to log into... | Read more »
SwitchArcade Round-Up: ‘Escape Lala’, ‘B...
Hello gentle readers, and welcome to the SwitchArcade Round-Up for January 21st, 2022. In today’s article, we’ve got a lot of new releases. A lot. There were eight on the schedule when I went to bed last night. There were twenty-four when I woke up... | Read more »
Beta Testers Needed for Huge Version 2.0...
Ya’ll remember Dungeon Raid, right? The phenomenal matching RPG hybrid that launched on mobile more than a decade ago, but was more or less abandoned by its developer only to die a slow death on the App Store before the 32-bit Appocalypse finally... | Read more »
‘Ark Legends’ Gives Players a Chance to...
It’s Airpods and Amazon gift cards galore as Melting Games opens pre-registration for Ark Legends. The upcoming mobile RPG is giving away tons of in-game goodies such as gold, energy, iron core, hero summon chest and rare iron core to players who... | Read more »
‘Nickelodeon Extreme Tennis’ Out Now on...
Nickelodeon Extreme Tennis () from Old Skull Games and Nickelodeon is this week’s new Apple Arcade release. Nickelodeon Extreme Tennis features characters from old and new Nickelodeon shows including SpongeBob, TMNT, and many more. The tennis game... | Read more »
SwitchArcade Round-Up: ‘RPGolf Legends’,...
Hello gentle readers, and welcome to the SwitchArcade Round-Up for January 20th, 2022. In today’s article, we’ve got a massive amount of new releases to check out. We’ve got summaries of all of them, from heaven to hell. We also have the lists of... | Read more »

Price Scanner via MacPrices.net

Verizon’s 2022 iPad promo: $100-$310 off any...
Verizon has cellular-capable iPads on sale for $100-$310 off MSRP when purchased with an Unlimited service plan. Sale price is applied to your account monthly over a 24 or 30 month period, depending... Read more
Sunday Sale: Apple AirPods are on sale for up...
Amazon has Apple AirPods on sale for $10-$100 off MSRP today, depending on the model. All are in stock today with free delivery: – AirPods Max headphones (Blue): $449 $100 off MSRP – AirPods Max... Read more
These Apple resellers are offering 13″ M1 Mac...
Apple resellers are offering discounts on 13″ MacBook Pros with M1 Apple Silicon processors ranging up to $150 off MSRP. Here’s where to get one today: (1): Apple’s 13″ MacBook Pros with M1 Apple... Read more
Amazon lowers prices on select 13″ M1 MacBook...
Amazon has select Apple 13″ M1 MacBook Airs on sale for $150 off MSRP this weekend, starting at only $849. Their prices are the lowest available for new MacBook Airs today. Stock may come and go, so... Read more
Apple has 13″ M1 MacBook Airs back in stock s...
Apple has restocked a full line of 13″ M1 MacBook Airs, Certified Refurbished, starting at only $849 and up to $190 off original MSRP. These are the cheapest M1-powered MacBooks for sale today at... Read more
In stock and on sale! 16″ 10-Core M1 Pro MacB...
Amazon has new 16″ 10-Core/512GB M1 Pro MacBook Pros in stock today and on sale for $50 off MSRP including free shipping. Their prices are the lowest available for new M1 Pro 16″ MacBook Pro from any... Read more
Deal Alert!: 14″ M1 Pro with 10-Core CPU in s...
Amazon has the new 14″ M1 Pro MacBook Pro with a 10-Core CPU and 16-Core GPU in stock today and on sale for $2299.99 including free shipping. Their price is $200 off Apple’s standard MSRP, and it’s... Read more
Apple has 24-inch M1 iMacs (8-Core CPU/8-Core...
Apple has restocked a wide array of 24-inch M1 iMacs with 8-Core CPUs and 8-Core GPUs in their Certified Refurbished store. Models are available starting at only $1269 and range up to $260 off... Read more
Select 24″ M1 iMacs are on sale for $100 off...
Sales of Apple’s new 24″ M1 iMacs have been rare since its introduction, perhaps due to global supply issues. However, B&H is offering a $100 discount on select 24″ iMacs, and they’re in stock... Read more
M1 Mac minis are back in stock today at Apple...
Apple has M1-powered Mac minis available in their Certified Refurbished section starting at only $589 and up to $140 off MSRP. Each mini comes with Apple’s one-year warranty, and shipping is free: –... Read more

Jobs Board

Registered Nurse (RN) Employee Health PSJH -...
…is calling for a Registered Nurse (RN) Employee Health PSJH to our location in Apple Valley, CA.** We are seeking a Registered Nurse (RN) Employee Health PSJH to be Read more
Systems Administrator - Pearson (United State...
…and troubleshoot Windows operating systems (workstation and server), laptop computers, Apple iPads, Chromebooks and printers** + **Administer and troubleshoot all Read more
IT Assistant Level 1- IT Desktop Support Anal...
…providing tier-1 or better IT help desk support in a large Windows and Apple environment * Experience using IT Service Desk Management Software * Knowledge of IT Read more
Human Resources Business Partner PSJH - Provi...
…**is calling a** **Human Resources Business Partner, PSJH** **to our location in Apple Valley, CA.** **Applicants that meet qualifications will receive a text with Read more
Manager Community Health Investment Programs...
…is calling a Manager Community Health Investment Programs PSJH to our location in Apple Valley, CA.** **Qualified candidates will be invited to do a self-paced video Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.