Configure player

Close

WWDC Index does not host video files

If you have access to video files, you can configure a URL pattern to be used in a video player.

URL pattern

preview

Use any of these variables in your URL pattern, the pattern is stored in your browsers' local storage.

$id
ID of session: wwdc2007-116
$eventId
ID of event: wwdc2007
$eventContentId
ID of session without event part: 116
$eventShortId
Shortened ID of event: wwdc07
$year
Year of session: 2007
$extension
Extension of original filename: mov
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: ...

WWDC07 • Session 116

Apple Events: Packets of Pure Power

Mac OS X Essentials • 53:37

Speaker: Matt Neuburg

Unlisted on Apple Developer site

Transcript

This transcript has potential transcription errors. We are working on an improved version.

So I'd like to introduce without any further delay Matt Neuburg, author, teacher, programmer and I can attest to really an all around cool dude.

( Applause )

  • Thanks. So can we switch so the demo machine and let's just jump right into it. So I'm the author of this book Apple Script: The Definitive Guide published by O'Reilly, but I'm actually not going to -
  • thank you, I'll sign your copy later but I'm actually not going to talk all that much about Apple Script per se during the course of this, I want to talk about the technology that underlies Apple Script because that's what it is that makes Apple Script work and what it is that makes Apple Script cool.

When I got started in computers things were kind of crude. You couldn't actually run more than one program on the computer at the same time. Basically whatever was running just took over and then there was that thing that multiple finder thing that happened in System 7 where you could sort of run two programs simultaneously.

Then System 7 came along and you were really running two programs simultaneously and along with that System 7 introduced the notion that two programs running simultaneously would be able to send little messages to one another, one of them would be able to tell the other what to do just like as if it was the user holding the mouse and the keyboard except it was telling it what to do in some other way that's an Apple Event, the little message that is send from one program -- one running program to another and that's what I'm calling a packet of power because what does that let you do? It let's you tie two programs together so that your program could be one of these programs, and it could reach out and ask some other program for information or make it do something or some other program or the user could use Apple Event to tell your program what to do, putting things together in ways that you never expected that make your program seem cooler and more powerful, so that's Apple Events. It'll help a little if I show you a picture.

This is a diagram of an Apple Event in action. Now, we have two applications which I'm calling the sender and over on the far right just off the screen because of slight resolution oddities that we're having for some reason -- no, it's just because that's where I positioned the window -- we have another application which I call the target.

So the sender is going to send an Apple Event to the target and in order to do that it assembles the Apple Event and it assembles it out of two pieces which you may think of like a letter in an envelope. So the letter, the contents of the letter, is the Apple Event this is what I want you to do like a telegram: Come at once; I need you.

Okay. And around that is an envelope saying what's to be done with the Apple Event what is the target application and also it includes some other information like how long the sender is willing to wait around for a reply to come back because every Apple Event has a reply. No, it's just -- I think it's just me. I just didn't move the window.

So that is then handed to the system and the system acts like a kind of postman and the postman must then go out and see if it can find the target and, if it can, it hands the target the Apple Event which is shown up here. Now notice this line this -- this column of things that have four letters and a backward slash and four more letters, what is that supposed to represent in the diagram? Well, every Apple Event is actually encoded as two groups of these four letters which are -- these four letters are called four letter codes.

Apple Events are totally -- almost totally composed of four letter codes like this, vast majority of Apple Events are these kinds of four letter codes and what this is supposed to represent conceptually is the notion that these are Apple Events to which the target application is prepared to respond.

If you send an Apple Event to a target application that isn't ready to deal with that particular set of four letter codes that particular Apple Event who knows what's going to happen. So I put up a sort of picture here saying well this -- this target application is in some way advertising these are the Apple Events that you may send to me; so we send one.

When the target -- now meanwhile the sender is waiting around. He's waiting around for the results of this thing. Now meanwhile the target then does whatever the Apple Event tells him to do and -- or something might go wrong and he generates an error. One way or another he puts something back in the envelope, same envelope that the system is holding on to, that's the reply and then he says I put my reply in the envelope.

I've let go thank you very much and the system then turns right around hands that back to the sender. Why does the system have to be involved in this story at all? Because these are two running applications. They're independent, there's many a slip twixt the cup and the lip, anything could go wrong. All right. It may be that the target application is missing in action.

It may be that the target application takes two hours to perform whatever it was told to do and the sender is not willing to wait around that long, all kinds of things could happen. Also, when I say system here, I could be talking about a much more complicated postal system than the system on one machine, for example, Apple Events can travel across the internet. They can travel across the local network from one machine to another. So that system in the middle, the postman, is supposed to be shorthand for all of that. So that's a diagram of an Apple Event.

Now, we are now in an application that I commonly use for sending Apple Events using Apple Script, namely Script Debugger which is written by Mark Albrecht who is sitting right up front here and the man without whom I probably wouldn't be saying any of this. And the reason I'm showing you this is because I want to show you a dictionary -- that's probably not the one I want to show you. Yeah, never mind that. Thanks a lot.

This is a thing called a dictionary and an application which is scriptable by Apple Events usually is Apple Scriptable. It's scriptable by Apple Script and the way that it advertises to the world that is scriptable by Apple Script involves putting up a dictionary and you will notice that this dictionary contains English terms for English-like terms.

So -- and those terms have to do with the kinds of things that this application deals with. So, for example, iPhoto can deal with an album that makes sense and an album is going to contain things like photos. So we run down here and we say, sure enough there's -- there's an element of a -- of an album called a photo and then we can look at what phots consists of and sure enough photos have call kinds of properties, a photo has a date. Now every one of these English-like terms is actually one of those four-letter codes and, in fact, the reason I'm using Script Debugger to show you this is that Script Debugger, being really cool, let's me simply show you the four-letter codes.

So, when you talk about -- when you talk in Apple Script about the dimensions of a photo, that's translated into the four-letter code PDIM. When you talk about the height of a photo, that's translated into the four letters PHIT. When you talk about -- and so on and so forth and the same thing is true for commands. You'll remember that earlier on I showed you those sets of eight letters -- let's just pick a command, assign keyword. I just picked that one out of the blue that is actually the eight letters IPHO followed by AKWD.

So the job of the dictionary is two-fold, one it is two advertise both to machines and to human beings this is how you talk to me. These are the kinds of Apple Events that I receive; the other is to allow Apple Events to consist of four-letter codes but the human interface to Apple Events to consist of English-like terms because you would not want to look at a raw Apple Event; it's too horrible to deal with. Nevertheless, I'm now going to show you one. So, if you have -- if you have any qualms about that, this is the time.

What I'm going to do is I'm going to send an Apple Event, and I'm going to capture it as I do, and I'm going to show you the Apple Event. Now the particular Apple Event that I'm going to show you is going to be directed at Apple Mail and I've chosen this Apple Event because I find it rather compelling. Here's what I'm going to say, I'm going to say, tell application mail to get messages of inbox whose subject contains FS5-beta and whose sender contains Mark. Now the reason I'm showing you this is, that's pretty complicated.

This is going to be a single Apple Event that expresses that notion. Go into the inbox, look at the messages in the inbox, not just any message but the ones whose subject contains the string and not just those but the ones who sender also contains the letters M-A-R-K. Nevertheless a single Apple Events will suffice to say this complicated thing.

So let me actually run the script and there is over on the right where the cursor is that is the actual result, that is the very one -- the very one message in the list in question, but we didn't actually get to see the Apple Events so, now I'm going to do it again with the Script Debugger log window open.

And there lo and behold is the actual Apple Event. Now, if you look at it, you will see that it is almost entirely composed of four-letter codes. First of all at the top there's that CORE/GETD that we saw before in the diagram of Apple Events that I showed you that's -- that's how you say in Apple Event language GET. Okay. Now, what is it that you want me to get. Well, I want you to get from the inbox that's INMB on the line that I'm selecting now, the messages, that's MSSG on the line that I'm selecting here.

And now I'm going to tell you what messages, in other words I want you to give me not just any message but I want you to perform a test that's TEST which you see there that's that four-letter code and that test is going to be composite. So, I'm telling you how to compose the test. It's going to involve two terms joined by AND now that might look like a three-letter code to you, but it's not there is a blank and that counts as part of the four letters. So it's AND blank.

Okay. And what are the two tests that I have to perform, well one of them is that the subject should contain that CONT this string FS5-beta and the other one is that the sender that's SNDR should contain that's CONT the string MARK that's four letters but it's not a four-letter code it's just an ordinary string. So almost this entire thing except for the part that says FS5-beta and the part that says MARK this entire thing is composed of four-letter codes.

So you can -- you can obviously see that it was much more pleasant looking at the Apple Script version of that then it is looking at this and this is why nobody every dares to look upon a raw Apple Event; they're simply too frightening. And then here's the reply coming back and the reply is also an Apple Event, and it's also composed of four-letter codes.

So -- I've -- I've got the message MSG whose ID ID blank blank is 16 and, if you go back to the script, sure enough it says message ID16 of the inbox. So that's what's remain going on behind the scenes every time Apple Events fly around the system.

Now a cool thing is that you can do even more than simply get information you can also give commands. So in this script I'm doing even more. I'm saying move every one of those messages that I talked about in the previous example to a different mailbox and so, if I run that Apple Event there will actually be a change in mail -- let's bring mail where we can see it.

Okay. There it is, now you'll know notice that there are four messages showing. Now I'm going to run this. Okay. Ready, one, two, three, go and sure enough come back over here. We now only have three messages, what happened to the other one, it went into important. It did what it was told to do. So that's even more power packed into a single Apple Event.

So there's a grammar of these Apple Events and, in fact, the reason I'm telling you this is to impress upon you that the grammar of the Apple Script language is, in fact, merely a reflection of the grammar of Apple Events. Apple Script works the way it does because every line -- well, okay. -- every expression is one Apple Event that's a bit rough but it'll do.

Now this is Microsoft Word and I'm showing it to you because I would now like to show you some examples of why Apple Events are cool. Why is it good to be able to do the kind of thing that I just did. Well, I think the answer is that computers are to program, computers should not just be glorified typewriters, computers should do some of our thinking for us and in particular they should do the kind of thinking and the kind of work at which we humans beings are not so good, and I group those three kinds of things that you would want to do with Apple Events into three groups. The first groups is what I call repetition and calculation and so I'm going to show you a little script that performs some repetition and calculation. This is a real-life example.

This is a -- this is a book that I wrote about Tiger. It's been retitled Take Care of -- Take Control of Customizing Leopard but, in fact, it isn't about Leopard yet it's still about Tiger because Leopard wasn't far enough along for me to really say anything very useful and you'll notice that the figure is numbered Figure XX that's because I didn't want to number the figures beforehand here's another one that one is also Figure XX -- here it comes, well, I can't find it but there are others and they're all numbered figure XX. So, yeah there's -- that one that'll do.

There's lots of other diagrams in there and they're all numbered Figure XX and the point that I'm making is that I -- I haven't bothered to put in the numbers because I might want to rearrange the figures and, yes, there is a kind of auto numbering feature in word, but it doesn't work as well as I'd like it to.

It would be better if I could just leave them all until the last minute and then, when I'm ready to rock and roll and we're ready to publish the thing as a PDF, then I'm going to run through and actually create the numbers, and now I'm going to do that. Here's the script that does it, this is the actual script that is actually used in actual real-life by TidBITS Take Control Publishing. We actually do this, this is how we write our books. We press this button.

We're now running through and finding all of those things, and you'll see, if you look down at the bottom, you'll see each figure being found the XX is being changed, 14 that's it. So you just saw us go through. We found 14 of those Figure XXX things and they were numbered successively, repetition and calculation sure a human could have done that, find the next one, call it Figure 1, find the next one, call it Figure 2. Sure as shooting you're going to make some mistake, or you're going to be completely bored, or you'll probably just jump off a cliff because the job is just so terrible.

Also, what if there were a hundred of them, what if there were a thousand of them, makes no difference to the computer. Computers are good at repetition and calculation. So that's the first thing -- that's the first kind of thing that I like to use Apple Events for. Second kind of thing, now I'm bringing up iTunes.

I can use Apple Events to answer a question that the writers of an application might not have thought I'd like to ask. Now iTunes as you know consists of tracks and playlists -- where are you iTunes. So I've got these playlists down the side and I've got all the tracks all the songs that are in my music library, and I personally do not like there to be any songs in my music library that are not in some playlist or other. I called songs like that, songs that are not in any playlist, orphans.

Now it turns out in iTunes there just doesn't happen to be any simple interface for asking the question, where are the orphans. There are ways around this and -- and you can find out quite a lot of information, for example, I can take -- I'll just take a typical song -- I can find out what playlist he's part of -- here's another one, I can find out what playlist he's part of, but I wouldn't want to have to do that manually for all of them, that's a kind of an example of repetition again.

There's lots and lots of these songs, so I've so I've written a script that answers this question. I'll just run it, here we go, we're off to the races and the answer comes up, went through all of them, found three of them, those are my orphans, and it just lists their names and sure enough they really are orphans. Now the iTunes people could remedy this situation they could have a feature of the GUI. They could have a button or menu item that says 'find orphans' or 'list orphans' but it happens that they didn't think of that.

Now some people might say that's bad, my attitude is so what. They've made the application scriptable, so I can find out that information by using Apple Events. So it doesn't bother me that they didn't include that as part of the GUI, I can include it as part of the GUI and m I really can include it as part of the GUI because a feature of iTunes is its got a scripts menu. So the script that I just showed you I can put it in iTunes's script ment it's the last one there orphans and then, whenever I want to know the answer to this question, I just run that. So I've actually inserted my own script into iTunes' GUI.

Why is that possible, because the people at iTunes were wise enough -- the people who wrote iTunes were wise enough to realize, we don't know everything that someone might want to do with us. We'll leave ourselves open to be scriptable. I'm telling you all of this because I'm saying, when you write your application, you should be thinking about making yourself scriptable for the very same reason. You don't know what people are going to want to do. You can't put in every piece of interface, but you can open yourself to scriptability.

Finally, the third thing that I like to use scripts for is to take advantage of existing functionality in some applications, so that I don't have to do any extra programming. As you know programers are lazy that's regarded as a virtue among programers, to be lazy. Here is a large text document. It happens to be Benjamin Jowett's translation of Plato's Crito and that happens that I would like to know what are the most common words used in this document, longer than a certain length, let's not use words like "the" and "what".

Now, it's very easy to find that out and, in fact, I don't even need Apple Script for that, I can just use any ordinary scripting language like Pearl and Ruby. It's a text document, we'll just run through make what's called a histogram count the number of occurrences of each individual word, and we're done, but it just so happens that the people who assigned me the task of answering the question would also like a graph.

Now I do not want to program the making of a graph, so instantly I start asking myself, what programs have I got on my computer that can make a graph? Well, I couldn't think of anything except for Microsoft Excel. Now this is surely not what the Excel people were thinking they were going to get used for but Excel is scriptable, and it does make graphs and that means that I can just go ahead and hand -- I can perform my histogram count, hand the data over to Excel and use Apple Events to tell it to graph that thing. So I'm going to do that right now, so we're off to the races, there's the data and there's the graph.

Now isn't that nice. This is taking advantage of the power of different applications. You have lots of applications sitting on your computer that can do always kinds of things and, so you can take advantage of their functionality. You can take advantage of them as a scriptor or you can take advantage of them as a programmer. You could -- you could write a program that does something and you don't want to bother to write graph power into it, but you can say, well, if you've got Excel, then Excel will draw the graph, and I'll send it the necessary Apple Event.

Anyway that's my third example of the things I like to do with Apple Events, taking advantage of existing functionality so that I can be lazy. Often taking advantage of existing functionality in ways that the guys that wrote the program probably didn't expect.

( Silence )

Now, I'm now going to talk about what it would take for you, your application, to deal with Apple Events, and I'm going to look at it from both directions. You can be the sender or you can be the target. I'll talk about the sender first and then I'll talk about the target.

So how can you send Apple Events? Well, to send Apple Events, you have to make Apple Events, and how are you going to do that? Well, one way to do it is to simply make raw Apple Events. It's a very unpleasant task, this is a little application that I've written that actually creates a raw Apple Event and, if you look down through this code most of which is Carbon because, although, I'm using Cocoa you have to use Carbon calls in order to actually put the Apple Event together from its individual bits, you will see the little bits, the little four-letter codes in here that typify an Apple Event. So you can actually see me putting the whole thing together I'll scroll down a little this is sure -- boy oh boy this is sure a lot of code and let's see what it actually does when we run it. So I'll build the application.

I'll run it -- as soon as it comes up, come on give me some interface please, thank you very much -- I'll press the little button and I just sent my Apple Event and guess what it does, it goes out to BB Edit, and it says BB Edit make a new document and make that new document contain the phrase, "Hello World." That's all it does, now that was a heck of a lot of work in order to make BB Edit say, "Hello World." So this is obviously not the kind of solution that you would like to use, making a raw Apple Event is really a lot of work.

What you'd like is something that's more like what I would call a language-based solution. You'd like to do this more like it was English, remember the whole point about being Apple Scriptable is that you put up that dictionary. I shouldn't have to deal with these four-letter codes. I should simply be able to deal with the English-like terms, pass through those English-like terms through the dictionary. Get the whole thing automatically translated into an Apple Event and send it that way. Now one way to do that obviously is to do it in Apple Script, and we can actually do that.

( Silence )

So I could go back to Script Debugger, make a new script, say tell Ap BB Edit activate, make new document, set text of document 1 to Hello World, and run it. There it is, so that was a little easier and yet the Apple Event that I made is the very same Apple Event that you just saw me construct in raw form using Cocoa and Carbon and there are other language-based solutions for doing this kind of thing.

It used to be that Apple Script was sort of the big cookie on the block, and it sort of still is but, for example, now you can do this kind of thing in Ruby. In Leopard they'll be a -- they'll be the Ruby scripting bridge Ruby OSA, this is preLeopard, I'm running on a Tiger machine so that doesn't -- that doesn't exist on my machine yet, but I'm using a thing by a guy called Amos Sanderson (presumed spelling) called Ap Script which does exactly the same kind of thing and this is what I was running before when I did that thing with the histogram and Excel.

Now this is Ruby, so this part is pure Ruby, here I'm actually creating the histogram. I make a hash. I go through the words of the document one at a time. I hash them right in. I count that's it, very, very simple, very, very fast, this is the kind of thing that Ruby is good at.

But now look what happens, all of a sudden it looks like I'm talking to Excel, and look I'm using terms that are English-like terms that look like they came right out of Apple Script. I'm telling Excel to activate. I'm telling Excel to make a new workbook. I'm telling Excel to make a new chart sheet.

So, I mean, these are -- all this language that you see down in the bottom half of the window that all comes directly out of the dictionary. How is this possible? It's possible because Ruby is a wonderful language. What happens is as soon as I say Excel equals app Microsoft Excel, app Script this thing by Amos Sanderson just goes out and reads the dictionary and because Ruby is so wonderfully dynamic, it just takes those English-like terms and essentially makes them things that you can say, while you're talking Ruby. So you're talking Ruby, but you're talking Apple Script. You're using Apple Script's English-like terms.

So -- and there's other ways to do this as well, in Leopard, of course, there's also going to be the Cocoa Scripting bridge so you can do the same kind of thing in Cocoa, and it's going to look a lot like this. You can do the same kind of thing in Perl, these are all technologies that Apple is going to be bringing to Leopard to make it easier to use the English-like terms but distinguish -- and you might say, oh, good I'm not going to have to use Apple Script, well yes you are using Apple Script, distinguish between Apple Script, the language, and Apple Script, the technology.

This is Ruby the language not Apple Script the language, but I'm still passing through Apple Script the technology because somebody is taking all these English-like terms and turning them into four-letter codes and turning that into Apple Events and sending them and that's the very same technology that backs Apple Script. So that's why I say it's the Apple Events themselves that are the packets of pure power, scripting comes from Apple Events.

( Humming )

Now let's go the other way, what would it take for you to receive Apple Events? Well, if all you want to do is receive four-letter codes and you don't want to do anything very complicated or sophisticated, it's actually quite easy. Now here's a very short program and all it does is make it possible for me to receive a single Apple Event.

So in the first half of this thing what I do is in Application Did Finish Launching, that is to say during the course of starting up but late enough in the course of starting up that this will work properly, what I do I talk to the NS Apple Event Manager and I ask him to set an Event Handler for a particular Apple Event whose four-letter codes are MATT and COOL. I think that's a particular aptly named Apple Event, I like that, and then what I do is down here here's the handler for when that comes in.

So the idea is that handle reply that selector which is this, handle reply, is going to be called when that Apple Event comes in. So what do I do? Well, the first thing I do is make sure that really is the right Apple Event because you never know there's many a slip twixt the cup and the lip, and then I've got a text field in my interface and I simply set that to "thank you" and that's going to be an indicator to us that I received the Apple Event in good order. Let's try it.

So I'm building, still building and running and there's my interface and so now I'm going to send the MATT COOL event. Now this is -- I'm doing it through Apple Script but -- but this little phrase over here Event MATT COOL is -- is -- it's not Apple Script. It's simply a raw Apple Event consisting of those two four-letter codes.

So, when I run this, I'm going to be talking to that application which you see over on the left in the background and, if everything is working correctly, the phrase send me a MATT COOL event please will change to thank you. Let's try it. Okay one, two, three, go and it worked.

So, yes, my application was able to receive an Apple Events, but it was a very, very simple Apple Event. It was not like get every message of the inbox whose subject contains FS5-beta that would have been much more difficult to parse and so Apple has made is easier for you to parse this kind of thing in a Cocoa Cocoa application through the Cocoa Scriptability layer and, if you have an application and you want -- if you have a Cocoa application and you want to make it scriptable, you use the Cocoa Scriptability layer to do that and now you've got a scriptable application.

Now the entire rest of this talk is going to be devoted to answering the question, just how hard is this to do? And the answer is well, it's really not all that hard and, in fact, it's not all that hard to do after the fact. So you might realize sort of late in the game that you really ought to add scriptability to your existing application, you can do that.

You don't actually have -- it helps if you've planned the entire time to do that, but you don't actually have to have planned the entire time, and I'm going to demonstrate this with an actual application that I added scriptability to it and to make the story more interesting; it's not my application. The application came to me prewritten, so before I do anything else I'm going to show you what the application does.

This application is by Aaron Hillengass (presumed spelling) the guy that wrote the Cocoa book, and he sent me this application -- he sent me the code, and he said, can you make this scriptable? This is an application that he gives away for free over the internet and let's just run it and see what it does.

Compile. And run. There it is. Now his application puts up -- it's a documents -- it's a document-based application and every document consists of a window divided into eight squares and the object of the game is that you drag stuff into each of these eight squares, and you can drag it either from this window over on the left which is called the catalog window, so I can take the very window that we're looking at right now -- if I can get the mouse to work, there it is.

Let me just drag that right in, there it is. It's -- it's been turned on its side for reasons that I'll explain later, and I can scroll through the catalog. I can go to Page 45 of the catalog, drag that into a different one, not very visible let's do a different one, there we go.

I can also drag things from the Finder, so, for example, right here I've got a jpeg, the one that I showed you earlier in the talk, I'll drag that into number 2, there it is Apple Script: Definitive Guide that will -- that will serve as an example. Here's -- here's the PDF that I showed you earlier.

Now why does Aaron think this is a good thing to be able to do? Because it turns around -- turns out that among the people who are doing -- getting things done kinds of things, they like to carry these little eight-page booklets around with them that like remind them of the things they have to do during the day and there's a way of taking this eight-page thing.

You print it out and then you -- you snip along the snippy line and you fold along all the foldy lines and guess what, it turns out that it's a little eight-page document and all the pages that are like lying on their sides and upside down, they all come out right side up and everything is great.

Okay. So this is a little application that allows you to do that, and Aaron said to me I've written this application, people are using it, but it doesn't have scriptability, can you make it scriptable? So the object of the game was, I am to make this application scriptable and, if at all possible I don't want to touch Aaron's code, can I do it ? Yes. I gave it away, yes, you can do it.

How, first you need a plan. Here's my plan. So I thought about what do we want to be able to say. We want to be able to do what you just saw me do, dragging things from the Finder or from the catalog into a page of a document.

Ooh, a page of a document. Okay. So what have I got? What are the -- what's the object model of my application. Well, I've got the application at the top level because all applications have the application object at the top level and then an application can have multiple documents. This is a document-based application, happens there was only one document open over here but you can actually have many, and then every document has -- has something that I'll call pages and that's the things that you see these numbers on. They're numbered 1 through 8.

So I'll just treat those as elements of a document. So every document has eight page elements. Now this is a funny kind of element because in most scriptable applications you can make new ones, you can delete those elements. No, in this particular application I'm going to have a rule that says every page has exactly eight elements. You can't alter that fact, and I need to build that into the way I make the thing scriptable.

Now let's talk about pages. Now, again I need a way to make the page have in it either a particular page of the catalog or a particular file that's found in the Finder. Okay. So to do that I'm going to have two settable properties that a scriptor can use, either the scriptor can take a catalog source page and assign -- assign that property of a page or the file source -- those are just names that I made up.

So what -- basically what I'm getting at is, in my mind I'm planning that the ultimate user is going to be able to say things like this, tell application page packer to tell document 1 to tell Page 3 to set its catalog source page to 4 that's going to mean that we should take the fourth page of the catalog and assign it into Page 3 of the first document or -- or I can tell a different page, say Page 4 to set its file source to, and then I'll give the alias for -- and -- and path for some file that's -- that's in the Finder, from some file that's on disc, that's the way I want to be able to talk. So now I have a plan good.

( Silence )

To carry out my plan I have to act in two parts. First I have to think about the dictionary, remember that all important dictionary, remember I showed you the dictionary for iPhoto earlier? Well, now I'm going to write a dictionary, and I know what has to go in that dictionary because what it is is it's got to be the stuff that I said according to my plan.

I've got to say in the dictionary, there is an application, the application has document elements, every document has page elements, and a page has a file source property and a catalog source page property. I have to say that in the dictionary. Now in Tiger and later, that is to say also in Leopard, a dictionary can be written in XML in what's called .sdef format .SDEF and the way to deal with this is through the wonderful free program SDEF Editor. So we download SDEF Editor and you create your dictionary and here's mine.

So, there's the application and sure enough and application has a document element, so far so good. Here's the document and sure enough, a document has a page element and, finally, here is a page and sure enough a page has catalog source page and file source properties. I'll make that a little larger so it's a little easier to see. Maybe. Thank you.

Now this is the really interesting part, in the Cocoa Scripting -- in the Cocoa Scriptability layer the dictionary has a second job to do and that job is to translate between the incoming Apple Events and your Cocoa code, and it does this through Keyvalue Coding and so every entry in the dictionary has what's called a Key and you must be very careful about this. I'm so careful that, in fact, I write it all down on a piece of paper. So let's go back to the page -- let's go back to the document first.

You remember that the document has page elements, you go down to the bottom here, and you'll see it says the Cocoa Key is pages array. Now I just made that up but whatever I make up, I must remember what it is, capitalization EVERYTHING. This is tremendously important because, if I get this wrong, it's not going to work and I'm not going to know why not.

So I -- I pick some arbitrary key but I must stick to it. So this is the Cocoa Key the -- the -- the letters pages array are going to appear in my Cocoa code and you will see that, so that is the key by which the document is able to refer to its pages. All right.

Fine. Now back to the page, now you'll remember the page has properties, again, there's a property called catalog source page, the Cocoa Key I've decided should be catalog source page, and it's got a file source, and I have decided that the Cocoa Key should be file source, so having made those determinations and having written them down on a piece of paper, I am now ready to write my Cocoa code and here we go.

( Silence )

Now the first thing you'll notice about my code is, what is it? It is a, it is a bunch of categories -- it is a bunch of categories. What I've done is I've made some new files that were not in Aaron's original code. Actually I've made one -- I -- I've only made three new files, oh, let me show you, here they are. This is the SDEF and these are the code files and the one I'm showing you now is scriptability.M and it consists entirely of categories, well almost entirely.

So, for example, he had a document class. I've added a category on his document class, his document class was called "my document" my category is called MN Scriptability, this is the scriptability part of that. So basically I have simply added some functionality to a class that he had already created and the really important part of the functionality that I've added is here.

It's the stuff you're looking at on this page right now, and you'll notice that these one, two, three, four, five methods all have that string, pages array, in them and, in fact, in Tiger at least the way to get this to work properly is simply to implement all five of these, well, there's other ways around that, but I've chosen the simplest path, a kind of mechanical path.

So, if I'm going to have pages in my document and that's called "pages array" that's the Cocoa key, then I implement county of pages array, object in pages -- what is count of pages array do? It -- any time I'm asked how many pages there are I've got to give an answer.

Well, that's easy, there's always going to be eight pages, because you can't create any, you can't destroy any, this is a really simple application. So and then for the last three, the three on the bottom, insert in pages array, insert object in pages array at index and remove object from pages array at index all I do is return an error because hah, hah, those are things you can't do in this application.

You can't add any pages, every document has eight pages. This is really easy. Okay. So the only thing I actually have to do is -- is implement this one method, object in pages array at index, so that if someone asks for Page 3, I've actually got to -- to return what's called a reference to Page 3.

And by reference I mean an object specifier but -- but, basically, so what do I do? Well, the first thing I do is I check to make sure that, you didn't ask for a page whose number is too large like Page 10 or something like that would be simply terrible.

Now you'll notice that what I'm checking is to see whether "I" is larger than 7. Now you'll remember that there are eight pages but, of course, Apple Script arrays are 1 based but Objective-C arrays are zero based so there's an off by one problem which I involve by checking to see if "I" is larger than 7.

So, yes, the end user is allowed to ask for Page 8 but that's translated into 7 that's going to work but, if it's greater than 7, no. So, if that happens I return an error, sorry you asked for a page that doesn't exist. Otherwise I simply make an object that is a stand-in for this page and I return it, end of story.

So now we've got a page, onto the problem of the properties in the page, so I've got another class down here and this class is not a category because in Aaron's -- and actually I think this is the really interesting part of the story -- in Aaron's original implementation he didn't know what he had to do in order to provide for scriptability, so there are no page objects of any kind, there's no class representing a page in his underlying model and I didn't want to write back to him and say, well, you really didn't do it in a way that lends itself to scriptability.

I just wanted to solve the problem, so I created a class that exists only in this -- in this file which is a stand-in for a page and what you see me doing here is implementing the access to the properties. So you will remember -- let's just scroll down here -- you will remember that I have got let's say a file source, so you have to implement two methods corresponding to that.

Remember this is KeyValue Coding, so file source and set file source. Well, I'm afraid I don't actually do anything for file source because this is a very strange property, it's settable but not gettable that's just the weird way in which I did the scriptability here, so fine we'll just accept that just live with it.

So I return an error in that case but, if we set file source, then I turned -- turn around and actually call whatever is was in Aaron's code actually it's this thing that he uses the very same code that he uses when someone drags a file into the document onto a particular page, I simply call that same line of code that he was using and there I've set the file source.

Same kind of thing for the catalog source page, I -- I look in the cat -- someone asks us to set the catalog source page, first I make sure that there's a catalog page that corresponds to the page number that I'm asked to use and, assuming that there is, then I go ahead and I call the very same -- I do the -- these three lines are ripped right out of his code. I simply copy what it is that he does when -- when the user drags from the catalog into a page, I simply copy those lines, stuck 'em right in here, now I'm doing exactly the same thing that he does, that's basically it.

Okay. Let's build it and run it, and let's see whether it works, so you will remember that somewhere here, I've got a script and this script is supposed to tell page packer to set Page 3 to some catalog source page and it also sets Page 4 to something that's on disc. So let's run it and see whether that really happens. Yep, sure does. So I would say that we're in pretty good shape so far.

However, we're not done because we need to test a little more thoroughly than that. You should always test to make sure that your error messages are coming out coherently, so here I've got a whole bunch of things that the user should not be able to do. For example, the user should not be able to make a new page, let's try it.

So I'll run this script, I get a run time error and it is coherent. A nice English straightforward ordinary run time error, nope can't create additional document pages. Good. That's working very nice. Okay. Let's try it again. Another thing the user might say is make new page at end, I'll try that. Nope, can't create additional document pages. Good that's a coherent run time error fine.

Next I will try delete Page 3. Nope. Can't delete document pages. Good. Good answer that's what I want it to say. Now I'll say, tell Page 9 -- there is no Page 9, what will happen? Nope, no such document page. Uh-ho I'm handling all the cases, and finally I'll say get Page 3, Uh-oh I've gotten the dreaded NS Internal Script Error. Here's a case that I forgot to cover.

I've made a mistake, now it happens that in Leopard this kind of thing is going to go away. The Cocoa Scriptability layer is itself going to supply a much better response than NS Internal Script Error but this is written to run on Tiger, so I've got to supply something, how do I do that? And the answer is, I have to implement something that I forgot to implement, namely -- thank you.

I've got to implement this method object specifier, so basically I commented it out by giving it the wrong name object specifier not, but now it is object specifier so implement object specifier that's what's going to be called when somebody says, get page something or get whatever the object is supposed to be. All right. Now let's see if that works. So, again, I'm going to build. I'm going to run. I'm going to go back to my Apple Script script.

Okay. Again I'm going to try to get Page 3, kaboom! I've got a reference to Page 3. Perfect. So that's the kind of thing you have to do, you have to test against -- now the one last thing you should do is look at your dictionary in some kind of nice dictionary display, so let's just take a look at it.

There's a page packer suite, the page packer suite contains the following classes, application document and page. Let's look at what is says about document, looks all right, a document and look at this down here you can actually be right quite informative in your dictionary. This is stuff I wrote in the dictionary, it says page, pages of the document, a document has exactly eight pages. I'm trying to be informative to the user who's going to be using this thing, and finally the all important page. Now here I've really gone to town you can really be informative in the doc -- so catalog source page is property.

I've actually given an entire example in code, so I say this is the page number of the built in catalog that's to be used for this page, for example, you might say and then I've included an actual piece of Apple Script code and I say what it is that -- that happens when you run that Apple Script code.

Same thing for file source, I show that that property exists and I've provided enough documentation there is a whole long thing about it and then at the bottom just to make sure that everybody understands, I repeat the fact that a document has eight pages, pages can neither be created nor deleted.

So I'm using -- I'm using the dictionary as I kind of little mini scripting instruction manual. Its not just a set of terms, SDEFs allows you to do this, you can put in a lot more information, so now my scriptability is done. I have a user friendly dictionary.

I've tested it against the various kinds of errors that the user might make and I'm returning coherent error messages to all of them. I would say this is a pretty good piece of scriptability, so what's the take home message here, take home message here is don't be afraid of the notion of making your application scriptable, on the contrary this is your chance to do yourself and your users a big favor, why is it a big favor for your users? It's a big favor for your users because you put the power in their hands. They can use your application in all kinds of ways in all kinds of workflows that you never imagined. Remember the iTunes example, getting the orphans, there is no GUI for getting the orphans, but I was able to do it anyway thanks to iTunes' scriptability.

Why is it good for you? It's good for you because people are going to regard this as a major feature and second of all you're now working together with your users. Your users are now helping you grow the application. They're going to write back to you and they're going to say, well, I wrote this script that makes your application do this. And you're going wow, that's really cool.

I never thought of making my application do that, you know, you've opened up the possibilities instead of the GUI being some kind of limitation, behind that there's a scripting API and you've put the power in the users hands that's what you want to do because for every user whether it's me or my mother, a computer is to program. She may not know it but that's what it's for.