Starbuzz

**I. Introduction**
Coffee break. Even an evil genius needs a caffeine fix ... especially an evil genius. But Dr. Horrible is on a budget. He needs you to write a //screen scraper// that checks Beans 'r Us for the current price of coffee and buys in bulk when the price drops below $4.75 a pound.



**II. Learning Objectives**
//**Knowledge**// //**Skills.** By the end of the session, you'll be able to...//
 * Screen scrape - Input can come from the web, not just from a user. In Flash, you can use a URLLoader to load the html of a web page.
 * Try-catch - a try-catch block is a control statement that allows you to //try// to execute a set of code, and, if that code throws an exception, to //catch// the exception and execute a second set of code.
 * Timer - A timer allows you to execute a set of code after a given delay, or to execute a set of code repeatedly on a set interval.
 * Polling - When you repeatedly query a data source for updates, it's called polling. You can use a timer and URLLoader to poll a website for changes.
 * Initialize - When a Flex web or desktop application starts, it throws an //initialize// event. You can use the //initialize// property of the MXML (web) Application or (desktop) WindowedApplication tag to call a function when the application starts.
 * load an web page for screen scraping
 * use a timer to poll a web source
 * use String methods
 * use a try-catch block

**III. Concepts**
Input can come from the web, not just from a user. In Flash, you can use a URLLoader to load the html of a web page. code format="actionscript3" private function checkPrice(event:Event):void{ var urlLoader:URLLoader = new URLLoader; urlLoader.addEventListener(Event.COMPLETE, checkPriceHandler); var request:URLRequest = new URLRequest("http://www.beans-r-us.biz/prices.html"); urlLoader.load(request); }
 * Input from the web**

private function checkPriceHandler(event:Event):void{ var loader:URLLoader   = URLLoader(event.target); var beanPageText:String = loader.data; //do something with the result ... } code The basic steps are to create a URLLoader, add an event listener to listen for the result of the query, create a URLRequest that defines the web source, and then load the request into the URLLoader. The even listener will then receive the event and you use a URLLoader to get the data out of the event.

Of course, when you call urlLoader.load, the web query may not succeed for many reasons. Your may be disconnected form the internet, the webpage may not exist, you may have a typo in your url, etc. When urlLoader.load has a problem, it will throw one of several types of //Exceptions//. If you run the code above and it throws an exception, your program will //crash// and display a nasty error message.

Exceptions like this are common, and your program shouldn't crash under normal circumstances like an internet connection being dropped. Flash and other modern languages provide a control statement called //try-catch// to deal with this situation.

A try-catch block is a control statement that allows you to //try// to execute a set of code, and if that code throws an exception, to //catch// the exception and execute a second set of code. code format="actionscript3" private function checkPrice(event:Event):void{ var urlLoader:URLLoader = new URLLoader; urlLoader.addEventListener(Event.COMPLETE, checkPriceHandler); var request:URLRequest = new URLRequest("http://www.beans-r-us.biz/prices.html"); try { urlLoader.load(request); } catch (error:Error) { trace("Unable to load requested document."); }     } code The code above executes the urlLoader.load statement within a try block. If the load function runs smoothly, then the //catch// block will be skipped. However, if the //load// function throws an exception, then the code inside the //catch// block will be run. In this case, the program will just print out a debugging message (rather than crashing and displaying an error message).
 * Try catch**

code format="actionscript3" private var _urlLoader:URLLoader; private var _timer:Timer;
 * Polling with timers**
 * When you want to repeatedly query a data source for updates, it's called polling. You can use a timer and URLLoader to poll a website for changes. **

private function startup:void{ _urlLoader = new URLLoader; _urlLoader.addEventListener(Event.COMPLETE, checkPriceHandler); _timer = new Timer(5000, 0); _timer.addEventListener(TimerEvent.TIMER, checkPrice); _timer.start; }

private function checkPrice(event:Event):void{ var request:URLRequest = new URLRequest("http://www.beans-r-us.biz/prices.html"); try { _urlLoader.load(request); } catch (error:Error) { trace("Unable to load requested document."); }   } code The //startup// function constructs the URLLoader and a //timer// that will repeatedly call the checkPrice method. The first timer line says to create a timer that dispatches a special timer event every 5000 milliseconds infinitely. The second timer line says that whenever the TimerEvent.TIMER is dispatched by timer, to call the checkPrice method. The third timer line actually starts the timer running. Once this code is run, the checkPrice method will be called every 5 seconds.


 * Note:** Polling is generally considered an inefficient, but sometimes necessary, technique. For example, it would be better if you could tell your data source once that you want to be informed of any changes, and then just wait for the web source to tell you went something has changed. That is the event listener model. Using polling requires you to send lots of messages which if sent too frequently can overload your data source, or if sent too infrequently doesn't allow you to update quickly. However, in this case, your data source doesn't allow you a means to register as a listener for changes, so polling is your only option. The same situation applies to user input.

**Initialize** When a Flex web or desktop application starts, it throws an //initialize// event. You can use the //initialize// property of the MXML (web) Application or (desktop) WindowedApplication tag to call a function when the application starts. You'll see an example of this in the program you'll be writing.

The String class comes with a number of useful methods for manipulating text. You can think of String as an array of characters. For example, for the string "dog", the character at position 0 is 'd', at position 1 is 'o', and position 2 is 'g'. String provides methods for searching, slicing and dicing that array. For example: code format="actionscript3" var pet:String = "Sara is best dog in the world";
 * String methods**

var dogIndex:int = pet.indexOf("dog");                  //index will be 9; var dog1:String  = pet.slice(dogIndex, dogIndex + 3);  // dog1 will be set to "dog" var dog2:String  = pet.substr(dogIndex,  3);           // dog2 will be set to "dog" code If you are going to be writing any programs that require processing of text, you will definitely want to get familiar with strings. You can check out the [|developer's guide on Strings] to get a good understanding of strings and the Flex language reference describes all of [|String's methods]. There is also a very powerful approach to finding patterns in strings called regular expressions. You can learn more about this in the [|developer's guide on regular expressions].

**IV. Scenario**
Dr Evil wants a Bean price ticker that checks beans-r-us every 5 seconds and tells him when to buy beans.

**Bean Price Ticker**

**Use Case** 1. User starts bean price ticker 2. Ticker checks price every 5 seconds 3. Ticker displays price and advises to buy if prices is under 4.75 4. If the prices is below 4.75, stop checking, otherwise check again

**V. Program**
Here is the bean price ticker. code format="actionscript3"       

 <![CDATA[

private var _urlLoader:URLLoader; private var _timer:Timer;

private function startup:void{ _urlLoader = new URLLoader; _urlLoader.addEventListener(Event.COMPLETE, checkPriceHandler); _timer = new Timer(5000, 0); _timer.addEventListener(TimerEvent.TIMER, checkPrice); _timer.start; }

private function checkPrice(event:Event):void{ var request:URLRequest = new URLRequest("http://www.beans-r-us.biz/prices.html"); try { _urlLoader.load(request); } catch (error:Error) { trace("Unable to load requested document."); }           }

private function checkPriceHandler(event:Event):void{ var loader:URLLoader    = URLLoader(event.target); var beanPageText:String = loader.data; displayPrice(beanPageText); }

private function displayPrice(beanPageText:String):void{ var where:int            = beanPageText.indexOf(">$"); var price:String        = beanPageText.substr(where + 2, 4); var time:Date            = new Date;

_price        = "$" + price + "."; _checkTime    = time.hours + ":" + time.minutes + ":" + time.seconds ;

if(int(price) > 4.74){ _recommend = "Price is too high"; }else{ _recommend = "Buy! Buy! Buy!"; _timer.stop; }           }

]]>   

<s:BorderContainer x="0" y="0" width="227" height="116"> <s:Label x="62" y="11" text="Bean Price Ticker" fontWeight="bold"/> <s:HGroup x="13" y="40" width="200" height="51"> <s:VGroup width="96" height="51"> <s:Label text="Price:" width="81"/> <s:Label text="Last check:" width="69"/> <s:Label text="Recommend:" width="82"/> </s:VGroup> <s:VGroup width="97" height="51"> <s:Label text="{_price}"    width="110" textAlign="left"/> <s:Label text="{_checkTime}" width="110" textAlign="left"/> <s:Label text="{_recommend}" width="110" textAlign="left"/> </s:VGroup> </s:HGroup> </s:BorderContainer> </s:WindowedApplication> code

<span style="font-size: 1.3em; margin: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 5px;">**VI. Self-explain (Try it!)**
Go over each line program and explain out loud to yourself what it does. If you can't figure out the what the line does, write down a question to ask.

<span style="font-size: 1.3em; margin: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 5px;">**VII. Program Walkthrough (Try it!)**
To write the Bean Price Ticker program, do the following:
 * Create a new Flex Project, this time it should be an desktop (AIR) application
 * Create the Bean Price Ticker interface
 * Take a look at the page: http://www.beans-r-us.biz/prices.html, this is the html you are trying to retrieve
 * Create a //checkPrice// function that uses a URLLoader to get the html of prices.html page
 * Create an //checkPriceHandler// event listener that for the URLLoader to extract the html from the URLLoader's request
 * Just for testing, use the //initialize// property in your application tag to call your //checkPrice// function when the application starts
 * Test your program to see if your //checkPrice// functions are working
 * Write a function to //displayPrice// function that takes the html of the prices.html page, extracts the information from the html and displays it in the interface
 * Test your program to make sure it's working
 * Now that your screen scraper is working, use a timer to make it check the price every 5 seconds
 * Modify your checkPriceHandler so that it will stop the timer if the bean prices is below $4.75

<span style="font-size: 1.3em; margin: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 5px;">**VIII. On your own (Try it!)**
Try writing a program that polls the web or the user for input intermittently. For example, you can write your own screen scraper. You could also write a program that asks the user to rate a program, or that tests a student's knowledge every few minutes. While possibly annoying to the student/user, this allows you to gather process data about learning or usability.

You might also be interested in using an [|alert box].

<span style="font-size: 1.3em; margin: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 5px;">IX. Check yourself
Here are some questions to check your knowledge:
 * How would you extract the names from these two strings: "My name is Jack" and "My name is Jill"?
 * How would you write a function that prints the html of a web page, and prints a debug message if the html can't be downloaded?
 * How would you poll a user input the current interest in a program from 1-10

<span style="font-size: 1.3em; margin: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 5px;">**XI. References**
The Starbuzz program based on a Python program from first Head First Programming