Vous êtes sur la page 1sur 117

Department of Information Technology

MULTIMEDIA AND APPLICATION DEVELOPMENT LAB Lab Manual for the Academic Year 2007-2008

IV B.Tech

Guru Nanak Engineering College


Ibrahimpatnam, R R District 501 506 (A. P.)

In-charge Prepared by: N. Kutumba Rao M. B. N. Reddy

HOD Approved & Reviewed by: Issued by:

Principal w.e.f Date:

Guru Nanak Engineering College


Ibrahimpatnam, R R District 501 506 (A. P.)

Department of Information Technology Lab Manual for the Academic Year 2007-08 (In accordance with JNTU syllabus)
SUBJECT : MMAD LAB : : : : : CS (05420) IV - I Information Technology D. RAMA RAO 1) 2)
N. KUTUMBA RAO M.B. NEELAKANTESHWARA REDDY

SUBJECT CODE SEMESTER STREAM INSTRUCTOR PROGRAMMERS

Head IT

-2-

Guru Nanak Engineering College


Ibrahimpatnam, R R District 501 506 (A. P.)

Suggestions from Principal :

Enhancement if any :

Comments :

-3-

INDEX S.No 1 2 3 4 Name of the Content Lab Objective Introduction About Lab LAB CODE List of Lab Exercises 4.1 Syllabus Programs (JNTU) Description about MMAD Concepts Programs List References 9 10 166 PAGE NO. 4 5 7 8

5 6 7

-4-

Lab Objective:
Multimedia is simply multiple forms of media integrated together. Media can be text, graphics, audio, animation, video, data, etc. An example of multimedia is a web page on the topic of Mozart that has text regarding the composer along with an audio file of some of his music and can even include a video of his music being played in a hall. Besides multiple types of media being integrated with one another, multimedia can also stand for interactive types of media such as video games CD ROMs that teach a foreign language, or an information Kiosk at a subway terminal. Other terms that are sometimes used for multimedia include hypermedia and rich media. The term Multimedia is said to date back to 1965 and was used to describe a show by the Exploding Plastic Inevitable. The show included a performance that integrated music, cinema, special lighting and human performance. Today, the word multimedia is used quite frequently, from DVD's to CD ROMs to even a magazine that includes text and pictures.

-5-

INTRODUCTION ABOUT LAB There are 66 systems ( Compaq Presario ) installed in this Lab. Their configurations are as follows : Processor RAM Hard Disk Mouse Network Interface card Software 1 All systems are configured in DUAL BOOT mode i.e, Students can boot from Windows XP or Linux as per their lab requirement. This is very useful for students because they are familiar with different Operating Systems so that they can execute their programs in different programming environments. 2 Each student has a separate login for database access Oracle 9i client version is installed in all systems. On the server, account for each student has been created. This is very useful because students can save their work ( scenarios, pl/sql programs, data related projects ,etc) in their own accounts. Each student work is safe and secure from other students.
3

: : : : :

AMD Athelon 1.67 GHz 40 GB Optical Mouse Present

256 MB

Latest Technologies like DOT NET and J2EE are installed in some systems. Before submitting their final project, they can start doing mini project from 2nd year onwards.

4 MASM ( Macro Assembler ) is installed in all the


-6-

systems

Students can execute their assembly language programs using MASM. MASM is very useful students because when they execute their programs they can see contents of Processor Registers and how each instruction is being executed in the CPU. 1 Rational Rose Software is installed in some systems Using this software, students can depict UML diagrams of their projects. 2 Software installed : C, C++, JDK1.5, MASM, OFFICE-XP, J2EE and DOT NET, Rational Rose. 3 Systems are provided for students in the 1:1 ratio. 4 Systems are assigned numbers and same system is allotted for students when they do the lab.

-7-

LAB CODE: 1. Students should report to the concerned labs as per time table schedule. 2. Students who turn up late to the labs will in no case be permited to do the program scheduled for the day. 3. After completion of the program , certification of the concerned staff in-charge in the observation book is necessary. 4. Students should bring a notebook of about 100 pages and should enter the reading/observations into the notebook while performing the experiment. 5. The record of observations along with the detailed experimental procedure of the experiment performed in the immediate last session should be submitted and certified by the staff ember in-charge.

6. Not more than three students in a group are permitted to perform the
experiment on a setup.

7. The group-wise division made in the beginning should be adhered to


and no mix up student among different groups will be permitted later.

8. The components required pertaining

to the experiment should be

collected from stores in-charge after duly filling in the requisition form.

9. When the experiment is completed, students should disconnect the


setup 10. made by them, and should return all the components/instruments taken for the purpose. Any damage of the equipment or burn-out of components will be viewed seriously either by putting penalty or by dismissing the total group of students from the lab for the semester/year. 11. 12. Students should be present in the labs for the total scheduled duration. Students are required to prepare thoroughly to perform the experiment before coming to Laboratory.

13. Procedure sheets/data sheets provided to the students groups should


be maintained neatly and to be returned after the experiment.

-8-

Lab Programs Multimedia And Application Development Lab Programs List


Submission 1 Week 1 Week 2 Week 3 Week 4 Submission 2 Week 5 Week 6 Week 7 Submission 3 Week 8 Week 9 Week 10 Submission-4 Week - 11 Week - 12 Week - 13 Week 14 Week 15 17. Formating Currency Amount. 18. 19. 20. 21. Converting Between Units of Measurement. Determining points Along a Circle. Sorting or Reversing an Array. Implementing a Custom sort. 14. Scripting Masks. 15. Converting Angle Measurements. 16. Calculating the Distance Between the Two Points. 9. 10. 11. 12. Tinting a Movie Clips Color. Controlling a Movie Clips Color with Sliders. Drawing a Circle. Drawing a Rectangle. 1. Assigning Actions to an Object, and a Button. 2. Creating Loops. 3. Generating Ramdom Numbers 4. Craeting a Function, Calling a Function. 5. Detecting the Player Version. 6. Detecting the Operating System. 7. Checking the System Language. 8. Detecting Display Settings

13. Filling a Shape with a Gradient.

22. Creating a Text Field. 23. Making a Password Inputfield.

-9-

Description about MMAD Concepts:


Multimedia has become a huge force in American culture, industry and education. Practically any type of information we receive can be categorized as multimedia, from television, to magazines, to web pages, to movies, multimedia is a tremendous force in both informing the American public and entertaining us. Advertising is perhaps one of the biggest industry's that use multimedia to send their message to the masses. Where one type of media, let's say radio or text can be a great way to promote an item, using multimedia techniques can significantly make an item being advertised better received by the masses and in many cases with greater results. Multimedia in Education has been extremely effective in teaching individuals a wide range of subjects. The human brain learns using many senses such as sight and hearing. While a lecture can be extremely informative, a lecture that integrates pictures or video images can help an individual learn and retain information much more effectively. Using interactive CD ROM's can be extremely effective in teaching students a wide variety of disciplines, most notably foreign language and music. As technology progresses, so will multimedia. Today, there are plenty of new media technologies being used to create the complete multimedia experience. For instance, virtual reality integrates the sense of touch with video and audio media to immerse an individual into a virtual world. Other media technologies being developed include the sense of smell that can be transmitted via the Internet from one individual to another. Today's video games include bio feedback. In this instance, a shock or vibration is given to

- 10 -

the game player when he or she crashes or gets killed in the game. In addition as computers increase their power new ways of integrating media will make the multimedia experience extremely intricate and exciting.

AIM
Assigning Actions to an Object, and a Button.

PROGRAM
Action buttons are built-in button shapes that you can add to your presentation and then assign an action to occur upon the click of a mouse or when someone mousesover the button. You can also assign actions to clip art, pictures, or the text in a Smart Art graphic. The idea is that when you deliver your presentation, you can click or mouse-over an action button to:

Go to the next slide, the previous slide, the first slide, the last slide,

the most recent slide viewed, a specific slide number that you specify a different Microsoft Office PowerPoint presentation, or a Web page.

Run a program. Run a macro . Play a sound.

Some examples of built-in action button shapes that you can find in the Shapes gallery include right and left arrows and commonly understood symbols for going to next, previous, first, and last slides and for playing movies or sounds, and more. 1). On the Insert tab, in the Illustrations group, click Shapes, and then under Action Buttons, click the button that you want to add. 2). Click a location on the slide, and then drag to draw the shape for the button.

- 11 -

3). In the Action Settings dialog box, do one of the following: i). To choose the behavior of the action button when you click it in Slide Show view, click the Mouse Click tab. ii). To choose the behavior of the action button when you move the pointer over it in Slide Show view, click the Mouse Over tab. 4). To choose the action that will take place when you click or move the pointer over the action button, do one of the following: i). To use the shape without a corresponding action, click None. ii). To create a hyperlink, click Hyperlink to, and then select the destination (for example, the next slide, the previous slide, the last slide, or another PowerPoint presentation) that you want the hyperlink action to go to. To link to a file created by another program, such as a Microsoft Office Word or Microsoft Office Excel file, in the Hyperlink to list, click Other File. iii).To run a program, click Run program, click Browse, and then locate the program that you want to run. iv). To run a macro (macro: An action or a set of actions that you can use to automate tasks. Macros are recorded in the Visual Basic for Applications programming language.), click Run macro, and then select the macro that you want to run. v). The Run macro settings are available only if your presentation contains a macro. vi). When you save the presentation, you must save it as a PowerPoint Macro-enabled Show.

- 12 -

vii). For more information about macros, see Run a macro. viii). If you want the shape that you chose as an action button to perform an action, click Object action, and then select the action that you want it to perform. NOTE The Object action settings are available only if your

presentation contains an OLE (OLE: A program-integration technology that you can use to share information between programs. All Office programs support OLE, so you can share information through linked and embedded objects.) object. For more information about OLE objects see Create, change, or delete an OLE object ix). To play a sound, select the Play sound check box, and then select the sound that you want to play. 5). 1). Click OK. On the Insert tab, in the Illustrations group, do one of the

following: i). Click Picture, and then in the Insert Picture dialog box, locate the picture that you want to add, and then click Insert. ii). Click Clip Art, and then in the Clip Art pane, locate and then

click the picture that you want to add. NOTE You can assign an action to the text inside the shapes of a

SmartArt graphic, but not to the SmartArt shapes themselves. For more information about inserting SmartArt graphics, see Create a SmartArt graphic. 1). Click the picture or clip art that you added, and then on the Insert tab, in the Links group, click Action. 1). In the Action Settings dialog box, do one of the following: i). To choose the behavior of the picture or clip art when you click it in Slide Show view, click the Mouse Click tab.

- 13 -

ii). To choose the behavior of the picture or clip art when you move the pointer over it in Slide Show view, click the Mouse Over tab. 1). To choose the action that will take place when you click or move the pointer over the picture or clip art, do one of the following: i). To use the shape without a corresponding action, click None.

ii). To create a hyperlink, click Hyperlink to, and then select the destination (for example, the next slide, the previous slide, the last slide, or another PowerPoint presentation) that you want the hyperlink action to go to. NOTE To link to a file created by another program, such as a

Microsoft Office Word or Microsoft Office Excel file, in the Hyperlink to list, click Other File. iii). To run a program, click Run program, click Browse, and then locate the program that you want to run. iv). To run a macro (macro: An action or a set of actions that you can use to automate tasks. Macros are recorded in the Visual Basic for Applications programming language.), click Run macro, and then select the macro that you want to run. NOTES v). The Run macro settings are available only if your presentation contains a macro. vi). When you save the presentation, you must save it as a PowerPoint Macro-enabled Show. viii). For more information about macros, see Run a macro. ix). If you want the picture or clip art to perform an action other than what is listed, click Object action, and then select the action that you want it to perform.

- 14 -

NOTE

The Object action settings are available only if your

presentation contains an OLE (OLE: A program-integration technology that you can use to share information between programs. All Office programs support OLE, so you can share information through linked and embedded objects.) object. For more information about OLE objects see Create, change, or delete an OLE object x). To play a sound, select the Play sound check box, and then select the sound that you want to play.

AIM
Creating Loops.

PROGRAM
Audio that loops seamlessly creates a perfect soundtrack for many Flash animations and video spots. 1. In the Tasks panel, click Create Loop. In the transport controls, Soundbooth automatically enables the Loop Playback option .

2. Press the spacebar to start playback. 3. In the Editor panel, select a time range for the loop. 4. In the Tasks panel, fine-tune the loops in point, out point, and duration. 5. Select from the following options: Lock Duration Restricts the loop to the currently specified duration. If you need a loop of precise length, select this option, and adjust the in point and out point as needed.

- 15 -

Auto-Smooth Loop Point Cross-fades audio from the out point to the in point, creating a smoother transition. Play Entire Loop/Play Transition Only Previews either the entire loop or only the transition from out point to in point. 6. Click Save Loop As to save the loop to a new file. Select time ranges

1. In the toolbar, select the Time Selection tool


2. In the Editor panel, drag to select a range. 3. (Optional) Do any of the following:

i). To extend or shorten a selection, Shift-click the end of the selection that you want to modify, and drag to extend or shorten it. Or, drag the left or right edge of the selection in the timeline ruler. ii). To move the selection without changing its length, drag the middle of the selection in the timeline ruler.

Save entire files or selected ranges Use the File > Save command to either save newly created files or quickly resave existing files and retain their settings. Use the File > Save As

- 16 -

commands to save selections or change settings such as file format, sample rate, and bit depth. 1. Choose one of the following: i). File > Save. (If youre resaving, you can skip all steps below.) ii). File > Save As. iii). File > Save Selection As.
11 Specify a file location, name, and format. Then click Save. 11 Set format-specific options. For more information, see one of the

following:

mp3 options. AIF, AVI, MOV, and WAV options. Options for additional video formats.

Click OK.

AIM
Generating Ramdom Numbers

PROGRAM
Generating Random Numbers When you need to incorporate random elements into your Flash movie, either for a design effect or for game play, you can use the Math class's Math.random() method. The Math.random() method generates random numbers between 0 and 1 (including 0 but not including 1) with up to 15 decimal places in between. Typical return values are 0.242343544598273 0.043628738493829 0.7567833408654 The Math object in ActionScript contains a number of methods that perform mathematical operations. Among these is random(), which generates an apparently random number between 0 and 1. To generate a random-number value and assign it to a variable, use a statement like this: someVariable = Math.random();

- 17 -

Note that the "M" in Math must always be capitalized. The names of predefined objects are always given this way. Technically speaking the output of Math.random() is random, because the technique used to generate its values detectable pattern if it is repeated enough times. But unless patience to scrutinize hundreds of thousands of repetitions, won't notice. only pseudowill display a you have the you probably

Below are five movies showing Math.random() in action. In each movie a script displays randomly generated numbers or words. The script is installed within a Movie Clip called scripts, which appears in the upper right corner of the movie window. This element may look like a button but it's just a convenient place to park the scripts. In a real project we'd probably make this Movie Clip invisible. Some scripters prefer to place general scripts in the first frame of a layer devoted exclusively to scripting. This is an even simpler solution. Also on the right side you'll find a button marked Repeat. This button invokes a function defined within the Scripts Movie Clip. This allows you to re-run the demonstration function as many times as you like. The first demonstration movie Math.random() invoked four times. below shows the results of

By themselves, long decimal numbers between 0 and 1 are not much help in controlling Flash movies. To select from among a range of elements, you'll probably want to match the output of Math.random() against a series of tests, as in this example: The first demonstration movie Math.random() invoked four times. below shows the results of

By themselves, long decimal numbers between 0 and 1 are not much help in controlling Flash movies. To select from among a range of elements, you'll probably want to match the output of Math.random() against a series of tests, as in this example: if(randyItem if(randyItem if(randyItem if(randyItem if(randyItem == == == == == 0) 1) 2) 3) 4) loadMovie("firstCourse.swf",0); loadMovie("secondCourse.swf",0); loadMovie("thirdCourse.swf", 0); loadMovie("fourthCourse.swf", 0); loadMovie("fifthCourse.swf", 0);

These five lines allow you to choose a new movie at random and load it over the present movie.

- 18 -

As you can see, the if tests here assume we're dealing with integers. Two steps are required to get from the raw output of Math.random() to useful integer values. First, multiply the output of Math.random() by the number of items from which you wish to choose. In the example above we'd multiple by 5: someVariable = Math.random()*5; Here's what this change does to our initial example: As you can see, when you multiply an integer like 5 by a messy decimal number like 0.427009978920274, the result is itself a messy decimal (2.13504989460137, to be exact). We need a simple integer. To clean up the results we apply another method of the Math object called floor(). This method rounds the decimal down to the nearest integer. In the case above, it yields 2. The statement looks like this: someVariable = Math.floor(Math.random()*5); Be careful with those embedded parentheses; you have to get them just right. Here are four more iterations of Math.random(), this time multiplied by 5 and rounded down with Math.floor(): If you study the output above, you'll see that the random values may include 0 but never include 5. That's because we're always rounding down. If we wanted to include 5 and exclude 0, we'd use the Math.ceil() function instead of Math.floor(). Which function you choose depends on what you want to do with the random value. In many cases you may want to do something slightly different from the example discussed earlier (a series of if tests). You may want to extract a randomly-chosen value from a specially constructed object called an Array. At heart, Arrays are simply ordered lists, though their numbering systems differ from everyday practice in one respect: they always start at 0. Arrays are numbered from 0 to one less than their total length--from 0 to 14 for a fifteen-element array. Thus the numbers generated by a random function rounded down with Math.floor() will always correspond to indices of the array. If we write an array containing fifteen words, we can now use Math.floor(Math.random()*15)) to generate a random word list: Constraining Random Values

- 19 -

If you re-run the example above a few times, you'll notice that it often contains duplicate items, and that these duplicates may occur one after another. This happens because we're choosing from a relatively small range of options, and because nothing prevents the script from generating the same random integer twice in succession. (Technically speaking, the problem lies with the Math.floor() operation, which takes nearly unique decimals and rounds down to a much smaller range of integers.) You can minimize repetition by keeping track of the random function's past performance and screening out previously-used values. Here's an example of random selection constrained to produce five unique selections from a list of fifteen words: To explain this technique as clearly as possible, we'll first discuss a simpler form of constraint than what you see above--constraint against only a single repetition. Then we'll show how to scale the procedure up. Here's how to achieve a simple, first-order constraint. First, we initialize a pair of variables to the same value: var randy = 0; var randyOld = 0; In ActionScript as in JavaScript, it's possible to place certain statements inside control structures such as loops and functions so that they can be repeated on command. The statements above must be placed outside any such structures and be executed only once, when the movie loads. In the example above they are placed within an onClipEvent(load) handler attached to the Scripts Movie Clip. You'll see why this placement is important in just a moment. The first variable, randy, holds the current random value. The other variable, randyOld, is used to store the random value generated on the previous run of the function. Needless to say, when the movie is loaded there has been no previous run, so we have to supply initial values. It's essential that both variables be assigned the same value. Again, you'll see why in just a bit. Next we make a change to the statement that generates the random number randy. In the unconstrained version of the function, that statement is: randy = Math.floor(Math.random()*contentArray.length); In the constrained case, however, we place this statement within a special construction called a while loop: while(randy == randyOld)

- 20 -

{ }

randy = Math.floor(Math.random()*contentArray.length);

A while loop executes so long as its conditional clause evaluates to true. In this case, so long as the random number we generate is the same as the random number we previously generated, we generate a new random number. In other words we keep trying numbers until we hit one that is not the same as the one that came up previously. This is why both randy and randyOld must have the same value on the first run of the function: we only get a random value if the two variables are identical. One more refinement makes the constraint complete. Outside the while loop we add this statement: randyOld = randy; This statement records the current random number and stores it in the variable that will be used for comparison on the next run of the function. This line lets the function remember its previous behavior each time through. Extensions of Constraint Using the logic explained above, you may constrain a random number generator against several orders of repetition, so that it is guaranteed to produce non-repeating values for three, four, five, or more successive iterations. The crudest way to do this is simply to create more storage variables (randyOlder and randyOldest, for instance), write a compound test condition for the while loop, and push every new random value back through the record variables as we go. If you look at the scripts attached to the Scripts Movie Clip in the demonstration movie above, you'll find five constraint variables. That's not a very elegant solution, but you may find it easier to take in at a glance than some of the alternatives. After the fifth level of constraint, brute-force methods may become too cumbersome for most people's tastes. It's awkward to write a test condition with six or seven parallel cases. At this point you might want to use an array instead of separate variables to store the record values. This means writing code to scan that array. Alternatively you could write previous random values to a string, moving each value one place back as it ages out; but again, you'd have to write code to look for values in that string.

- 21 -

Practically speaking, if the range of content choices is large enough, there may be no reason to constrain the randomizer against more than two or three repetitions. Better Solutions The method we've just discussed has important flaws--executed on a very slow system it can behave sluggishly if the system randomly selects the same number many times in a row. Real programmers have better ways of constraining random number generation; unfortunately, these methods are hard to explain to people (like me) who are mathematically challenged. The scheme described above should work fine for Flash movies for two reasons: first, Flash is very well integrated with PC operating systems so it makes excellent use of processing resources; second, most PCs today have plenty of computing power to spare for tasks like multimedia. So unless you have a deep dislike for sloppy solutions, you may use this method with random abandon. The Deprecated random() Function If you used ActionScript in its earlier iterations (Flash 3) you may have encountered a simpler random() function. Given an argument N, this function would return an integer between 0 and N-1, inclusive. It wasn't necessary to use Math.floor() or Math.ceil(). Macromedia has officially deprecated the old random function, partly (we guess) because it is not consistent with the way people learn to code in Java and JavaScript, and partly because floor and ceiling functions allow greater control. Though it's simpler to write, do not include the old random function in your code. You should never use deprecated commands when you can avoid them. Though Macromedia is very generous about legacy code, once an instruction is deprecated it need no longer be supported. Some future version of Flash will refuse to recognize the old random function. Source Files The five demonstration movies that appear on this page are called random1.fla, random2.fla, random3.fla, random4.fla, and random5.fla. They're available on Crow within MMShare/randoms. In each movie the scripts are attached to the Scripts Movie Clip.

- 22 -

AIM
Craeting a Function, Calling a Function.

PROGRAM
The following is a step-by-step description of the process that happens when you create an event listener. In this case, it's an example of creating a listener function that is called when an object named myButton is clicked. The actual code written by the programmer is as follows:

- 23 -

function eventResponse(event:MouseEvent):void { // Actions performed in response to the event go here. } myButton.addEventListener(MouseEvent.CLICK, eventResponse); Here is how this code would actually work when it's running in Flash Player: When the SWF file loads, Flash Player makes note of the fact that there's a function named eventResponse().

1.

Flash Player then runs the code (specifically, the lines of code that aren't in a function). In this case that's only one line of code: calling the addEventListener() method on the event source object (named myButton) and passing the eventResponse function as a parameter.

2.

- 24 -

a. Internally, myButton has a list of functions that are listening to


each of its events, so when its addEventListener() method is called, myButton stores the eventResponse() function in its list of event listeners.

At some point, the user clicks the myButton object, triggering its click event (identified as MouseEvent.CLICK in the code).

3.

At that point, the following occurs:

a. Flash Player creates an object, an instance of the class

associated with the event in question (MouseEvent in this example). For many events this will be an instance of the Event class; for mouse events it will be a MouseEvent instance; and for other events it will be an instance of the class that's associated with that event. This object that's created is known as the event object, and it contains specific information about the event that happened: what type of event it is, where it happened, and other event-specific information if applicable.

- 25 -

b. Flash Player then looks at the list of event listeners stored by

myButton. It goes through these functions one by one, calling each function and passing the event object to the function as a parameter. Since the eventResponse() function is one of myButton's listeners, as part of this process Flash Player calls the eventResponse() function.

c. When the eventResponse() function is called, the code in that


function runs, so your specified actions are carried out.

- 26 -

Related Topics

Popup

Popup

- 27 -

Flash CS3

AIM
Detecting the Player Version.

PROGRAM Detecting the Flash Player


What good is an awesome Flash experience if no one can see your Flash movies? Because most Flash content is viewed with a Web browser, it's extremely important to make sure that your HTML pages check for the existence of the Flash Player plug-in before you start pushing Flash content to the browser. There are a variety of ways to check for the Flash Player, and this section provides an overview of the available methods. New Feature As we mentioned in the previous chapter, Flash 8 includes an updated Flash Player detection feature within the Publish Settings. You learn how to create a set of detection pages with this new feature later in this chapter.

Plug-In versus ActiveX: Forcing Content without a Check


The Flash Player is available for Web browsers in two forms: the Flash Player plug-in (as a Netscape-compatible, or Mozilla-compatible, plug-in) and the Flash Player ActiveX control (for use only with Microsoft Internet Explorer on Windows 98/ME/2000/XP). If you directly insert a Flash movie into a Web page with the <embed> tag (for Netscape browsers), one of two scenarios will happen:

The browser has the Flash Player plug-in and will load the Flash movie. The browser does not have the Flash Player plug-in and displays a broken plug-in icon.

If the second scenario occurs and the pluginspage attribute of the <embed> tag is defined, the user can click the broken plug-in icon and go to the Macromedia site to download the Flash Player plug-in. If the pluginspage attribute is not specified, clicking the broken plug-in icon will take you to a generic Netscape plug-in page.

- 28 -

If you insert a Flash movie into an HTML document with the <object> tag (for Internet Explorer on Windows only), one of two scenarios will happen:

The browser has the Flash Player ActiveX control and will load the Flash movie. The browser does not have the Flash Player ActiveX control and will autodownload and install the ActiveX control file from the Macromedia site.

Note Newer versions of Windows XP (that is, with Service Pack 2 or SP2 installed) will likely get an additional warning represented as a strip across the top of the Web page attempting to initiate the installation of a new ActiveX control. The user must also click this strip and accept the download of the ActiveX control. The ActiveX control will autodownload and install only if the classid and codebase attributes of the Flash movie's <object> tag are correctly specified. Depending on the user's security settings, the user needs to grant permission to a Security Warning dialog box to commence the download and install process. Although using the <object> and <embed> tags by themselves is by far the simplest method for integrating Flash content into a Web page, it's not the most user-friendly method of ensuring that the majority of your Web visitors can view the Flash content. Flash 8 uses a new JavaScript detection mechanism, updating the Flash sniffer approach used in Flash MX 2004. Note Since Flash Player 4 was released, many seasoned Flash developers have used small Flash movies known as sniffers to detect the presence of the Flash Player in a user's Web browser. Sniffers are virtually hidden from the visitor to a Web site, and they direct an entry HTML page to a new location (using a getURL() action) where the real Flash content (or site) exists. If the Player is not installed, the sniffer movie won't be able to play and direct the HTML page to a new location. If this happens, a special <meta> tag in the <head> of the HTML document directs the browser location to a screen that informs the visitor to down load the plug-in or ActiveX control.

Detecting the Flash Player with Flash 8


In Flash 8, Macromedia has made the process of using a sniffer methodology incredibly simple. In the following steps, you learn how to use the new Detect Flash Version feature to properly direct a user to Flash Player 6 r65 content. Note You can check for Flash Player 4 or higher with the Detect Flash Version feature. For demonstration purposes, we chose Flash Player 6 r65 because Flash MX 2004 introduced a new optimization feature for .swf files generated for this version (or higher) of Flash Player 6.

- 29 -

Caution If you use the Detect Flash Version in Flash MX 2004, be sure to review this section. The feature no longer uses three HTML pages for the detection process. Everything from the detection to the content display to the alternate content display occurs on one HTML page. 1. Create a new Flash document by choosing File New. In the New Document dialog box, choose Flash Document and click OK. Alternatively, open an existing .fla file that you have created and skip to Step 4. 2. Save the new Flash document as detection_test.fla. 3. Add some placeholder text to the stage using the Text tool. As this example is checking for Flash Player 6 r65, you can type This is Flash Player 6 r65 content. 4. Choose File Publish Settings. By default, both the Flash and HTML formats are selected in the Formats tab of the Publish Settings dialog box. The filenames for these formats should reflect the current .fla filename, such as detection_test.swf and detection_test.html, respectively. 5. To keep the new version settings in a separate profile, click the Create New Profile (+) button at the top of the Publish Settings dialog box. Name the profile FP6 r65 Detection, as shown in Figure 22-3. Click OK to close the dialog box, but leave the Publish Settings dialog box open. 6. Click the Flash tab. In the Version menu, choose Flash Player 6. In the ActionScript version menu, choose ActionScript 1.0. Select the Optimize for Flash Player 6 r65 check box. Refer to Figure 22-4 for a review of these settings. 7. Click the HTML tab of the Publish Settings dialog box. Select the Detect Flash Version check box. The two editable text fields to the right of the Version label should now be enabled. The major version of the Flash Player is fixed to the Player version you chose in the Flash tab. The first of the two editable fields represents a Minor Revision value; to date, Macromedia hasn't released any minor revisions of the Flash Player, but this feature is enabled just in case Macromedia does release any minor revision during the life cycle of the Flash 8 authoring tool. The second field represents the Incremental Revision value. Since Flash Player 4, Macromedia has released several incremental revisions of the Flash Player for each player cycle. Web To get a sense of how many incremental revisions of Flash Resource Player 7 were released, see the "Flash Player Release Notes" category at www.flashsupport.com/links. Caution In Flash MX 2004, Macromedia referred to these two editable values as Major Revision and Minor Revision. With a little revisionist history in Flash 8, Macromedia now refers to Major Revision as Minor Revision and Minor Revision as Incremental Revision. 9. Type 65 in the second field, as shown in Figure 22-5. If you wanted to check for a different incremental version of Flash Player 6, you could enter

- 30 -

that value instead. Click OK to close the dialog box, and go back to the HTML tab of the Publish Settings dialog box. 10. In the Publish Settings dialog box, click the Publish button. You may see an alert box, as shown in Figure 22-6, letting you know that the Flash movie file (.swf) you are about to publish is only compatible with Flash Player 6 r65 or higher. Click OK in this alert box. Flash 8 generates all of the necessary JavaScript within the published HTML document to properly detect the Flash Player version. Click OK to close the Publish Settings dialog box. 11. On your desktop, navigate to the folder where you saved your original .fla file. If you created the sample document in Step 1, you want to find the location of detection_test.fla. In this location, you will see the HTML file used for the detection process, the Flash content, and the alternate content. 12. In your own Web browser, load the detection_test.html page. If your browser has Flash Player 6 r65 or higher, the browser should display your detection_test.swf movie. This process works because the detection_test.html page uses JavaScript (or VBScript on Internet Explorer for Windows) to check the installed Flash Player version, if one exists. If you open the HTML document in a text editor such as Macromedia Dreamweaver, you'll see that lines 1015 declare the version numbers you entered in the HTML tab of the Publish Settings. The JavaScript code compares these values to the version of the Flash Player that loaded the movie. If the Flash Player matches (or exceeds) the version requirements, the Flash content tags (<object> and <embed>) are written to the HTML page with JavaScript. Otherwise, the alternate content specified on line 147 in the JavaScript code is loaded into the browser window. Note Macromedia provides generic alternate content that you should replace with your own preferred HTML tags indicating what you want to the user to do if the version of the Flash Player required is not installed. 13. To accurately test your pages over an Internet connection, upload all of the files (except the .fla file) to your Web server and load the detection_test.html document from the Web server URL to redo the test.

Figure 22-3: The Create New Profile dialog box, showing the new profile name

- 31 -

Figure 22-4: The Flash Player 6 r65 settings in the Flash tab

Figure 22-5: The Publish Settings dialog box

Figure 22-6: The Optimize for Flash Player 6 r65 alert box On the CDYou can find all of these files created for this detection example ROM in the ch22/flash8_detection folder of this book's CD-ROM. The JavaScript in the detection_test_f8b.html version of the document contains additional alternate content that is specified in an - 32 -

alternate.js file, also included on the CD-ROM. If you'd like to find the latest "Get Flash Player" graphics to use in your Web pages, go to www.macromedia.com/macromedia/style_guide/buttons. If you want to test the detection mechanism with an older version of the Flash Player, we recommend that you use an older Flash Player installer with Netscape or a Mozilla-compatible browser. The process of uninstalling an ActiveX control used by Internet Explorer is much more difficult to do. Web You can find just about every past version of the Flash Player at Resource www.macromedia.com/cfusion/knowledgebase/index.cfm? id=tn_14266 for testing purposes. As mentioned previously, we recommend that you install the older versions with a Netscape or Mozilla-compatible browser. If you are using Mac OS X, the first Flash Player released for Mac OS X was version 5. You can set up your Netscape or Mozilla-compatible browser's plug-ins folder to accommodate multiple versions of the Flash Player plug-in. When you installed Flash 8, the first release of Flash Player 8 should have automatically been installed to your Netscape (or Mozilla) browser's Plugins (or plugins) folder. The plug-in file, named NPSWF32.dll, can be moved outside of the Plugins folder, into a new parent folder that you create. For the following example, we'll use Mozilla FireFox as our test browser. Web Resource Mozilla FireFox is a free Web browser that you can download at www.mozilla.org/products/firefox/. FireFox has quickly become the preferred cross-platform browser of many Web developers.

We prefer to create a _Flash Players folder in the C:\ProgramFiles\MozillaFireFox folder, and put each Flash Player version plug-in file into its own folder, as shown in Figure 22-7.

- 33 -

Figure 22-7: A sample Flash Players folder structure for use with Mozilla FireFox on Windows Caution Regardless of the Flash Player version you install, all Flash Player plugin files for Netscape or Mozilla-compatible browsers have the same name on Windows: NPSWF32.dll. For this reason, you must isolate multiple installations of the Flash Player into their own folder. You can do the same procedure on Mac OS X, where all browsers share the same plug-in folders. That's right! Mozilla, FireFox, Internet Explorer, and Apple Safari all refer to the same plug-ins folder. On your boot disk, such as Macintosh HD, browse to the Library\Internet Plug-Ins\ folder. In this location, you will find the Shockwave Flash NP-PPC plug-in file. As Figure 22-8 shows, you can create a Library\Internet Plug-Ins (DISABLED) folder to store other versions of this plugin file.

- 34 -

Figure 22-8: A sample Flash Players folder structure for use with Mozilla FireFox or Apple Safari on Mac OS X Caution On Mac OS X, you may need to re-create the same plug-in structure with the Users\[Your User Name]\Library\Internet Plug-Ins\ folder. Or, you may just want to remove any Flash Player plug-in files within this folder. Mac OS X should then default to the main Library\Internet PlugIns\ folder. This process takes some time, as you have to download and run each installer from the URL we mentioned in the earlier Web Resource note, and move the NPSWF32.dll file from the Plugins folder to its own folder in the Flash Players folder. When you're done, however, you'll have an efficient system for checking your content against older versions of the Flash Player. Simply move the current NPSWF32.dll file into its appropriate _Flash Players folder, and move the desired test version from its Flash Players folder into the Plugins folder.

Building Your Own Flash Sniffer Movie


While the Macromedia Flash 8 detection features work wonderfully, you may want to know how to build your own custom Flash detection sniffer. In this section, you learn how to build a Flash movie that uses client-side ActionScript to direct the browser window to the appropriate content. This sniffer directs each version of the Flash Player to its own unique HTML page. Meaning, Flash Player 3 (or earlier) is directed to a flash3.html page, Flash Player 4 is directed to a flash4.html page, Flash Player 5 jumps to a flash5.html page, and so on.

- 35 -

Making the Sniffer Movie


The sniffer movie is a small Flash movie that has the same background color as the HTML document. You do not need any artwork or symbols in this movie. 1. Open Flash 8, and in a new Flash document file (.fla), rename Layer 1 to actions. 2. Add a keyframe on frame 2 of the actions layer. With this keyframe selected, open the Actions panel (F9 or Option+F9 on Mac). 3. In the Actions panel, add some ActionScript that checks for Flash Player 3 (or earlier). If Flash Player 3 is detected, then the movie will stop here and launch a URL for Flash 3 movies. If a later version of the player is detected, a separate keyframe labeled checkPlayer is called. You can direct each version of the Player to a unique URL. The basic principle of this ActionScript is to use Flash version-specific actions to determine which Player is displaying the movie. Refer to Listing 22-1. Listing 22-1: The Detection Script on Frame 2 of the actions Layer
// // // // create a Flash variable, whose value is equal to the $version environment variable in Flash Player 4, 5, or 6. This action line will not be read by Flash Player 3(or earlier).

player = eval("$version"); // // // // // // // // // // // // // // // // // // // // The $version value will be in the format: abc 1,2,3,4 where abc is the operating system (e.g. WIN, MAC) and 1 and 2 are the major version designations (e.g. 4.0, 5.0, etc.) and 3 and 4 are the minor and sub-minor version designations (e.g. r20, r27, etc.) By default, Flash MX 2004 ships with a Player version equal to WIN 7,0,0,0 or MAC 7,0,0,0. However, the Flash Player is available on other platforms like UNIX and POCKETPC as well. We just need the major version designation at placeholder 1. Using a while loop and substring(), we can extract this number, searching for the space (" ") between the platform text and the version numbers. The major version starts just after the space (" "). The Flash Player 3 will disregard this section of code.

playerLength = length(player); i=1; while (i<=playerLength) {

- 36 -

currentChar = substring(player, i, 1); if (currentChar eq " ") { platform = substring(player, 1, i-1); majorVersion = substring(player, i+1, 1); break; } i = i+1; } // This code will check the value of majorVersion. // Flash Player 3 will not be able to execute the // call() action, but Flash Player 4 or higher will. if (majorVersion == " ") { // Flash Player 3 will execute this code // automatically, because it will not interpret // the if action. getURL("flash3.html"); } else { call("checkPlayer"); } // We will prevent the movie from accidentally looping. stop ();

4. Now you need to create a keyframe with actions that will be executed by Flash Player 4, 5, or 6. Add a keyframe on frame 5, and in the Property inspector assign a label of checkPlayer in the <Frame Label> field. Press the F5 key on frame 20 to add more empty frames to the layer so that you can read the frame label. 5. Select frame 5, and open the Actions panel (F9, or Option+F9). Type the following code into the Script pane. The code in Listing 22-2 checks to see if the Flash Player is version 4, 5, or 6 (or higher). Listing 22-2: The Script on the checkPlayer Frame of the actions Layer
// majorVersion will be equal to either 4, 5, 6, 7, or 8 in // Flash Player 4, 5, 6, 7, or 8 (or higher) respectively. if (Number(majorVersion) == 4) { // Flash Player 4 will execute this code. getURL("flash4.html"); } else if (Number(majorVersion) == 5) { // Flash Player 5 will execute this code. getURL("flash5.html"); } else if (Number(majorVersion) == 6) { // Flash Player 6 will execute this code. getURL("flash6.html"); } else if (Number(majorVersion) == 7) { // Flash Player 7 or higher will execute this code.

- 37 -

getURL("flash7.html"); } else if (Number(majorVersion) >= 8) { // Flash Player 8 or higher will execute this code. getURL("flash8.html"); }

6. Change the size of the movie frame to 18 px 18 px, in the Document Properties dialog box (Modify Document). Change the background color of the movie to match the background color of the HTML document. Click OK. New In Flash 8, you can now specify movie dimensions as small Feature as 1 px 1 px. While 18 px 18 px is small enough to remain unnoticeable on a Web page, you can opt to make your Flash movie even smaller. 7. Save the Flash movie as sniffer.fla. 8. Open the Publish Settings dialog box (File Publish Settings). Make sure the Flash and HTML options are selected in the Formats tab. Rename the HTML file sniffer_start.html. 9. In the Flash tab, select Flash Player 4 in the Version drop-down menu. Note You are using the Flash Player 4 format because Flash Player 3 ignores all Flash 4 or higher actions, and Flash Player 4 or higher recognizes the formatting of the variable and ActionScript structures. Flash Player 5 .swf files restructure variables and ActionScript (even Flash 4-compatible code) in a manner that doesn't work consistently in Flash Player 4. 10. In the HTML tab, select the Flash Only template. Click the Publish button located at the bottom of the Publish Settings dialog box. 11. When the files have been published, click OK to close the Publish Settings dialog box. Save your document again. You now have sniffer_start.html and sniffer.swf files in the same folder as your sniffer.fla file. In the next section, you add some additional HTML tags to the sniffer. html document.

Integrating the Sniffer Movie into an HTML Document


After you have made the sniffer.swf and the sniffer.html files, you can modify the HTML document to guide the browser to a unique URL where plug-in information and a down load screen are shown. Remember that the indicates a continuation of the same line of code. Do not insert this character into your HTML document. 1. Open the sniffer_start.html file in your preferred HTML document editor. Macromedia Dreamweaver, Notepad (Windows), TextEdit (Mac), or BBEdit (Mac) will do just fine.

- 38 -

2. Somewhere between the <head> </head> tags, insert the following HTML <meta> tag as one line of code:
3. <meta http-equiv=" Refresh" content="3; 4. url=download.html" />

This <meta> tag has two attributes, http-equiv and content. The http-equiv attribute instructs the hosting Web server to add the value of http-equiv as a discrete name in the MIME header of the HTML document. The value of the content attribute becomes the value of the MIME entry. Here, the Web browser will interpret the META tag as
Refresh: 3; URL=download.html

in the MIME header. This name/value pair tells the browser to reload the browser window in three seconds with the file download.html. After testing, you may decide to increase the time the browser waits before reloading a new URL. On slower connections (or during peak Internet hours), you may find that three seconds is not long enough for the initial HTML and Flash movie to load into the browser. Caution Some older browsers may require an absolute URL in the content attribute. This means that you may need to insert a full path to your HTML document, such as http://www.yourserver.com/download.html, as the URL in the content attribute. 5. You may want to create some text on this HTML document that indicates its purpose. If the user does not have the plug-in installed, he or she will be staring at a blank white page until the refresh is activated. For the purposes of this example, create an HTML table that centers the text "Checking for Flash Player " on the page. 6. Save the HTML file as sniffer.html. If you want this to be the default page for your Web site, you may need to rename this file to index.html, idex.htm, index.cfm, or to whatever filename your Web server is configured to use as a default page. At this point, you need to create a download.html file. You also need to create flash3.html, flash4.html, flash5.html, flash6.html, and flash7.html files for the getURL() actions in the sniffer.swf movie. On the CDROM We have included sample sniffer.html, download.html, flash3.html, flash4.html, flash5.html, flash6.html, flash7.html, and flash8.html files in the ch22/custom_sniffer folder on this book's CD-ROM. The Flash movie placeholder documents (for example, flash3.html, flash4.html, and so on) do not contain any Flash content. Note that the download.html sample file uses the JavaScript and VBScript player detection discussed in the next

- 39 -

section. When you have your HTML documents ready, you can load the sniffer.html document into a browser. If the Flash Player is not installed, then the meta tag should transport the browser location to the download.html URL. If the Flash Player is installed, then the Flash ActionScript directs the browser to the appropriate page.

Detecting the Flash Player with JavaScript and VBScript


The use of scripts written into an HTML document is also popular for Flash Player detection. If you're getting familiar with ActionScript syntax, you'll find that JavaScript detection code isn't all that complex. JavaScript is a universal scripting language that most 3.0 or higher Web browsers can employ to some capacity. Microsoft's implementation of JavaScript, called JScript, isn't exactly the same as JavaScript found in other browsers. For this reason, you can translate some JavaScript functionality into Microsoft's proprietary Web-scripting language, VBScript. On the CDROM You'll find the HTML, Flash documents, movies, and GIF files for this section in the ch22/javascript_detection folder of this book's CD-ROM.

In this section, we look at how to create an HTML document that checks for the presence of the Flash Player plug-in with JavaScript, and the Flash ActiveX control with VBScript. We use two images of a traffic light one Flash movie with a green light animating on and off, and one GIF image with a red light on to display the results of our plug-in and ActiveX detection. Many Web sites employ a similar mechanism: Before an HTML page with Flash content can be accessed, visitors are presented with a splash screen telling them whether they have the Flash Player installed. If they don't have it, they can click a link to get the plug-in or ActiveX control. As a backup, many splash pages also include a link to bypass the detection in case the detection fails. This link would take the visitor straight to the HTML document that contains the Flash content. Caution The Flash Player can be detected with most JavaScript-enabled Web browsers by using the JavaScript array navigator.mimeTypes. The value for this array is always empty for Internet Explorer browsers, including IE 4.5 on Macintosh. IE 5.0 (or higher) for Macintosh provides support for this array. While you can use VBScript to detect for IE on Windows, there is no script plug-in detection available for IE 4.5 on Macintosh. You can however, use the Flash sniffer method, discussed in the previous sections, to detect Flash on IE 4.5 on Macintosh.

- 40 -

Detecting the Plug-In with JavaScript


By using JavaScript code, you can set up a testing mechanism that delivers one of two graphics to the visitor's Web browser. Copy the script_detection.html document located in the ch22/javascript_detection folder of this book's CD-ROM and open it in your preferred text editor (TextEdit, Notepad, BBEdit, and so on), or, even better, in Macromedia Dreamweaver. Look at lines 22 through 27 in the following listing. Note The indicates a continuation of the same line of code. It should not be written in the actual JavaScript code in the HTML document.
22. var plugin = 0; 23. var activeX = 0; 24. var plugin = (navigator.mimeTypes && navigator.mimeTypes["application/x-shockwave-flash"]) ? navigator.mimeTypes["application/x-shockwaveflash"].enabledPlugin : 0 25. if (plugin) { 26. 27. } plugin = parseInt(plugin.description.substring (plugin.description.indexOf(".")-1)) >= 8

Line 22 initializes a variable plugin to save a value that indicates the presence of the Flash Player 8 plug-in on Netscape (or Mozilla, FireFox, IE 5.0 Mac, or Apple Safari). Line 23 initializes a variable called activeX to save a value that indicates the presence of the Flash Player 8 ActiveX control. At this point, you assign a value of 0 to these variables, meaning that the plug in and ActiveX Control are not installed. This is used for worst-case scenarios in which the user may be using a version of JavaScript that doesn't interpret the detection code correctly. Line 24 is borrowed from the Detect Flash 6 HTML template output from Flash MX (not Flash MX 2004 or Flash 8). It uses the mimeTypes array of the navigator JavaScript object to determine whether the Flash Player (in any version) is installed. If the Flash Player plug-in is installed, the variable plugin is now equal to the value [object Plugin]. If this is true, lines 25 and 26 will execute. Using the description property of the Plugin object, you can determine whether the Flash Player is the correct version. In this example, you check whether it's greater than or equal to 8. Notice that you can use a comparison as the value of the plugin variable. If Flash Player 8 (or higher) is installed, plugin will equal true (or 1); if a lower version is installed, plugin will equal false (or 0).

Creating a Test Object in VBScript


At this point, if the visitor is using Netscape (or a Mozilla-based browser, on any operating system) or Internet Explorer on the Macintosh, the variable plugin will

- 41 -

have a value of either 0 or 1. However, you still need to check for the ActiveX control if the visitor is using Internet Explorer for Windows. Line 13 already initialized a variable called activeX. Lines 28 through 33 check to see if VBScript can create a Flash object in the document: Note The indicates a continuation of the same line of code. It should not be written in the actual JavaScript code in the HTML document.
28. else if (navigator.userAgent && navigator.userAgent.indexOf("MSIE")>=0 && navigator.userAgent.indexOf("Windows")>=0){ document.write(<SCRIPT LANGUAGE=VBScript\> \n'); document.write(on error resume next \n'); document.write(activeX = (IsObject(CreateObject ("ShockwaveFlash.ShockwaveFlash.8")))\n'); document.write(<' + /SCRIPT>');

29. 30. 31. 32. 33. }

Line 28 determines whether the visitor is using Internet Explorer on Windows. If that's the browser the visitor is using, lines 29 to 33 will execute. These lines of code create the VBScript that is necessary to check for the existence of the Flash Player 8 ActiveX control. Using the IsObject() and CreateObject() methods, VBScript can determine whether the ActiveX Control is installed. If it is installed, the variable activeX equals true (or 1). Note that this variable is available to both JavaScript and VBScript.

Inserting the Graphics


After the variables plugin and activeX have been set appropriately, you can use these variables to either display a Flash movie file (.swf) or a GIF image graphic. In the body of the HTML document, you can reuse the plugin and activeX variables to insert either the Flash or GIF graphics. Lines 43 through 48 of the HTML document will write the tags to display the Flash movie or the GIF image for Netscape/Mozilla browsers (on any platform) or IE on the Mac. Note The indicates a continuation of the same line of code. It should not be written in the actual JavaScript code in the HTML document.
43. if (plugin) { 44. document.write('<embed src=" trafficlightgreen.swf" width="105" height="185" swliveconnect=" false" quality=" high"></embed><br/>Flash Player 8<br/>plug-in detected.'); 45. } else if (!(navigator.appName && navigator.appName.indexOf("Netscape")>=0 && navigator.appVersion.indexOf("2.")>=0)){ 46. document.write(<a href=" http://www.macromedia.com

- 42 -

/go/getflashplayer/">'); 47. document.write(<img src=" trafficLightRed.gif" width="105" height="185" border="0" /></a><br/> Flash Player 8<br/>plug-in not installed.'); 48. }

If the plugin variable is not equal to false (line 31), line 43 executes. Line 43 uses the <embed> tag to insert a Flash movie file (.swf), depicting a green light that animates to a full green color, and the HTML text "Flash Player 8 Plug-in detected." If the plugin variable is equal to false and the browser is Netscape 2.0 (or Mozilla-compatible) or higher (line 43), then lines 44 and 45 create <a href> and <img> tags, depicting a static GIF image of a red traffic light that links to the Macromedia download area. Then, JavaScript creates the HTML text "Flash Player 8 plug-in not installed." Note The following discussion refers to lines not shown in the code listings for this section. Please refer to these lines (and line numbers) within the script_detection.html document in your preferred text editor. Lines 55 through 64 perform the same functionality for Internet Explorer for Windows. If the activeX variable is true, then an <object> tag is written and a green traffic light animates on. If it's not installed, then a static GIF image of a red traffic light is displayed. Finally, you should do two more things:

Tell IE 4.5 (or earlier) Mac users that you can't detect the Flash Player 8 plug-in. Tell other users that they can either proceed to the main Flash site, or click the appropriate traffic light to download the plug-in or ActiveX control.

Lines 72 to 75 tell IE 4.5 (or earlier) Mac users that you can't detect their plug-in settings. You can either leave it to them to decide whether they should download the plug-in, or you can direct them to a sniffer movie (discussed in the previous section) to determine whether the plug-in is installed. Lines 76 to 78 check whether either the plug-in or the ActiveX control is installed. If it is, you tell the visitor to proceed to the main Flash site. Note that you'll want to insert more JavaScript code here that includes a link to your Flash content. Lines 79 to 87 check whether the plug-in and the ActiveX control are both absent. If neither is installed, you tell them which traffic light (lines 80 to 87) to click. Although you'll most likely want to spruce up the look and feel of this page to suit your particular site, you can use this scripting layout to inform your visitors about their plug-in or ActiveX control installations.

- 43 -

AIM
Detecting the Operating System.

PROGRAM
There are no two ways about it: Flash MX 2004 is a powerful development environment for creating fun and engaging applications. Yet, there comes a time when you may need a little more control of system-related functions such as being able to detect the operating system the user is using, launching external programs, detecting default file handling applications and controlling system windows -- especially when creating distributed applications. When you are looking to create educational reference material, presentations, CD-ROMs or complicated applications, Flash will (depending on the complexity of the project) usually fulfil the needs of the brief. But there are times when Flash on its own just doesn't cut the mustard, and needs a little more horsepower to accomplish the desired effect. In this article, we'll look at how, by integrating Flash and Director, we can query the operating system on which the application runs, return information and make decisions based on that data. The information presented in this article should give you the inspiration to explore the possibilities of Flash and Director integration, and give you a taste of what you can achieve with a little imagination and flair. The article source files can be downloaded by clicking here

- 44 -

Example Scenario You are building an application in Flash that needs to open several different file types (spreadsheets, PDFs, presentations, executables etc), but in order to make the application as smooth as possible, you need to check for the existence of applications that handle the types of files you are trying to open, and act accordingly. Using Flash to check whether there is a registered file-handling application for a given file that you're trying to open is, to my mind, extremely difficult -- if not impossible -- without third party or bespoke integration tools. Enter Stage Left: Director MX /MX 2004! I was recently working on a project for a CD-ROM application, and decided to create the interface in Flash. There were several sections of the application that needed to open PDF files, and I included a link to the Adobe Acrobat Reader that was included on the CD-ROM. Everything was working fine, until the client decided to add features to the project, which included opening multiple document types. Of course, this presented a new problem: I needed to know and inform the user of whether they had installed the application required to open the document they'd selected, and Flash just wasn't up to the job on its own. Rather than scrapping what I'd already written, I decided to investigate other methods by which I might retrieve this

- 45 -

information, and found Director MX 2004 to be the prime candidate for the job.

How It Fits Together The solution that I came up with was a meld of Flash and Director, where I used Flash to create the interface and act as the 'stub' to call functions within the Director application, which, in turn, was using an Xtra to perform a series of functions. While I researched alternative methods for retrieving the information, I came across a Director Xtra called 'Buddy API', which contains over 140 functions for interfacing with the Windows API and Macintosh Toolbox. This was the perfect Xtra for the job and, although it is a commercial Xtra, the unregistered free version includes two free functions. The Xtra contains many functions, some more useful than others. Click here for more details. Luckily, I could use the unregistered version, as I only needed two functions from the Xtra:

FindApp: Finds the application associated with a file type OpenFile: Opens a file using its associated program

Essentially, the Flash movie is embedded within a director application, and, rather than producing a Flash projector, we produce a Director Projector that interfaces with the operating system via the Director Xtra to check certain criteria, then carry out specific functions. The flow of information from the Flash interface through Director projector for this example is outlined in the diagram below; - 46 -

while it's simple, let's take a quick look at the steps involved and how the two applications communicate.
1342_image1 (click to view image)

Step 1 In the embedded Flash interface, the user clicks a button (in the example shown below, it's named openPDFDoco) which calls a defined function within the Director application in the following format:
openPDFDoco.onRelease = function() { getURL('lingo:FunctionHandler.FunctionName(Parameters)'); };

- 47 -

Step 2 The parameters of the file (name, extension, type) are passed to the Director movie and a custom function is called, which checks via the Buddy API Xtra whether a file handler is present for the file we wish to open. Step 3 The Buddy API Xtra checks to see if a file handler is present using the FindApp("file type") function and returns a
true

or false value to the Director Projector.

Step 4 Based upon whether a file handler is present, the file is opened using the OpenFile(filename, windowSize) function of Buddy API (step 5). Step 5 The file handler is verified and the file is opened in the relevant application. Step 6 If the File Handler is not found for the file we are trying to open, we can either trigger an alert within the Director projector to inform the user, or we can call a function in Flash. Step 7 We call the function to be executed at a specific frame in Flash; this could be as simple as moving the playhead to a specific frame to inform the user of the missing application for the file they're trying to open. By planning the behavior and integration of both the Flash SWF and the Director Projector, we can have the best of both worlds -- an easy-to-maintain application with a powerful interface that's capable of many different tasks. In the example shown below, I've implemented this

methodology to create a distributable Director projector. This serves as an installer for an application -- both as a Macromedia Extension Manager file (*.mxp) and as PDF documentation (*.pdf) -- but the basic idea outlined here can be used for any - 48 -

number of different projects when you need expand the capabilities of Flash.
1342_image2 (click to view image)

We've now discussed how the application works from a process flow point of view, so let's build the application and see how it all gels together. Creating a Scalable Directory Structure As with any development project that uses multiple sources of information, we need to establish a working directory structure that we can understand easily and use with the minimum of confusion; in this case, we're using Flash FLA / SWF / .as files, as well as Director Movies / Projectors and PDFs.

- 49 -

Create a suitable working directory structure as shown below:


1342_image3 (click to view image)

It's simple, really, but, without the basic groundwork here, we could easily get in a mess later when we edit multiple files. From the root folder for the application ('Director Application'), we have two folders ('Flash Files' and 'ISO'). The Flash Interface and relevant ActionScript files will reside in the 'Flash Files' folder. The 'ISO' folder contains the Director Movie and Projector files that we'll create later, as well as the 'Files' folder, which will contain the asset files (PDFs) for the application. Creating the Flash Interface You can make your Flash interface as complicated or as simple as you like; in this example, we'll create a simple interface with

- 50 -

a single button (just to keep things simple) that will launch the PDF opening process. Setting the Scene

With Flash open, create a new Flash document 450

pixels wide by 300 pixels high. Accept the default frame rate and click 'OK'.

Rename the default layer Actions and add below this

two further layers, called Buttons and Interface.

Select the first frame of the Interface layer and create

an interface with a relevant header and other information to match your requirements.

Select the first frame of the Buttons layer and create a

new button called launchButton. Add the relevant graphic and text garnishes to make the button functional. Once you're happy with the button, drag an instance from the Library Panel into the first frame of the Buttons layer, naming the instance launchButton.

1342_image4 (click to view image)

We're all done for the first phase of setting up the Flash movie. At the moment, there's no ActionScript to control the behavior of the button; we'll add this later, once we've set up the Director project, imported the SWF, and set up the roundtrip environment.

- 51 -

Save your Flash document as Flash to the 'Flash Interface' folder you

Interface.fla

created earlier, and export your SWF (File > Export > Export Movie) as Flash Inteface.swf. Importing the Flash Interface into Director Now that we've created the basic interface, we need to import it into Director and set up a few parameters. Setting the Scene 1) Within Director, create a new Movie (File > New Movie). From the 'Movie' tab of the Property Inspector, set the Stage Size to 450 x 300. 2) Select File > Import and locate the Flash Interface.swf that you have just exported from Flash. Click 'Add' to add it to the import list and click 'Import'. 3) If the Cast window isn't already visible, select Window > Cast to show the window and arrange it to your liking. 4) 5) You should now see the imported Flash movie within the internal cast window. 6) Select the Flash movie, and select the 'Member' tab of the Property Inspector. Change the 'Name' of the movie to test. Within the same tab, click the 'Edit' button and locate the source FLA for the SWF file (Flash Interface.fla). 7) Drag an instance of the imported SWF to the stage and, with the Flash movie selected on the stage, edit the 'L' (Left) and 'T' (Top) parameters within the 'Sprite' tab of the Property Inspector to L:0, T:0.

- 52 -

This now allows us easily to edit the Flash SWF file via the roundtrip methodology from within Director. 8) Save your Director Movie within the Director Application/ISO directory that you created earlier. If you now double click the Flash Movie on the stage, it will automatically launch Flash for editing. When the file is open within Flash, clicking the 'Done' button at the top left of the timeline automatically updates the embedded SWF within Director.
1342_image5 (click to view image)

This makes life a lot easier; making updates becomes seamless, and reduces the chance of Flash SWF edits being lost or overwritten. Installing the Buddy API Director Xtra In order to make full use of what we're working to accomplish here, you'll need to install the Buddy API 3.6 Director Xtra. This Xtra is downloadable here. Once it's downloaded, extract the contents of the .zip or .hqx file and copy the budapi.x32 file to your Director Xtras folder, which, in Windows and Macintosh, will look something like this:
Windows - c:\windows\program files\macromedia\director mx 2004\configuration\xtras Mac OS X /Users/~USERNAME/Library/Application Support/Macromedia/Director MX 2004/Configuration/Xtras

- 53 -

Adding the Lingo If you were to try and publish your Director Projector now, things would look a little odd -- the projector would successfully be created but, when you tried to load it, it would open for about a second, then close. Why?...Well, there's no Lingo or JavaScript code that has been added within Director. Although it may preview internally within Director without any problems, as soon as it's exported into a projector, the playback head hits the last frame of the Flash movie and quits. We need to start adding within Director the code to control this -- a simple score script. Note: If the Score window is not open make sure it is be selecting Window > Score. 1) Select the first frame of the behavior channel, right click and select 'Frame Script'.

- 54 -

1342_image6 (click to view image)

2) When the script window opens, name the cast member pauseMovie and add the following code:
on exitFrame go to the frame end

This script simply pauses the movie and gets rid of the annoying exiting behavior within the projector. If you now preview your projector (File > Publish) you'll see that the projector window stays open, and we can move on to add more of the control code.

- 55 -

AIM
Checking the System Language.

PROGRAM

- 56 -

Macromedia Flash MX 2004 provides localization capabilities using the Strings Panel to create multi-language text. The Strings Panel enables you to have Flash automatically detect a user's local system language and use this as the default for displaying localized text strings. Sometimes developers may want to provide, by way of a menu selection in the Flash movie, a user-specified language selection that can be used instead of the default system language to substitute the localized text strings.

Prerequisites
In order to get the most out of this TechNote, an understanding of the Flash MX 2004 Strings Panel functionality is required. Information on using the Strings Panel to provide localized text objects can be found in the "Using the Strings panel to author multi-language text" section of the Flash Help. Additionally, an understanding of ActionScript programming and debugging is needed since you will modify a source ActionScript file and add new functions that must be called from your FLA.

Strings panel settings


Under its Settings button, the Strings Panel has a user selectable option to replace the dynamic text objects with localized strings. In this example we will be using theruntime mode. In the Strings panel settings, make the selection for runtime below:

Author time: Uncheck "Insert ActionScript for automatic language detection". You have to select the stage language and publish. The published SWF will always use the stage language strings for the dynamic texts. Runtime: Check "Insert ActionScript for automatic language detection". You have to make sure the external XML files with the localized strings are available with the published SWF. These external XML files are written out by the Flash authoring tool and reside in the same directory as the published SWF. The Flash player detects System.capabilities.language and loads the XML file that matches the local user's language.

- 57 -

ActionScript Implementation
You will need to modify and add new methods in the Locale.as file. Follow the steps below to modify the Locale.as file located in the user configuration path (do not use the original Locale.as file located under the application path). There are actually two locations that developers can choose to place the newly modified Locale.as file: in the user path (which will affect all projects) or in the local path (which affects the current document only). This TechNote will discuss the user path location. For more information about the local path location, refer to the Additional Information at the end of this document.

To modify Locale.as: 1. Open up the Locale.as file located at:


Windows 2000 or XP: <system drive:>\Documents and Settings\<username>\ Local Settings\Application Data\Macromedia\Flash MX 2004\en\Configuration\Classes\mx\lang\Locale.as Windows 98SE: <system drive:>\Windows\Application Data\ Macromedia\Flash MX 2004\en\Configuration\Classes\ mx\lang\Locale.as

- 58 -

Mac OS X: <hd>:Users:<username>:Library:Application Support: Macromedia:Flash MX 2004:en:Configuration:Classes:mx:lang:Locale.as

2. In Locale.as, add a new public method:

3. static function setXMLLang(langCode:String):Void 4. { 5. xmlLang = langCode; 6. } Separate the existing initialize() function into two functions by creating a new start() function and copying code from the original initialize() function: static function initialize():Void { xmlDoc = new XML(); xmlDoc.ignoreWhite = true; xmlDoc.onLoad = function(success:Boolean){ onXMLLoad(success); // parse the XML callback.call(null, success); } } static function start():Void { var langCode:String = xmlLang; if(xmlMap[xmlLang] == undefined) { } langCode = defaultLang;

currentXMLMapIndex = 0; xmlDoc.load(xmlMap[langCode][0]);

7. Save and close Locale.as.


8. To utilize the changes you just made in Locale.as, add these 2 lines as a frame action to the FLA file. You only need to call them once and the new language setting will apply to the whole movie: 9. // make sure the there is a corresponding 10. //<language>/<fla_name>_<language>.xml file in the SWF root directory 11. var newLang:String = "<language>"; //for example "de"

- 59 -

12.

mx.lang.Locale.setXMLLang(newLang);

13. // begin replacing the dynamic texts with strings from the xml file mx.lang.Locale.start();

Authoring Implementation and Debugging


There is a limitation that developers need to be aware of when using this technique. All dynamic text fields that use the Strings Panel have to exist in or before the frame where the language switching code is executed. In cases where it is not desirable to show a text field prior to language selection, it may be necessary to author text fields with the visibility set to false. A useful debugging technique to show correct implementation is to add trace statements to the modified Locale.as file to ensure methods are being called in the correct order. Traces can be added to these Locale.as methods: static function addDelayedInstance() private static function onXMLLoad() private static function assignDelayedInstances() Successful implementations will result in traces in this order: addDelayedInstance onXMLLoad assignDelayedInstances Notes

Unless you setup a local document path for the modified Locale.as, the changes you make to the source Locale.as will apply to all FLA files in all your projects. Since mx.lang.Locale.initialize() no longer contains all of its original code, you will have to call mx.lang.Locale.start(); in other FLA files even if you do not plan to define your own language. See theAdditional Information below. When modifying the Locale.as file, be sure to leave a space or line return between the function return type and the opening brace in order to avoid syntax error messages in the authoring environment: static function start():Void {...} If you want to revert back to the original behavior, simply delete the modified Locale.as file in your user configuration folder. The original file at "<installation>\en\First Run\Classes\mx\lang" will be copied over to your user configuration folder the next time you launch Flash. Be aware that there is a dependency that the timestamp of modified AS files must precede the timestamp of the compiled ASO files. It may

- 60 -

be necessary to manually delete yourmx.lang.Locale.aso file for the changes to take effect. For more information, see Compiler caches external class files ( TechNote 19045).

Additional information
Developers can also create a classpath for Locale.as for a path local to the project and leave the original Locale.as in the user path undisturbed. Configuring local Actionscript classpaths (TechNote 19189) discusses how to configure local ActionScript classpaths in order to use modified classes on a per-document basis. Compiler caches external class files (TechNote 19045) discusses how ActionScript Object (ASO) files are cached and how it may be necessary to manually remove .ASO files which become out of sync with their associated .AS files. Dynamically Replacing Strings panel text content (TechNote 19096) describes a technique for replacing text strings that have been bound with string IDs at runtime.

- 61 -

AIM
Detecting Display Settings.

PROGRAM
Communicating with a movie's playback environment is important for knowing how your Flash movie will play and be seen by your audience. With that information, you can tailor the movie's display or provide warnings and recommendations to your viewers so they can better enjoy your movie. A viewer might have a lower screen resolution than you require to display the entire Stage of your movie, for example. You could load a different movie that fits, or you could modify the movie's display settings to allow it to be scaled down. Detecting system capabilities and the kind of player hosting the movie is especially important as Flash content becomes more prevalent in devices such as cell phones, PDAs, and television set-top boxes. Two classes can help you gather information about the playback environment: the System.capabilities class and the Stage class. The System.capabilities class can tell you about screen resolution, the operating system, the color capabilities, and many other useful properties. Table 6.4 summarizes the System.capabilities properties. Table 6.4. Properties of the System.capabilities Class PROPERTY language os manufacturer serverString isDebugger version playerType hasAudio hasMP3 DESCRIPTION Language that Flash Player supports, indicated by a twoletter code (en = English) Operating system Manufacturer of Flash Player Information to send to a server containing the System.capabilities properties Debugger capability Flash Player version The type of player playing the movie (e.g., standalone, plugIn, etc.) Audio capability MP3 decoder capability

- 62 -

Table 6.4. Properties of the System.capabilities Class PROPERTY hasAudioEncoder DESCRIPTION Audio encoder capability

hasEmbeddedVideo Embedded video support hasPrinting hasVideoEncoder screenResolutionX screenResolutionY screenDPI screenColor pixelAspectRatio hasAccessibility Printing support Video encoder capability Horizontal size of screen, in pixels Vertical size of screen, in pixels Screen resolution, in dots per inch Color capability (color, grayscale, or black and white) Pixel aspect ratio of the screen Accessibility capability

The Stage class can tell you about the display and layout of the movie, detect whether the Stage is resized, and modify the movie's properties in response. Table 6.5 summarizes the properties of the Stage object. Table 6.5. Properties of the Stage Class PROPERTY DESCRIPTION align Alignment of the Flash content ("T" = top, "B" = bottom, "R" = right, "L" = left, "TR" = top right, "TL" = top left, "BR" = bottom right, "BL" = bottom left, "C" = center) Height of the Stage, in pixels (read-only) Width of the Stage, in pixels (read-only) Type of scaling display ("showAll", "noBorder", "exactFit", or "noScale") Shows the Control menu when you Control-click (Mac) or rightclick (Windows) the movie (true/false)

height width scaleMode showMenu

- 63 -

AIM
Tinting a Movie Clips Color.

PROGRAM
Color Class package: control over movie clip color valuesversion: Flash 5 Color Class Constructor new Color(target) Arguments

target A string or reference indicating the path to the movie clip or document level whose color will be controlled by the new object (references are converted to paths when used in a string context). Methods

getRGB( ) Retrieve the current offset values for Red, Green, and Blue. getTransform( ) Retrieve the current offset and percentage values for Red, Green, Blue, and Alpha. setRGB( ) Assign new offset values for Red, Green, and Blue, while reducing percentage values to 0. setTransform( ) Assign new offset and/or percentage values for Red, Green, Blue, and Alpha. Description We use objects of the Color class to dictate the color and transparency of a movie clip or main movie programmatically. Once we've created an object of the Color class for a specific target, we can then invoke the methods of that

- 64 -

Color object to affect its target's color and transparency. That is, there is no color property used to manipulate a movie clip's color; instead we create a Color object that targets the desired movie clip. For example, suppose we have a clip instance named ball that we want to color red. We first make a Color object with a target of ball, and store it in the variable ballColor. Then we can use ballColor.setRGB( ) to assign ball the color red, as follows: var ballColor = new Color("ball"); ballColor.setRGB(0xFF0000); // Pass setRGB( ) the hex value for red

For a custom example that adds a color-setting method directly to the MovieClip class, see the Color.setRGB( ) method.

The preceding example provides color control for simple applications. But to handle more complex scenarios, we need to know more about how color is represented in Flash. Every individual color displayed in a movie clip is defined by four separate components: Red, Green, Blue, and Alpha (or transparency). These four components are combined in different amounts to generate each color we see on screen. The amount of Red, Green, Blue, and Alpha in a given color is described as a number between 0 and 255. The higher the value of Red, Green, or Blue, the more each of those colors contributes to the final color. However, remember that computer color is additive, not subtractive like paint, so higher values tend to be brighter, not darker. If all three RGB components are equal, the result is a shade of gray; if they are all 0, the result is black; if they are all 255, the result is white. The higher the value of Alpha, the more opaque the final color will be. (A color with an Alpha of 0 is completely transparent, and a color with an Alpha of 255 is completely opaque.) For example, pure red is described by the following values: Red: 255, Green: 0, Blue: 0, Alpha: 255 whereas a partially transparent red might have the values: Red: 255, Green: 0, Blue: 0, Alpha: 130 For the purposes of this discussion, we adopt the so-called RGB triplet notation (R: red, G: green, B: blue) when talking about color values. Although ActionScript doesn't support decimal RGB triplets such as (255, 0, 255), it does support the hexadecimal equivalent form 0xRRGGBB, where RR, GG, and BB are each two-digit hex numbers representing Red, Green and Blue. For example, the RGB triplet (R:51, G:51, B:102) is equivalent to the hexadecimal value 0x333366.

- 65 -

We'll also adopt the so-called RGBA quadlet notation (R: red, G: green, B: blue, A: alpha) for convenience during the following discussion. Note that although there is no color property for a movie clip, clips do have an _alpha property that represents the alpha channel setting. The initial Red, Green, Blue, and Alpha values for each color in a movie clip are set in the Flash authoring tool using the Color Mixer panel. (In the Color Mixer panel, Alpha is shown as a percentage, not a number from 0 to 255.) To alter all the colors in a movie clip via ActionScript, we make universal adjustments (known as transformations) to the Red, Green, Blue, and Alpha components of the clip's color. Transformations can be applied at authoring time via the Property inspector (Flash MX) or Effect panel (Flash 5). We have two means of setting transformations for each color component:

We can set the percentage of the component's original value to a number between -100 and 100. For example, we can say, "set all red used in this clip to 80% of its original value." Although negative percentages aren't meaningful in isolation, they are used to calculate the final transformation as shown later in this Description. We can specify an amount to offset the component's original value. The offset is a number between -255 and 255. For example, we can say, "add 20 to all blue values in this clip," or, using a negative number, we can say, "subtract 30 from all blue values in this clip."

The final value of a color in a transformed clip is determined by combining its original (author-time) color component values with the transformation percentages and offsets set through the Color object, as follows: Code View: Scroll / Show All R = originalRedValue * (redTransformPercentage/100) + redTransformOffset G = originalGreenValue * (greenTransformPercentage/100) + greenTransformOffset B = originalBlueValue * (blueTransformPercentage/100) + blueTransformOffset A = originalAlphaValue * (alphaTransformPercentage/100) + alphaTransformOffset If no transformations have been performed through ActionScript, the initial transformation percentage for each component defaults to 100, while the initial offset defaults to 0. Let's look at how color transformations work with a practical example. Suppose that a clip contains an opaque red triangle (R:255, G:0, B:0, A:255) and an opaque green circle (R:0, G:255, B:0, A:255). Also suppose that we apply a universal transformation to the clip, setting the percentage of Green to 50, the percentage of Alpha to 80, and the offset of Blue to 100, but

- 66 -

leaving the other offsets and percentages at their defaults (0 or 100). Here's how the universal transformation affects our red triangle: R= G= B= A= = 255 * (100/100) + 0 = = 255 = 0 * (50/100) + 0 = = 0 = 0 * (100/100) + 100 = = 100 = 255 * (80/100) + 0 = = 204 // No change to Red // Green reduced to 50% // Blue offset by 100 // Alpha reduced to 80%

The final transformed red triangle has the color value (R:255, G:0, B:100, A:204). Now here's how the transformation affects our green circle: R= G= B= A= = 0 * (100/100) + 0 = = 0 = 255 * (50/100) + 0 = = 127.5 = 0 * (100/100) + 100 = = 100 = 255 * (80/100) + 0 = = 204 // No change to Red // Green reduced to 50% // Blue offset by 100 // Alpha reduced to 80%

The final transformed green circle has the color value (R:0, G:127.5, B:100, A:204). To apply our hypothetical color transformations to a real clip, we use a Color object as we saw earlier. To set a clip's universal color offset and percentage values we use the setRGB( ) and setTransform( ) methods (see the entries for those methods for example code). Conversely, to examine the current color transformations of a clip, we use the getRGB( ) and getTransform( ) methods. The Color class methods can produce animated color effects, such as fade-ins, fade-outs, and tinting. Furthermore, because we can apply tints to each clip instance individually, the Color class provides a very efficient way to create diverse graphics with minimal assets. For example, we can create a scene full of balloons from a single movie clip that we colorize and tint in myriad ways, as shown under the Example heading that follows.

- 67 -

AIM
Controlling a Movie Clips Color with Sliders.

PROGRAM
Controlling a Movie Clip's Color with Sliders This recipe presents a full application that creates sliders for the red, green, blue, and alpha values that control a movie clip's color: 1. Create a new Flash document and save it.

2. On the main timeline, rename the default layer as movieClips and


create a new layer named actions. 3. Create a movie clip symbol and draw a circle in it. The circle should be approximately 120 x 120 pixels.

4. Return to the main timeline and create an instance of the circle movie

clip on the Stage on the movieClips layer. Place the instance on the left side of the Stage. Name the instance circle_mc using the Property inspector. Components) and drag four instances of the ScrollBar component onto the Stage on the movieClips layer. Name these instances red_sb, green_sb, blue_sb, and alpha_sb. Line them up horizontally on the right side of the Stage.

5. Open the Components panel (Window

6. Select the keyframe of the actions layer and open the Actions panel. 7. Add the following code to the Actions panel and test the movie
(Control Test Movie). The scrollbars are automatically colorized to indicate the color components they control. Moving the thumb sliders on the scrollbars adjusts the circle's color. Code View: Scroll / Show All // Define a function that will initialize the scrollbar instances as sliders to // control the color values. function initSliders ( ) { // First, set the scroll properties of each of the scrollbars. For the red, // green, and blue scrollbars, the values should range from 0 to 255. Use a // pageSize of 120 for the color sliders to create a proportional thumb bar.

- 68 -

// The alpha range is from 0 to 100, and so the pageSize should be 47 to create // a thumb bar that is proportional with the other sliders. red_sb.setScrollProperties (120, 0, 255); green_sb.setScrollProperties(120, 0, 255); blue_sb.setScrollProperties (120, 0, 255); alpha_sb.setScrollProperties(47, 0, 100); // Colorize the sliders themselves. Make the red_sb slider red and, similarly, // make green_sb green and blue_sb blue. Make the alpha_sb slider white. red_sb.setStyleProperty ("face", 0xFF0000); green_sb.setStyleProperty("face", 0x00FF00); blue_sb.setStyleProperty ("face", 0x0000FF); alpha_sb.setStyleProperty("face", 0xFFFFFF); // Set the initial position for the color sliders. alpha_sb remains at 100%. red_sb.setScrollPosition (127); green_sb.setScrollPosition(127); blue_sb.setScrollPosition (127); } function initColor ( ) { // Store a new Color object in a property of circle_mc. my_color = new Color(circle_mc); circle_mc.col = my_color; // Store references to the four scrollbars as properties of circle_mc. circle_mc.red = red_sb; circle_mc.green = green_sb; circle_mc.blue = blue_sb; circle_mc.alpha = alpha_sb; } // Initialize the sliders and the Color object. initSliders( ); initColor( ); // Update the color of the circle_mc movie clip based on the slider positions. circle_mc.onEnterFrame = function ( ) { // Retrieve the current position of the color and alpha sliders. var r = 255 - this.red.getScrollPosition( ); var g = 255 - this.green.getScrollPosition( ); var b = 255 - this.blue.getScrollPosition( ); var a = 100 - this.alpha.getScrollPosition( );

- 69 -

// Set up the transformation object properties to set circle_mc's color. transformObj = new Object( ); transformObj.ra = 0; transformObj.rb = r; transformObj.ga = 0; transformObj.gb = g; transformObj.ba = 0; transformObj.bb = b; transformObj.aa = a; transformObj.ab = 0; this.col.setTransform(transformObj); }

- 70 -

AIM
Drawing a Circle.

PROGRAM
Using Flash When you first open Flash, you will notice that it resembles other graphic editing programs you may be familiar with, such as Adobe Photoshop. At its basic level, Flash is a drawing program, and in order to use the more advanced features of Flash, basic drawing tool functions must be learned. Open Flash, if it is not already open. In the default layout, you will see several panels around the center of the drawing canvas, or stage. On the left is the Tools panel, along the bottom is the Properties, Actions, and Help panels, and along the right are such panels as Components, Color Mixer, and Component Inspector. Except for the Tools panel, you can click on the title of any panel to collapse it, and you click on the gripper next to the title to drag the panel around, allowing you to rearrange your panel sets to suit your work patterns. You can hide and show the various panels available in Flash by selecting them Window menu (or under the Design Panels, Development Panels, and Other Panels submenus of the Window menu). Basic Tools There are many basic drawing tools available in Flash. Each is detailed below. Also note that many of these tools have additional options or modes that can be changed in the Options area of the Tools panel. The first important tool is the Selection tool. This tool is used to make selections on objects and graphics on the drawing area, or stage. You can either click on individual objects to select them, or click and drag to make a rectangular region and select all the objects in it. Once you make a selection, you may perform subsequent actions that affect your selection, such as moving it around the stage, deleting, or altering it in the Properties panel. Hold down the SHIFT key to select multiple individual objects. The Subselection tool is used for selecting and modifying anchor points on curves and lines. Clicking once on a line or curve with the Subselection tool reveals the anchor points. Anchor points are represented either by a hollow square (a corner point), or a hollow circle (a curve point). Clicking on an anchor point with the Subselection tool will select that anchor point (then represented by a filled square or circle). You can then click and drag the anchor point to move it, ALT-click and drag on a corner point to convert it to a curve point (and thus reveal anchor point tangent handles), or ALT-click on a curve point to convert it to a corner point (and thus remove the tangent handles).

- 71 -

The Line tool is an important drawing tool. It functions like the line tool in other drawing programs. To use it, click on the stage, drag, and release to draw a straight line. Stroke width, style, and color can be changed in the Properties panel. Hold down the SHIFT key while dragging to constrain the line angle to increments of 45. The Lasso tool can be used to select objects on the stage. It allows y to create a freeform selection area by clicking and dragging around an area. When you release the mouse button, Flash automatically completes the loo with a straight line. Adding Drawing Code When the user clicks on the drawing interface (drawArea), look up the color selected, create a new Circle object, and then add the circle to the array of circles: drawArea.onPress = function() { var c; switch (colorGroup.getValue()) { case "red": c = 0xFF0000; break; case "green": c = 0x00FF00; break; case "blue": c = 0x0000FF; break; } var circle:Circle = new Circle(drawArea._xmouse,drawArea._ymouse,c); circles.push(circle); Note that you have not actually drawn anything, but just stored the information about the new circle. The drawing comes in the very next line that concludes the function: update(drawArea); }; What's going on here? You've delegated drawing to the update() function, sending in the name of the clip in which the circles are to be drawnin this case, drawArea. The update() function does the actual drawing: // draws the circles on the movie clip provided function update(mc) { for (var i=0;i<circles.length;i++) { // make a copy of the 'circle' movie mc.attachMovie("circle","circle" + i,i); // get a reference to this new clip var circleClip = mc["circle" + i]; // move the new clip circleClip._x = circles[i].getX(); circleClip._y = circles[i].getY();

- 72 -

var clipColor = new Color(circleClip); clipColor.setRGB(circles[i].getColor()); } } Note that this function takes a movie clip as an argument, so it can draw circles on any movie clip, not just the drawArea clip. By organizing your code in this fashion, you avoid repeating the code for drawing the circles. That is, you can use this same method for preparing your printouts of the drawing. Here is the print function, wired to the "print" button on the main interface. As you can see, this function starts off with two calls to update(), once for each of the print pages: printButton.onPress = function() { // prepare the printing area update(printArea1.printPreview); update(printArea2); // shrink the preview printArea1.printPreview._xscale = 25; printArea1.printPreview._yscale = 25; printArea1.dateField.text = new Date(); var printJob:PrintJob = new PrintJob(); if (printJob.start()) { var numPages:Number = 0; if (printJob.addPage(printArea1)) { numPages++; } if (printJob.addPage(printArea2)) { numPages++; } if (numPages > 0) { printJob.send(); } delete printJob; } } After the calls to update(), which render the circles on the offscreen movie clips, shrink the print preview movie clip to one quarter og its original dimensions so that it appears smallerlike a preview should. The rest is just the PrintJob boilerplate code from above. So when you press the print button, two new copies of

Figure 2. The Offscreen Clips: Pressing the print button copies the drawing twice to the offscreen clips.

- 73 -

the drawing are made to the offscreen clips. Figure 2 shows a screenshot taken from within the Flash Player that exposes these offscreen areas.

AIM
Drawing a Rectangle.

PROGRAM
By learning frame-by-frame animation, you will have a better understanding of how the Timeline works and how you can control it. 1. First, create a shape in one layer on the stage, say, a rectangle. Notice the frame in the Timeline has a black dot after you have created the circle i.e., it becomes a keyframe. Keyframes designate points in animation transitions and reflect changes in animation as the movie progresses. The first frame becomes a keyframe when you place an object on the stage.

2. Now, click on frame 2 in the layer and go to Insert > Keyframe, or press
the shortcut key, F6. Another keyframe will be created and your rectangle will be automatically placed on the stage in the second keyframe. 3. If the rectangle is not highlighted as a fine checkerboard pattern, use the Selection tool to draw a selection box around the rectangle. A checkerboard pattern indicates the graphic object is selected 4. Now, hold down the SHIFT key and press the down arrow on the keyboard to move the rectangle down a few pixels. (Without the SHIFT key pressed, the rectangle will move one pixel at a time.). The rectangle moves further down in the next keyframe

5. Click the next frame in the layer and insert another keyframe (F6).
6. Move the rectangle down again in the same manner. 7. Repeat this process until you have 12 keyframes, each with the rectangle moving down a little further than the last time. Now, if you slide, or scrub, the timeline playhead back and forth from the first to twelfth frame, you will notice that the rectangle moves up and down. 8. Move the playhead to the first frame and press Enter on the keyboard to play the movie. Congratulations, you have created your first Flash animation! 9. To preview your movie as it will play in real time, press CTRL-Enter. Watch how your animation plays and repeats. Close the movie to return to Flash. Frame-by-frame animation is rarely used in Flash. Its use is mainly confined to animation sequences that require exact positioning and strict rates of change. Another circumstance to use frame-by-frame animation is to display imported movie file images, which is beyond the scope of this workshop.

- 74 -

AIM
Filling a Shape with a Gradient.

PROGRAM
The Gradient Transform tool (F) was originally an option for the Paint Bucket tool, but in Flash MX 2004, it was given a home on the main Tools panel, right next to the Free Transform tool. Gradient Transform is used only to modify bitmap or gradient fills and will not apply to simple color fills. The Gradient Transform does many of the same things the Free Transform tool does, but it only modifies the fill of a shape without changing the stroke or outline appearance at all. This is a lot like shifting, rotating, or scaling a larger piece of material behind a frame so that a different portion is visible. The Gradient Transform tool has only one option in the Tools panel, but, as with the Eyedropper tool, it does apply differently depending on the type of fill selected. To use the Gradient Transform tool, select it in the Tools panel, and then simply click an existing gradient or bitmap fill. A set of three or four adjustment handles appears, depending on the type of fill. The following three transformations can be performed on a gradient or bitmap fill: adjusting the fill's center point, rotating the fill, and scaling the fill. The extra set of adjustment handles displayed on bitmap fills enables them to be skewed. The Magnet option in the Tools panel toggles on Snapping behavior making it easier to constrain transformations to even adjustment increments. Figure 9-8 illustrates the various adjustment handles on three types of fills.

- 75 -

Figure 9-8: The Gradient Transform tool applied to a Radial gradient (A), a Linear gradient (B), a tiled Bitmap fill (C), and a scaled Bitmap fill (D). Each handle type has an icon to indicate its function. The position of these handles may shift if a fill (or bitmap fill) has been variously copied, rotated, or pasted in any number of ways. The fundamental rules are as follows:

The round center handle moves the center point. The extra center pointer on radial gradients moves the highlight. The round corner handle with the short arrow rotates. The square edge handles scale either vertically or horizontally. The round corner handle with a long arrow scales symmetrically. The diamond-shaped edge handles on bitmap fills skew either vertically or horizontally.

Tip To see all the handles when transforming a large element or working with an item close to the edge of the Stage, choose View Work Area from the application menu or use the shortcut keys Shift+Ctrl+W (Shift+z+W). Adjusting the Center Point with the Gradient Transform Tool If the fill is not aligned in the shape, as you would like it to be, you can easily move the center point to adjust how the fill is framed by the shape outline. To adjust the center point, follow these steps: 1. 2. 3. 4. Deselect the fill if it has been previously selected. Choose the Gradient Transform tool. Click the fill. Bring the cursor to the small circular handle at the center of the fill until it changes to a four-arrow cursor, pointing left and right, up and down, like a compass, indicating that this handle can now be used to move the center point in any direction. 5. Drag the center circular handle in any direction you want to move the center of the fill. Figure 9-9 shows a radial gradient (left) repositioned with the Gradient Transform tool (right).

- 76 -

Figure 9-9: Adjusting the center point of a gradient fill with the Gradient Transform tool A new feature in Flash 8 makes it possible to adjust the highlight of a radial gradient without moving the center point of the fill. As shown in Figure 9-10, you can drag the extra pointer above the center point circle to move the highlight of the gradient along the horizontal axis. If you want to move the highlight along a vertical axis, use the rotate handle to change the orientation of the fill.

Figure 9-10: A new Flash 8 Gradient Transform handle makes it possible to adjust the highlight of a radial gradient without moving the center point of the fill. Tip The Paint Bucket tool is also a handy way to set the highlight point of a gradient fill. Select the gradient that you want to apply, then click in the shape where you want the highlight to be. You can keep clicking in different areas of the shape with the Paint Bucket to move the highlight around until you like it. Rotating a Fill with the Gradient Transform Tool To rotate a gradient or bitmap fill, find the small circular handle that's at the corner of the fill. (In a radial gradient, choose the lower circular handle.) This circular handle is used for rotating a fill around the center point. Simply click the circular handle with the Rotate cursor and drag clockwise or counterclockwise to rotate the fill. Figure 9-11 shows a bitmap fill (left) as it appears when rotated clockwise (right).

- 77 -

Figure 9-11: Rotating a bitmap fill with the Gradient Transform tool Tip Activate the Snapping toggle in the Tools panel if you want to use Snapping behaviors to help guide rotating or scaling of a fill. (Turn behaviors on or off in the application menu under View Snapping.) Adjusting Scale with the Gradient Transform Tool To resize a bitmap fill symmetrically (to maintain the aspect ratio), find the round-corner handle with an arrow icon, which is usually located at the lower-left corner of the fill. On rollover, the diagonal arrow icon appears, indicating the direction(s) in which the handle resizes the fill. Click and drag to scale the fill symmetrically. On radial gradients, you use the round-corner handle with the longer arrow icon to scale with the gradient aspect ratio constrained. Linear gradients only have one handle for scaling, and this handle always scales in the direction of the gradient banding. To resize a fill asymmetrically, find a small square handle on either a vertical or a horizontal edge, depending on whether you want to affect the width or height of the fill. On rollover, arrows appear perpendicular to the edge of the shape, indicating the direction in which this handle resizes the fill. Click and drag a handle to reshape the fill. Figure 9-12 shows the three fill types with their respective scale options. Linear gradient fills (left) can only be scaled in the direction of the gradient banding, but they can be rotated to scale vertically (lower) instead of horizontally (upper). Radial gradient fills (center) can be expanded symmetrically (upper) with the circular handle, or asymmetrically (lower) with the square handle. As with Linear gradients, they can be rotated to scale vertically rather than horizontally. Bitmap fills (right) can be scaled by the corner handle to maintain the aspect ratio (upper), or dragged from any side handle to scale asymmetrically (lower).

- 78 -

Figure 9-12: Scaling fills symmetrically (top) and asymmetrically (bottom) Caution Adjusting bitmap fills with the Gradient Transform tool can be tricky business. On tiled fills, the transform handles are often so small and bunched together that they are difficult to see. On full-size bitmaps, the handles are sometimes outside the Stage and it can be hard to find the handle that you need. It can also be unpredictable where the handles will appear when you select a bitmap fill with the Gradient Transform tool often they are outside the shape where the fill is visible. Our advice is to use this workflow only when you have no other choice. In general, it is a much better idea to decide on the size for a bitmap and create a Web-ready image that you can use without scaling before you import it to Flash. Note The right column of Figure 9-12 is a good example of how changes applied to one tile in a bitmap fill will be passed to all the other tiles within the shape. Setting Gradient Fill Overflow Styles As you work with scaled gradient fills, you will quickly notice that your shape is always filled from edge to edge but that the fill area may not appear quite how you'd like it to. In previous versions of Flash, you were stuck with the solid color fill around the edges when a gradient was scaled smaller inside of a shape. In Flash 8, this default behavior is now part of the Overflow menu in the Color Mixer panel that gives you some other options for how a gradient renders when it is scaled down. As shown in Figure 9-13, there are three different overflow styles:

Extend: Extends the colors on the outside edge of the gradient to create a solid fill beyond the edge of the rendered gradient Reflect: Alternates flipped (reflected) versions of the original gradient until the shape is filled from edge to edge Repeat: Renders the color pattern of the original gradient repeatedly until the shape is filled from edge to edge

- 79 -

Figure 9-13: Different overflow styles applied to a Linear gradient (top right) and a Radial gradient (bottom right) using the Overflow menu in the Color Mixer panel (left). Overflow styles applied to the fills from left to right Extend, Reflect, Repeat. Skewing a Bitmap Fill with the Gradient Transform Tool To skew a bitmap fill horizontally, click the diamond-shaped handle at the top of the image; arrows appear, parallel to the edge of the fill, indicating the directions in which this handle skews the fill. Drag to skew the image in either direction. Figure 9-14 shows a bitmap skewed horizontally (left) and vertically (right). Note that the skew procedure is still active after it has been applied, meaning that the skew may be further modified this behavior is common to all functions of the Gradient Transform tool.

Figure 9-14: Skewing a bitmap fill with the Gradient Transform tool Note Gradient fills cannot be skewed; they can only be scaled on the horizontal or vertical axis. Tip If you get carried away with the Gradient Transform tool and you want to get back to the original fill position and size, double-click the center icon of the shape and all transformations will be reset.

- 80 -

AIM
Scripting Masks.

PROGRAM
Simple Scripted Masking In this example, we'll animate a mask from one point to another, based on input parameters we provide. I created this example to illustrate the traffic received by two Web servers hosting a number of Websites. The movie accepts two input parameters, then animates the mask accordingly. For this simple example, we'll populate the variables statically by declaring them in the root of the timeline. A more realistic scenario would see the movie embedded in a database-driven Web page and the variables passed to the movie dynamically. We'll cover importing external data in Chapter 8, External Data. Figure 3.4. This simple scripted masking effect animates a mask between two points. The finished product is shown in Figure 3.4. Let's look at how this effect is accomplished. To skip straight to modifying the effect , locate the file called Simple_Animation_Masking.fla in the code archive. 1. Create a new movie that's 200 pixels wide and 40 pixels high. Alter the frame rate to 24 fps for a nice, smooth animation. 2. Create the folders and layers shown in Figure 3.5 below.

- 81 -

3. Figure 3.5. Organize the layers and folders for the scripted masking effect. We now need to create the background bar that we'll mask. In this example, I created a bar that's white on the left and gradually became red toward the right, indicating the increase in server load as traffic levels grow.

4. Add two static text fields within the textlabels layer and enter text that
reads, Server 1 and Server 2, to let users know what each bar represents. We don't need to convert these to movie clips, as we won't reference them in our ActionScript. Move them to (1, 0) and (1, 25) respectively.

5. Within the Server1Background layer, create a new rectangle that's 100


pixels wide and 9 pixels high. Select a gradient fill that changes from white on the left, through yellow and orange, to red on the right of the rectangle. Select the rectangle, then select Insert > Convert to Symbol. Choose to create a Graphic named Background.

6. Name the existing instance of Background backg1 and move it to (50,


3). Drag a second instance of the graphic from the Library Panel into the Server2Background layer naming it backg2, and move it to (50, 29). Lock these two layers; we don't need to modify them any further.

- 82 -

Now that we've created the backgrounds, we can build the masks we'll control via ActionScript:

7. Create a new rectangle, with no stroke and a solid white fill, that's 5
pixels wide and 9 pixels high (this exactly matches the height of the movie clip we will mask). Convert the rectangle to a graphic symbol

named ServerAnimation, and place instances of the graphic in the Server1Mask and Server2Mask layers. Name the instances server1Mask and server2Mask respectively. (This is important as we will reference these clips in ActionScript later.) Move them to (50, 3) and (50, 29), so they're flush with the left edge of the backg1 and backg2 movie clips. 8. To achieve the desired effect, we need to set up the server1Mask and
server2Mask graphics

so that they work as masks for the background

graphics beneath them. Locate the Server1Mask and Server2Mask layers, right-click on each, and select Mask (see Figure 3.6).

- 83 -

Figure 3.6. Convert the dynamic movie clips into masks. When the movie runs, only those portions of the Background graphics in Server1Background and Server2Background that are covered by the ServerAnimation graphics in Server1Mask and Server2Mask will be visible.

9. We now need to animate the two mask graphics so that they reveal
the appropriate portions of the Background graphics. Select the Actions layer, and, with the Actions Panel open, add the following code to the first frame:

10. Simple_Animation_Masking.fla Actions : 1 (Excerpt)


var server1load = 25; var server2load = 75; function animate (server, serverload) { server.onEnterFrame = function ()

- 84 -

{ if (this._width <= serverload) this._width += 2; }; } animate (server1Mask, server1load); animate (server2Mask, server2load); That's all the code we need to alter the rectangles to make the two bar graphs grow to their assigned lengths. Let's look at how it's done. First, we create two variables with values that represent (as a percentage) how much of the Background graphic we want to display for each server. The math is kept simple because the backg1 and backg2 graphics are exactly 100 pixels wide. The animate function takes a reference to one of our mask graphics and sets up an onEnterFrame event handler to increase its width by two pixels per frame up to a specified value. The code finishes by calling animate for each of the two mask graphics, passing each of the two server load values. Save your movie and preview it. Notice how the two masks grow to sizes dictated by the server1load and server2load variables. It's a pretty cool effect that you can easily include in your projects, creating bar

graphs or other visual displays of increases occurring over time.

- 85 -

AIM
Converting Angle Measurements.

PROGRAM Converting Angle Measurements


Create custom degToRad( ) and radToDeg( ) methods. The _rotation property of a movie clip object is measured in degrees. Every other angle measurement in ActionScript, however, uses radians, not degrees. This can be a problem in two ways. First of all, if you want to set the _rotation property based on the output of one of ActionScript's trigonometric methods, you must convert the value from radians to degrees. Second, humans generally prefer to work in degrees, which we must convert to radians before feeding to any of the trigonometric methods. Fortunately, the conversion between radians and degrees is simple. You should add the following degToRad( ) and radToDeg( ) methods to your Math.as file for converting from degrees to radians and vice versa. Note that they are attached directly to the top-level Math object, making them available throughout your movie.

- 86 -

AIM
Calculating the Distance Between the Two Points.

PROGRAM
Calculating Distances with the Math Class Using the Pythagorean theorem, Flash makes it possible for you to calculate the distance between two objects. This technique can be useful for creating novel interactions among interface elementsgraphics, buttons, or sounds whose reactions depend on their distance from the viewer's pointer, for example. You can also create games that have interaction based on the distance between objects and the player. A game in which the player uses a net to catch goldfish in an aquarium, for example, can use the distance between the goldfish and the net to model the behavior of the goldfish. Perhaps the closer the net comes to a goldfish, the quicker the goldfish swims away. The distance between any two points is defined by the equation a2 + b2 = c2 or c = square root (a2 + b2)

Static Calculations To get you acquainted with what Flash can do, well start off with simple, static calculations. By static, I mean equations that are hard coded, and do not require any input from the end user. All these calculations are performed with ActionScript, so well be doing a little coding. Lets go! 1.Start up Flash, and create a new movie.

- 87 -

2.Draw four dynamic textboxes on your stage. The dynamic property is set on the Properties panel.

3.

1124_image503 (click to view image)

4. Once that's done, give each textbox a Variable name. In this example,
Im using addition, subtraction, multiplication, and division as the Variable names. 1124_image1 (click to view image)

5.

Tip: When developing, you should always give objects (textboxes,

components, Movieclips, etc.) unique names. Otherwise, you run the risk of confusing Flash. This would be like having two brothers named John

- 88 -

and John, and having you mom say, "Tell John to wash the car and tell John to clean the bathroom. Avoid the confusion by giving every object a unique name. Well be using these variables to tell Flash were to display the results of our calculations.

6. In the timeline, create a new layer. Name the layer containing the
textboxes Calculations, and name the new layer Actions. We do this so that we can easily see which layer contains the code, and which layer contains the user interface.

1124_image2 (click to view image) 7. Now, lets apply the calculations. Select the first frame in your Actions layer. In order to give ourselves freedom to type what we wish, we need to set the Actions panel to Expert Mode. Choose Expert Mode from the Actions panel pop-up menu (at the upper right of the panel).

8.

1124_image3 (click to view image)

9. Now, input the following code:


addition = 1+1; subtraction = 5-2;

- 89 -

multiplication = 10*2; division = 100/5;

Now, an explanation of what this code does and why. There are four lines, and at the beginning of each is a Variable reference. Remember the Variable names we gave to the four textboxes? The first line starts with addition. This references our addition textbox. We then give an expression to which "addition is equal. The addition textbox will display the results of one plus one, the subtraction textbox will display the results of five minus two, etc. Publish your movie to see the results!
1124_image4 (click to view image)

- 90 -

AIM Formating Currency Amount. PROGRAM

Formatting Currency Amounts


Create a custom Math.currencyFormat( ) method. Unlike some other languages, such as ColdFusion, ActionScript does not have a built-in function for formatting numbers as currency amounts. That's the bad news. The good news is that it is not too difficult to create a custom method to format numbers as currency amounts. Flash Currency Conversion Service This application is an example of using Flash MX to communicate with a with a Web Service. By using a combination of the Load Vars Object, Flash MX Components, and a PHP Soap Toolkit - we can easily build applications such as these. About The web service that we are using provides us with the currency exchange rate between any two countries. What we are doing on the flash side is selecting two countries, country A and country B, entering an amount to convert - then sending those 3 values to a script. The script then looks up the current exchange rate between country A and country B and returns the value. We then multiply that value times the amount entered by the user to get the actual amount of Country B dollars for every dollar of Country A. This may sound a bit confusing - but is really only multiplying 2 values. By looking over the 'conversion.php' script, hopefully this becomes a bit more clear. To Use: The first thing you will need to do is look over the included fla file and read the comments and code. The newest concept to most of us will be using the Load Vars object to send and Load data. The Load Vars Object is not all that different from LoadVariables, this is realized when thinking of Movie Clips as Objects (which they are) and combining that more closely with a method to send and load data. If you where used to the Flash 5 XML object - you'll be right at home. One of the greatest things about the Load Vars object is that it makes working and thinking in terms of Objects instead of movie clips much more intuitive and clear. To send and recieve Soap based Objects - you will need to use one of the PHP Soap toolkits. We are going to use NuSoap for this example. We are

- 91 -

using NuSoap because of it's ease of use, only 1 file, and can be installed on any server/platform at no cost. This is great because we can build and consume Web services with no reliance on propritory software or restrictive licensing agreements. Basically NuSoap is a set of PHP class's that handles everything for you. To use this - we need to specify a couple of items in the client script, including the parameters to be sent, path to WSDL file, and the method to use. This is done in about 5 lines. And is shown below: // Include Nusoap.php file require_once('nusoap.php'); // Define needed parameters and put them in an array. $parameters = array( 'country1' => $currValue1, 'country2' => $currValue2 ); // Define new object and specify location of wsdl file. $soapclient = new soapclient('Currency.wsdl','wsdl'); // call the method and get the result. $result = $soapclient->call('getRate', $parameters); // Lets do some math, multiplies entered amount by the current conversion rate (result). $convertedAmount = ($amount * $result); // Print out a nice formatted return string and send it back to flash... print "&soapOut=$convertedAmount&"; <?php // Visit: http://www.flash-db.com/Board/ (the web services area) // for help and support on this. // Script by Jeffrey Hill, www.flash-db.com // Grab values from POST $currName1 = $HTTP_POST_VARS[currName1]; $currName2 = $HTTP_POST_VARS[currName2]; $currValue1 = $HTTP_POST_VARS[currValue1]; $currValue2 = $HTTP_POST_VARS[currValue2]; $amount = $HTTP_POST_VARS[amount]; if ($amount == "") { $amount = "NAN"; } // Include Nusoap.php file.

- 92 -

require_once('nusoap.php'); // Define needed parameters and put them in an array.. $parameters = array( 'country1' => $currValue1, 'country2' => $currValue2 ); // Define new object and specify location of wsdl file. $soapclient = new soapclient('Currency.wsdl','wsdl'); // call the method and get the result. $result = $soapclient->call('getRate',$parameters); // ----------------------------------------------------// We need to parse a couple of items so we get the correct dollar values. $symbol1 = split (" ", $currName1,2); $symbol2 = split (" ", $currName2,2); // Lets do some math, multiplies entered amount by the current conversion rate (result). $convertedAmount = ($amount * $result); // Print out a nice formatted return string and send it back to flash... print "&soapOut=<p align=\"center\"><font color=\"#ffffff\" size=\"+14\">$amount $symbol1[0] ($symbol1[1]) = <b>$convertedAmount</b> $symbol2[0] ($symbol2[1])</font></p>&converted=$convertedAmount $symbol2[0]\nRate: $result"; // ------End Script -------------// Author: Jeff Hill. ?> Flash Currency Conversion Client and Service: Client Flash and Code: Author: Jeff Hill Support/Help: http://www.flash-db.com/Board/ (web services area). NuSoap - PHP Soap Toolkit: Author: Dietrich Ayala Website: http://dietrich.ganx4.com/nusoap/ Please keep a Flash-db Logo or text link on the Flash Client App. Thanks.

- 93 -

Usage: You will need to download NuSoap from: http://dietrich.ganx4.com/nusoap/ Just download it - Unzip it and extract the file called 'NuSoap.php'. You can read over all the other files - but only the 'nusoap.php' file is needed. Be sure to read over the license agreement. This in combination with the client PHP code (conversion.php) is all you need. Place the two files in the same directory and your good to go. The Flash fla is set up - but you may want to change it around a bit for other use's or looks. It should be commented extensively, but if you need any help with it - visit us on the Flash-db forums at http://www.flash-db.com/Board/ About NuSoap: NuSOAP is a rewrite of SOAPx4, provided by NuSphere. NuSOAP is a group of PHP classes that allow developers to create and consume SOAP web services. It does not require any special PHP extensions, which makes it usable by all PHP developers, regardless of ISP, server or platform. Nusoap proves development of PHP web services as an alternative to .net and J2EE. (as if we needed any convincing!!).. If you are interested in a version of this Soap toolkit that has some extra functionality I would recommend: PEAR PHP toolkit: http://pear.php.net/package-info.php?pacid=87 Latest Version of Nusoap: http://cvs.sourceforge.net/cgibin/viewcvs.cgi/nusoap/lib/ The PEAR Soap Toolkit - may be a bit harder to use at first (which is the reason I'm using Nusoap for this example) but you will find some added features - that and it's updated much much more often. Extra big Thanks and Praise and everything else to: *** Dietrich Ayala *** - For NuSoap (which is also the base for part of the PEAR/CVS version!!! *** Shane Caraveo *** For working on the PEAR and CVS versions of SOAP for PHP!!!!

- 94 -

Bookmarks:

AIM
Converting Between Units of Measurement. PROGRAM

Converting Between Units of Measurement


You want to convert between Fahrenheit and Centigrade, pounds and kilograms, or other units of measurement. Write a custom method to perform the conversion and add it to the Math class. There are various systems of measurement used throughout the world. For example, temperature is commonly measured with both the Fahrenheit and Centigrade scales, and weight is commonly measured using both pounds and kilograms. For these reasons, you may need to convert from one unit of measurement to another.

- 95 -

AIM Determining points Along a Circle. PROGRAM

Determining Points Along a Circle


You want to calculate the coordinates of a point along a circle given the circle's radius and the sweep angle. Use the Math.sin( ) and Math.cos( ) methods to calculate the coordinates using basic trigonometric ratios. Finding the coordinates of a point along a circle is easy with some trigonometry. So let's look at the formulas you can use within your ActionScript code and the theory behind them. Given any point on the Stagea point we'll call p0, with coordinates (x0, y0)plus a distance and the angle from the horizontal, you can find the coordinates of another pointwhich we'll call p1, with coordinates (x1, y1) using some basic trigonometric ratios. The angle is formed between a conceptual line from p0 to p1 and a line parallel to the X axis, as shown in Figure 5-2. The opposite side (O) is the side furthest away from the angle. The adjacent side (A) is the side that forms the angle with the help of the hypotenuse (H). Figure 5-2. The angle, adjacent side, opposite side, and hypotenuse of a right triangle

- 96 -

If you know the distance between two points and the angle to the horizontal, as shown in Figure 5-2, you can calculate the x and y coordinates of the destination point using trigonometric functions. The trigonometric sine of the angle is equal to the ratio of the opposite side over the hypotenuse:

- 97 -

AIM Sorting or Reversing an Array. PROGRAM

We all know that the built-in Array sort method isn't the fastest around. The best way around the speed issue is to either build your own sorting method, or use someone else's. Prototype is a good place to start looking for code, and now you've brought that 261 milliseconds down to 127 with the qSort method, and even further down to 103 milliseconds with sortPInt. Still, I can't help but think that we can do better... So.. thinking a bit about the problem, I've come up with my own custom sort method. At it's heart it resembles the "Bin Sort" algorithm. I was able to reduce the sorting time down to 58 milliseconds (from the original 261). Sweetness. For starters, this sort method was built for a project I'm working on and thus only functions correctly under a given set of conditions. There are really only 2 conditions that need to be met for this sort to work. 1. All of the array elements must be integers (no decimals!) positive and negative integers will both work 2. The theoretical min and max values of the elements inside the array must be known If those conditions aren't met, then don't expect correct sorting results using my custom sort method. It's ok if the values you supply aren't the actual min and max values contained in the array - they only need to be the theoretical min and mix. But, the closer they are to the actual values the better performance you will see.

- 98 -

To start off, here is the code I'm using to test. What this does is generate an array of 1000 integers, ranging from -1005 to 1994. Where did these numbers come from? Why, I made them up for this example of course!
range = 3000; min = -1005; max = min + range - 1 // 1994 // create the numbers array and populate it numbers = new Array(1000); for (var i = 0; i < 1000; i++) { numbers[i] = Math.floor(Math.random() * range) + min; }

Note that declaring the array a fixed size and adding elements with the [] operator is faster (in this case, at least) than declaring a dynamic array (numbers = new Array()) and adding elements with "push" (numbers.push(newElement)). How much faster? Well, the dynamic array takes my computer around 51 milliseconds to build, whereas the fixed-length array takes only 45. This isn't a huge difference, but sometimes every little bit counts. Plus - Since we know we're going to have 1000 elements, why would we make the array dynamic anyway? That's a rhetorical question, for the most part. Next comes testing the built in sort method. Here we go:
// assuming numbers is built like the code snippet above start_t = getTimer(); numbers.sort(); trace("time: " + (getTimer() - start_t) + " ms"); trace(numbers);

- 99 -

With the above code snippet, you can see that the numbers aren't sorted correctly. Flash thinks that we're trying to sort strings instead of numbers (for example, 1403 comes before 304 because 1 is less than 3). So, we build a custom comparison function and run the test again:
function numCompare(a, b) { if (a < b) return -1 if (a == b) return 0; return 1; } start_t = getTimer(); numbers.sort(numCompare); trace("time: " + (getTimer() - start_t) + " ms"); trace(numbers);

That's better... but by golly that beast is slow. At least we got correct results this time, but let's see what we can do to improve the sort time. I repeated the same testing process for those 2 prototypes mentioned in the opening paragraph.... Copy the Array.prototype.qSort method to the frame replace "numbers.sort(numCompare)" with "numbers.qSort(0, numbers.length-1)" - this is faster, but not fast enough. Trying again.. copy the sortPInt method to the frame, and change the sorting line to "numbers.sortPInt()" - again, a little bit faster, but still not quite fast enough. Note that this sort only takes positive integers, so you'll need to change the min value to a positive integer for the sort to work correctly. Finally, get fed up and write your own custom sort method. Copy the code below, and then replace the sort call with - 100 -

"numbers.customSort(min, max)". Min is the smallest possible value in the array, and max is the largest possible value in the array. Note that these variables were defined right about the for loop that populates the numbers array. Also note that these are the theoretical min and max.. and may not actually be the min and max elements contained in the array.
// Darron Schall // 11/07/03 // pre: min and max are the theoretical min and max values // contained in the array. the array contains only integers. // post: the array will be sorted in ascending order Array.prototype.customSort = function(min, max) { var i; var bins = new Array(max-min+1); var binvalue; // distribute array to bins i = this.length; while (i--) { binvalue = this[i]-min; if (bins[binvalue] == undefined) { bins[binvalue] = 0; } bins[binvalue]++; } // rebuild - this may see some speed gains // by making the array fixed-length instead // of dynamic var tmp = new Array(); i = bins.length; while (i--) { if (bins[i] != undefined) { while (bins[i]--) { tmp.push(i);

- 101 -

} } } // reconstruct this from tmp, reversing the order i = this.length; while(i--) { this[this.length-i-1] = tmp[i]+min; } }

As stated before, my customSort method takes only 58 milliseconds to execute on my computer. Considering the built-in method takes 261 milliseconds, I would call this sort algorithm a success in this scenario. Of course, my custom sort may not always be the fastest depending on the number of elements in the Array. It seems to really outperform when the integer array to sort is large. Read on for an explanation of my algorithm... Here's a quck explanation about how the sort works. First, we declare a "bins" array big enough to have 1 position for every element ranging from min to max. In Flash, when you define an array like this without initializing any of the values, they all default to "undefined," which will be important later. Second, we loop over every element in the original array and determine the index it has in the bins array. We then mark that index as being in use (by incrementing it's value). If there are duplicate numbers in the array, then the value at the index representing the number will be the number of elements sharing that number value. The above is slightly confusing. Hopefully a quick example can illustrate the magic a little clearer:
// if num_array looks like this... num_array = [6, 1, 0, 1];

- 102 -

// bins would look like this: bins = [1, 2, undefined, undefined, undefined, undefined, 1];

See how the element in num_array is used as an index in bins, and that the element at the index in bins is the number of times that index number appears in num_array? Probably not... but think about it some more, the above is the trickist part. Since the number 1 is repeated 2 times in num_array, bins[1] = 2. There is no number 2 in num_array, so bin[2] is undefined. There is only one number 6, so bins[6] = 1. Get it now? I hope so... Ok, so the bins array is populated as described above. Now we just need to loop through it and reconstruct an array out of it. I know I said before that using dynamic arrays was bad if we know the number of elements the array will have, but it was easier (read: less time consuming for me) in this situation to just make a temporary dynamic array to rebuild with the data from the bins array. We loop through the bins array and if the value at the index is not undefined (meaning the original array contained a number equal to the index value), we push the index on the tmp array however many times the value appeared in the original array. This leaves us with a temporary array in reverse order. The final step is to replace "this" with "tmp" and reverse the order of the array, which is what the last while loop does. I apologize if my explanation is a little confusing. The algorithm itself isn't too hard to follow once you can get over how the "bins" array works. I hope that in reading this you've been inspired to always look for a better approach to solving problems. By not being satisfied with the built in sort, I was able to shave over 200 milliseconds off of the sorting time. There are probably even faster methods to sort an array of positive integers, but I'm pleased with the results I was able to achieve.

- 103 -

Note that all of these times are specific to my computer. Your execution times may vary. A possible improvement to my custom sort is to try and reduce the size of the bins array needed in memory, and to try and remove the tmp array at the end completely. As always, let me know if you find this method useful, or if you use my code as a building block for your own custom sorting methods!

AIM Implementing a Custom sort. PROGRAM

Custom Sorting a Flash Form DataGrid

I found tons of posts across the web on how to do custom sorts of a dataGrid in Flash, but nothing about how to do it within CFFORM. It took me a little while to figure it out based on the Flash instructions, so I figured I'd write up a quick how-to. Just like in Flash, the dataGrid object has a headerRelease event that is fired when you click on the column headers. The tricky part, however, is turning off the built-in sorting. I've written up some example code, but I didn't get all fancy with building in a query or whatnot since the intent is to show what the code looks like and where to put it. *FLASH Weirdness* For some reason, dataGrid indexes start with 1, and not 0. While natural to us CF folk, Flash usually starts with index 0. Example Code:

- 104 -

<cfform name="myForm" onload="formOnLoad()" format="Flash"> <cfformitem type="script"> public function formOnLoad():Void{ <!--- put the dataGrid in this scope ---> var myGrid:mx.controls.DataGrid = myGrid; <!--- custom grid sorting defaults ---> _root.lastColumnSorted = ""; _root.sortDesc = true; <!--- kill the default sort functionality for all columns ---> myGrid.getColumnAt(2).sortOnHeaderRelease = false; <!--- creat the listner object ---> var sortListener:Object = {}; <!--- do the meat & potatoes ---> sortListener.headerRelease = function(event):Void { if (event.columnIndex == 2) { if (_root.lastColumnSorted == myGrid.getColumnAt(event.columnIndex).columnName) { <!--- if this column was previously sorted, sort it in the opposite direction ---> if (_root.sortDesc) { _root.sortDesc = false; } else { _root.sortDesc = true; } } else { _root.sortDesc = false; } } _root.lastColumnSorted = myGrid.getColumnAt(event.columnIndex).columnName; <!--- fire off the function that sorts the data. this example used remoting to re-populate the grid ---> _root.myGrid_RefreshData(); } myGrid.addEventListener("headerRelease",sortListener); } </cfformitem> <cfgrid name="myGrid"> <cfgridcolumn name="StoreName" header="Store"> <cfgridcolumn name="StoreNumber" header="Store ##"

- 105 -

type="numeric" dataalign="center" width="80"> <cfgridcolumn name="City" header="City" width="75" dataalign="center"> <cfgridcolumn name="State" header="State" dataalign="center" width="55"> </cfgrid> </cfform>

AIM Creating a Text Field. PROGRAM Creating Text Fields In this section, we'll go over the basic ways to create and use all three types of text fields manually, and then we'll go over how to create a couple of them with ActionScript. The basic way to manually create a text field is to select the Text tool from the toolbar (T on the keyboard) and click and draw the text fields on the stage. TextField.embedFonts Availability Flash Player 6.

- 106 -

Usage my_txt.embedFonts:Boolean Description Property; a Boolean value that, when true, renders the text field using embedded font outlines. If false, it renders the text field using device fonts. Example In this example, you need to create a dynamic text field called my_txt, and then use the following ActionScript to embed fonts and rotate the text field. The reference to my font refers to a Font symbol in the library, with linkage set to my font. var my_fmt:TextFormat = new TextFormat(); my_fmt.font = "my font"; this.createTextField("my_txt", this.getNextHighestDepth(), 10, 10, 160, 120); my_txt.wordWrap = true; my_txt.embedFonts = true; my_txt.text = "Hello world"; my_txt.setTextFormat(my_fmt); my_txt._rotation = 45; Creating scrolling text You can use the scroll and maxscroll properties of the TextField object to control vertical scrolling and the hscroll and maxhscroll properties to control horizontal scrolling in a text block. The scroll and hscroll properties contain a number that specifies the topmost visible line in a text block; you can read and write these properties. The maxscroll and maxhscroll properties contain a number that specifies the topmost visible line in a text block when the bottom line of the text is visible in the text block; you can only read these properties. To use the scroll property to create scrolling text: 1. Assign an instance name to the text field that will contain scrolling text. Do one of the following:

- 107 -

Use the Text tool to create a text field on the Stage. Assign the text field an instance name in the Property inspector.

Use ActionScript to create a text field dynamically with the createTextField method. Assign the text field an instance name as a parameter of the createTextField method.

2. Create an Up button and a Down button or select Window > Other Panels > Common Libraries > Buttons and drag buttons to the Stage. You will use these buttons to scroll the text up and down. 3. Select the Up button on the Stage.

In the Actions panel, select the Built-in Classes category, then select the Movie category, then select the TextField category, and then select the Properties category. Finally, double-click the scroll property to add it to the Script pane.

4.

5. Replace instanceName with the instance name of the text field you want to scroll. 6. Increment the scroll property by 1 to scroll the text up. The code should look like this: 7. instName.scroll += 1; 8. Select the Down button on the Stage. 9. Repeat steps 4 and 5.

10. Decrement the scroll property by 1 to scroll the text down. The code should look like this: 11. instName.scroll -= 1;

AIM Making a Password Inputfield. PROGRAM

- 108 -

Part 1

Previous | Next >>

In order to use password protection, youll need first a scene, then an input field. Once youve set your scene, then draw a new text field with the Text Tool. Set the type to Input Text, using the dropdown in the Properties pane. An Input Text field isnt like a normal text field; instead of displaying text we specify as part of the movie, it exists so that the user can enter text. In this case, theyre going to enter password text so that our Flash movie can check to see if its the correct value.

<< Previous | Next >>

With the Input Text field selected, select Password from the display type dropdown (usual options are Single Line, Multiline, and Multiline no wrap). This is an added security option that causes all characters entered to be displayed as asterisks (*) instead of as alpha characters.

- 109 -

Click the icon to display the bounding box (the little box with horizontal lines), and then in the Var field, type the name of a variable by which youll reference the value of your password. Dont confuse this with an instance name; the instance name would be referring to the actual text box itself, but the variable is used to refer to the text entered into the input field. So if I typed purple monkeys into the input field, then password=purple monkeys. Part 3

<< Previous | Next >>

Once you have the password input screen, youll need another screen to display if they enter the incorrect password. On a separate frame from your password input screen, copy all of your graphics, etc. and then add text telling the user (in whatever words you choose, but lets try to behave here) that theyve entered the wrong password. Then create a Try Again button; this can be a graphic or text, whatever you choose.

- 110 -

Part 4

<< Previous | Next >>

Right-click the Try Again button, select Actions, and then assign the following script to the button: on (release, keyPress <Enter>) { gotoAndStop(1) ; password = ; } What this does is tell Flash that when the user clicks on the Try Again button or presses the Enter key, the movie should go back to frame one (the password input screen) and stop. It should also reset the value of password to nothing, so that it doesnt auto-populate mistakenly with the incorrect password (or the correct one).

- 111 -

Part 5

<< Previous | Next >>

Now, if youre working on a real application/movie/game/website/etc., then youll have another scene that contains all of your actual content, and youd normally direct the user there if theyre successful in entering the password. In this case, however, Ive created just a simple (if snarky) correct screen on another keyframe, just displaying a message to tell the user that theyve entered the correct password.

- 112 -

Part 6

<< Previous | Next >>

Because each frame is a static screen and it should remain visible until the user takes some direct action, make sure to insert a stop on each of your keyframes.

- 113 -

Part 7

<< Previous | Next >>

On your timeline, right-click on the frame containing your password entry screen, and select Actions to open the Actions pane. Part 8

<< Previous | Next >>

- 114 -

Switch to Expert Mode so that you can type freely, and then below your stop, enter password = ; (with the name of your variable in your input field substituted out for password). This makes sure that when the movie loads at frame one, the value of password is set to nothing, and thus isnt retaining anything from past attempts. Part 9

<< Previous | Next >>

Now well need to write the actual script that compares the value of the input, but first well need something to attach it to. Create a button near to your password input field; you can add the text Submit to let the user know that its clickable, or hide it by making it the same color as your background or turning it into an invisible hotspot button. Right-click on the button and open the Actions panel. Part 10

<< Previous | Next on (release, keyPress <Enter>) { if (password eq aikotoba) { gotoAndPlay(2) ; password = ; } else { gotoAndPlay (3) ; password = ;

- 115 -

} }

That looks like a lot, but its not. Its an function that tells Flash to use an if statement the mouse clicks the Enter key is pressed. The if statement checks to see what the characters entered for password are, and compares them to a value set by you: the actual correct password, inside the quotes. If the two are the same, then Flash will go to the access granted frame/scene (frame two, for me). If not, the else statement redirects to the wrong answer, try again screen. In both instances, the password is reset to nothing, so that its not carrying the entered string around. In mine, aikotoba is the correct password; if the user enters aiko, then password=aiko. Flash asks itself, does aiko equal aikotoba? and, when the answer is no, shunts them off to the wrong answer screen.

- 116 -

TEXT BOOKS:
1) Fundamentals of Multimedia by Ze-Nian Li and Mark S. Drew

PHI/Pearson Edition. 2) Essentials ActionScript 2.0, Colin Moock, SPD O.REILLY.

REFERENCES:
1) Digital Multimedia, Nigel chapman, Wiley-Dreamtech.
2) Macromedia Flash MX Professional 2004 Unleashed, Pearson.

3) Multimedia and communications Technology, Steve Heath, Elsevier(Focal Press). 4) Multimedia Applications, Steinmetz, Nahrstedt, Springer. 5) Multimedia Basics by Weixel Thomson. 6) Multimedia Technology and Applications, David Hilman, Galgotia. 7) Action Script Cookbook, Joey Lott, SPD-Oreilly. 8) Flash MX Action Script for designers, Doug Sahlin, Dreamtech Willey.
9) Flash MX professional 2004 Unleashed, David Vogeleer and Mattheww

Pizzi, Pearson edition.

- 117 -

Vous aimerez peut-être aussi