Creating the Web Store Shopping Cart

Team-Fly    

Macromedia® DreamWeaver® MX Unleashed
By Matthew Pizzi, Zak Ruvalcaba
Table of Contents
Chapter 31.  Adding Shopping Cart Functionality


This chapter focuses on the UltraDev Shopping Cart behavior. Although the name may sound deceptive, it is still very much a part of the Dreamweaver MX framework. Not only is it still supported under Dreamweaver MX, but it functions as well under UltraDev 4 as it does with Dreamweaver MX. The next few sections will provide you with a brief description of shopping cart technologies, an overview of the Shopping Cart behavior, and finally, integrating the Shopping Cart behavior with the Web Store application.

What Is a Shopping Cart?

The term shopping cart has been thrown around for a few years now. But what exactly is a shopping cart? We know a shopping cart to be the basket on wheels that you push around at a grocery store. Think about why you use the grocery store shopping cart. You go to your local grocery store, you push around the cart and add items from shelves as you see fit. When your shopping cart is full or you decide that you are finished shopping, you push your shopping cart all the way to the front of the store to the checkout counter. At the checkout counter, you proceed by providing your debit card, cash, or check to the cashier, finish the transaction, and off you go. Sound familiar? The Web is no different; rather than a physical shopping cart, you are provided with a virtual shopping cart, which is little more than a cookie, user session, or temporary array. A virtual table, if you will, then takes items that users request from the database and stores them into a temporary location (cookie, session, array) until you are ready to check out. If you decide that you want another item or more of the same item, you keep adding to the cart. Similar to the grocery store checkout counters, virtual checkouts enable you to enter your credit card information for purchase, but rather than your physically walking away with the items, they are conveniently mailed to your doorstep.

Most people think of shopping carts in the terms of the preceding example. But in fact, the same methodology is used in Web sites such as Microsoft's Clip Art Gallery, MP3.com, or Photodisc. These Web sites use the same idea of a shopping cart, but rather than purchasing the items within your shopping cart, you simply download them. Think of online shopping carts as a virtual table that stores information that the user requests for downloading or purchasing.

The UltraDev Shopping Cart

The UltraDev Shopping Cart is the perfect example of Dreamweaver MX's flexibility and extensibility. It shows how one man can create a single set of behaviors that virtually eliminates dozens of hours of development time. Written purely in JavaScript by Rick Crawford, the UltraDev Shopping Cart consists of some powerful behaviors that enable you to create and manipulate merchandise within your Web application. Aside from the UltraDev Shopping Cart behavior, the UltraDev Shopping Cart behavior set consists of the following behaviors:

  • Add to Cart Via Form Enables the user to select a form object within a page to manually insert an item into the shopping cart.

  • Add to Cart Via Link Enables the user to select a link within a page to manually insert an item into the shopping cart.

  • Repeat Cart Region Similar to the Repeat Region behavior, the Repeat Cart Region repeats a table with multiple contents.

  • Update Cart Updates items within the cart via a form object contained within the shopping cart page.

  • Save Cart to Table Enables the user to save the order to a database table so that an administrator can later look through orders received for a particular day and mail merchandise out accordingly. This is where the orders table will come into play.

  • Get Unique ID from Table Enables the cart to dynamically retrieve a unique ID from a database table.

  • Empty Cart Selecting a link within the page empties the cart of its contents.

  • Redirect if Empty Redirects the user to a different page if the shopping cart is empty.

The UltraDev Shopping Cart's functionality begins with the UltraDev Shopping Cart behavior. Very similar to a recordset, the UltraDev Shopping Cart allows for dynamic text binding within form objects, tables, and so on. The UltraDev Shopping Cart behavior is created in either the Server Behaviors or the Bindings panel, again similar to the recordset. Shopping cart items appear within the drop-down, available from the (+) icon, along with the capability to bind the number of items within the cart, the sum of the quantity of all items within the cart, and the sum of the prices of all of the items within the cart.

NOTE

The good part about the UltraDev Shopping Cart is it's free. The bad part about the Ultradev Shopping Cart is that it was written for the first release of UltraDev and not Dreamweaver MX. To get some of the features to work correctly with Dreamweaver MX, modification to the code will be limited but required. The newest version of the UltraDev Shopping Cart, the UltraDev Shopping Cart II, works with newer versions of Dreamweaver and includes more functionality, but it costs money.


Now that you have a firm understanding of what constitutes the UltraDev Shopping Cart, let's go over the installation process.

Installing the UltraDev Shopping Cart

Like most, if not all Dreamweaver MX extensions, you can obtain the UltraDev Shopping Cart extension for free from the Macromedia Dreamweaver Exchange (http://dynamic.macromedia.com/bin/MM/exchange/main.jsp?product=ultradev). To obtain and install the necessary files, follow the steps outlined next:

  1. Navigate to the Dreamweaver UltraDev Exchange. If you have not done so by now, you will be required to obtain a Macromedia user ID and password. After you obtain the proper user ID and password, you will be asked to log in. Successful login will redirect you to a personalized page, as shown in Figure 31.1.

    Figure 31.1. Log in with your user ID and password to access the personalized site.

    graphics/31fig01.jpg

  2. Select the e-commerce extensions from the drop-down menu. Halfway down the second page, you will see the selection for the UltraDev Shopping Cart as well as the UltraDev Shopping Cart II. Download the UltraDev Shopping Cart by selecting the link as shown in Figure 31.2.

    Figure 31.2. Select the UltraDev Shopping Cart extension.

    graphics/31fig02.jpg

    TIP

    To eliminate any coding errors, you should download and install the UltraCart Patch for UD4 available just above the UltraDev Shopping Cart. This guarantees that the UltraDev Shopping Cart will run smoothly.

  3. After you select the appropriate extension, you will be presented with a choice for the type of computer you are using. Select PC, as shown in Figure 31.3.

    Figure 31.3. Select the extension based on the type of computer you are using.

    graphics/31fig03.jpg

  4. After the Save As dialog box appears, navigate to the Downloaded Extensions folder within your Dreamweaver MX program folder and click Save, as shown in Figure 31.4.

    Figure 31.4. Save the extension to your Downloaded Extensions folder within Dreamweaver MX.

    graphics/31fig04.jpg

  5. Your last step is to find that MXP file within the Downloaded Extensions folder. Double-click it to install it, using the Macromedia Extension Manager as shown in Figure 31.5.

    Figure 31.5. Install the Shopping Cart extension by double-clicking the MXP file, which is located in the Downloaded Extensions folder.

    graphics/31fig05.jpg

Integrating the Shopping Cart with the Web Store

Now that the UltraDev Shopping Cart has been installed, you can access it from either the Server Behaviors panel or the Bindings panel. The next few sections will go over the UltraDev Shopping Cart in more detail as it relates to the Web Store application. You can begin by opening Dreamweaver MX if you have not already done so. Choose the plus sign (+) icon from either the Server Behaviors panel or the Bindings panel to reveal the UltraDev Shopping Cart, as shown in Figure 31.6.

Figure 31.6. Select the plus sign (+) icon to reveal the newly installed UltraDev Shopping Cart.

graphics/31fig06.jpg

Building the Web Store Shopping Cart

Oddly enough, the Web store shopping cart will be built starting with the viewcart.asp page. The reason for this is simple: first to demonstrate how the UltraDev Shopping Cart behavior is utilized and second because it is the only page that will use the binding features within it. You can begin building the Web store shopping cart by following the steps outlined next:

  1. Create a new page by selecting New from the File menu. Navigate to the Advanced tab and select the WebStore template.

  2. Immediately save the page as viewcart.asp.

  3. Add the Shopping Cart behavior by selecting the UltraDev Shopping Cart from the Bindings panel. The UltraDev Shopping Cart dialog box appears. The UltraDev Shopping Cart dialog box enables you to configure the following options:

    • Cart Name You can give your shopping cart any name that you want. Like a recordset, it's best to name the cart something relevant to your site.

    • Cookie Expiration To store the information that users place within their carts, a cookie is written to the user's computer. You can set the number of days to store the cookie or select 0 for none. For the time being, select 0. This guarantees that when the browser is closed, the user's information will not be stored. It is important to note that by setting the number of days to store the cookie, you are essentially allowing users to come back and still have the same items inside their carts. The cart will not be empty until either the user physically empties it or the cookie expires.

    • Shopping Cart Columns You can define the columns that the cart will use to store data. By default, ProductID, Quantity, Price, and Total cannot be deleted. These are functions that are used by the Shopping Cart behavior.

    • Column Name You can edit the name of any column that you add.

    • Compute By You can set how the UltraDev Shopping Cart will compute certain columns. For instance, the Total field multiplies the Price by the Quantity column to obtain a result. You can set these computations by hand using this selection.

  4. When you are finished configuring the dialog box, the result should look similar to Figure 31.7.

    Figure 31.7. Configure your cart accordingly.

    graphics/31fig07.jpg

  5. Notice that the names of the columns match the Products table almost exactly. These columns will eventually be read from the dynamic text that is inserted within the viewcatalog.asp page.

  6. Now that you have created the shopping cart, you are ready to begin building the table that will display the dynamic data. Insert the text View Cart in place of the Header editable region.

  7. Insert a table with three rows and five columns. Insert the captions Product #, Name, Quantity, Price, and Total. Select all the captions and make them bold. The result is shown in Figure 31.8.

    Figure 31.8. Create a new table that will display the items within the cart.

    graphics/31fig08.jpg

  8. You are now free to drag the columns from the shopping cart into the appropriate table cells, as shown in Figure 31.9.

    Figure 31.9. Drag the shopping cart columns into the appropriate cells within the table.

    graphics/31fig09.jpg

  9. To calculate the grand total of all of the items within the cart, merge the two bottom-right cells, add the caption Grand Total, and drag the sum[total] column into the table cell. The result is shown in Figure 31.10.

    Figure 31.10. Create a cell for the grand total and drag the column from the shopping cart into it.

    graphics/31fig10.jpg

  10. You can also format how the total appears within that cell by selecting the drop-down arrow from the sum[Total] column within the shopping cart. Select Currency, as shown in Figure 31.11.

    Figure 31.11. Format the text within the cell to a currency data type.

    graphics/31fig11.jpg

Although it doesn't seem like much was done, the majority of the work was, in fact, accomplished. The next few sections walk you through other options that are available within the shopping cart.

Repeating Cart Regions

Similar to bindings fields within a recordset, the UltraDev Shopping Cart will display only the first item added unless you allow for regions to repeat. You can insert the Repeat Cart Region to accomplish this task. To insert the Repeat Cart Region behavior, follow these steps:

  1. Select the entire second row of the table within the viewcart.asp page and select the Repeat Cart Region behavior from the UltraDev Shopping Cart submenu, as shown in Figure 31.12.

    Figure 31.12. Insert the Repeat Cart Region to allow for records to repeat.

    graphics/31fig12.jpg

  2. With the Repeat Cart Region behavior inserted, it may be a good idea to switch over to code/design view to make sure that the For…Next Loop was inserted correctly. These two lines of code loop through all the items within the cart, dynamically creating rows until there are no more items left to display. The code should resemble the code in Figure 31.13.

    Figure 31.13. Check the code to make sure the loop was added correctly.

    graphics/31fig13.jpg

Emptying the Cart

As you may have guessed, after users begin filling their carts with items, it may become necessary to enable them to remove those items. Fortunately, by using the Empty Cart behavior, you can provide this functionality to your users. To insert the Empty Cart behavior, follow the steps outlined next:

  1. Place your cursor in the second cell of the last row and insert a link with the text Empty Cart.

  2. Select the Empty Cart behavior from the UltraDev Shopping Cart submenu, as shown in Figure 31.14.

    Figure 31.14. Insert the Empty Cart behavior.

    graphics/31fig14.jpg

  3. The Empty Cart dialog box appears. The link should be prepopulated for you because you selected it prior to inserting the behavior. You can also specify a redirect URL. For now, simply redirect the user to the viewcatalog.asp page. You can also include a parameter to be passed on to the querystring to alert the user that the cart is empty.

  4. Select OK.

Making Quantities Editable

You've probably noticed that the quantities are currently hard coded, meaning that when the user adds an item to the cart, it automatically inserts a single item. You can allow users to modify how many items they would like in their carts by changing a text box value. Rather than binding the quantity column to the table cell, you can add a text box to allow users to modify the value on their own. Then by clicking an Update Cart button, users can change the quantities within the cart. You can add this functionality by following the steps outlined next:

  1. Insert a new form button into the first cell of the last row. Give it the label Update Cart. Make sure that the button is set to Submit. The result is shown in Figure 31.15.

    Figure 31.15. Insert a new button to update the quantities.

    graphics/31fig15.jpg

  2. The next step is create the text field that will display the quantities and ultimately allow the user to make edits. Remove the text binding from within the Quantity column and insert a new text field form object. Name it Quantity.

  3. Bind the Quantity column to the text field object, as shown in Figure 31.16.

    Figure 31.16. Bind the Quantity shopping cart column to the new text box.

    graphics/31fig16.jpg

  4. The Update Cart behavior will now take care of the update. You can select the Update Cart behavior from the UltraDev Shopping Cart submenu, as shown in Figure 31.17.

    Figure 31.17. Select the Update Cart behavior.

    graphics/31fig17.jpg

  5. The Update Cart behavior enables you to specify the form and form object to use for the cart update. You can also specify the URL to redirect to after the update takes place. You can add a parameter to alert the user of the update. The result is shown in Figure 31.18.

    Figure 31.18. Configure the Update Cart dialog box to handle your update.

    graphics/31fig18.jpg

  6. The last step is to add code that grabs the parameter and displays a message to the user. Add the text The text has been updated just below the table and insert the code similar to Figure 31.19.

    Figure 31.19. Add the code to handle the custom error message.

    graphics/31fig19.jpg

The viewcart.asp page should be completely finished. You will now be able to see all the items as the users insert them, clear the cart if necessary, and update items within the cart. The next step will focus in on the most important part of the chapter: adding items to the cart.

Adding Items to the Cart

So far you've learned how to display the items that the cart contains. But you can't stop there. You need to be able to add items to the cart before you can actually view them. This section introduces you to the Add to Cart Via Form behavior contained within the UltraDev Shopping Cart submenu.

As previously mentioned, there are two ways of adding items to the cart: Add to Cart Via Form and Add to Cart Via Link. Because both do virtually the same thing, this section will focus primarily on the Add to Cart Via Form behavior. To add an item to the cart, follow these steps:

  1. Before you can begin adding items to the cart, you need to create a simple image field that will submit the contents of the dynamic text elements. Add two more rows to the table just below Cost.

  2. Add a new image field pointing the source to the addtocart.gif located within the images directory. The result is shown in Figure 31.20. Remember, the image field acts the same as the Submit button form object.

    Figure 31.20. Insert a new image field to handle the form submission.

    graphics/31fig20.jpg

  3. Add the Add to Cart Via Form server behavior by selecting it from the UltraDev Shopping Cart submenu, as shown in Figure 31.21.

    Figure 31.21. Add the Add to Cart Via Form.

    graphics/31fig21.jpg

  4. The Add to Cart Via Form dialog box appears. The dialog box enables you to configure all the data items that will be sent into the cart. You are able to select the form that the data is coming from, all the cart columns and their corresponding data elements within the recordset, the actual recordset to use, and the URL to redirect to after the Add takes place. The important feature within this dialog box is within the cart columns. You want to make sure to match up the appropriate cart columns with the appropriate data elements within the recordset. The exception is the Quantity column. You can use a numeric literal 1, guaranteeing that only one item will be inserted at a time. Remember, quantity edits are handled within the viewcart.asp page. The following table illustrates the data elements that you should point your cart columns to:

    Cart Column Data Element Value
    ProductID Recset Col ProductID
    Quantity Literal 1
    Name Recset Col ProductName
    Price Recset Col ProductCost

  5. The result of the dialog box will look similar to Figure 31.22.

    Figure 31.22. Configure the Add to Cart Via Form dialog box, matching the appropriate cart columns with their respective data elements.

    graphics/31fig22.jpg

  6. Select OK.

  7. Save your work and test it within the browser. Log in to the site and navigate to View Catalog.

  8. Find a DVD to place into your cart and select the Add to Cart button. Figure 31.23 shows the result of the added item.

    Figure 31.23. Adding an item displays it within the view cart page.

    graphics/31fig23.jpg

  9. Select the View Catalog link again and try adding a different item. Figure 31.24 shows how a different item is added but the cart remembers the previous addition.

    Figure 31.24. Adding another item lists it within the cart page.

    graphics/31fig24.jpg

  10. Try modifying the quantity and select the Update Cart button. Notice how the grand total changes to compensate for the added quantity. Figure 31.25 shows the result.

    Figure 31.25. Modify the quantity to change the grand total.

    graphics/31fig25.jpg

Checking Out the Customer

Now that the customer has a good idea of what to order, the customer may want to continue with the purchase. This section covers creating a checkout page so that a particular customer can verify items within the cart as well as personal and credit card information.

NOTE

You will notice that throughout this section, there is no place for a customer to enter credit card information. The reason for this is twofold. First, we store the credit card information when the user registers, and second, tying the cart to a third-party payment host is beyond the scope of this book and is therefore not covered. This example assumes that the responsibility of running the credit card will rely on the merchant after the order has been processed. It's important to point out, though, that a truly dynamic site would integrate some third-party online payment service such as VeriSign or PayPal for electronic payment deductions.


Creating the Checkout Page

It's always a good idea to provide a quick synopsis of the user's information as well as a detailed overview of all the items that the user is purchasing. You may also want to provide randomly generated numbers that users can reference whenever they contact your customer support department. Another benefit to creating a checkout page is the capability for the user to track and print out the summary as an invoice. You can create the checkout page for the Web Store application by following these steps:

  1. You can use the same viewcart.asp page by selecting Save As and saving the file as checkout.asp.

  2. With checkout.asp open, add a new table with five rows and two columns with the captions Customer ID, Name, Shipping Address, Billing Address, and Credit Card. You may also want to add two more rows above that new table with the caption Order Number.

  3. Remove the Update Cart button, Quantity text field, Empty Cart link, and all associated behaviors. Rebind the quantity column as a dynamic text element.

  4. Create two more rows under the Cart table and place a new form Submit button aligned to the right. The result is shown in Figure 31.26.

    Figure 31.26. Create the new checkout.asp page by inserting table rows and a form Submit button.

    graphics/31fig26.jpg

  5. Switch back to the viewcart.asp page and add two more rows just below the grand total. Add a Check Out link pointing to the checkout.asp page in the last cell. Align it right. The result is shown in Figure 31.27.

    Figure 31.27. Add a new link that points to the checkout.asp page.

    graphics/31fig27.jpg

The next few steps outline creating a new recordset to retrieve the Customers information, as well as a customized way to create a randomized order number.

Obtaining the Customer ID

Probably the most crucial piece of the puzzle is the session variable that was created when the user logged in. The reason for this is simple. So far you've been adding items to your cart and modifying quantities without any concern for who these items will be for. If the user decided to purchase the items that they've added to their cart, how would the application know, or you the merchant know, who to send the final merchandise to? Retrieving and setting that information into the checkout page allows us to process that information and eventually update that customer into the orders table. Before we jump ahead of ourselves, let's look at how to retrieve the user's information into the checkout page:

  1. First, create a new recordset in simple mode. Name the new recordset rsCustomer, define the table as the Customer_CreditCards view, and create a new filter for Username and set that equal to the session variable MM_Username. The result is shown in Figure 31.28.

    Figure 31.28. Create a new recordset for the customer.

    graphics/31fig28.jpg

    TIP

    Remember the queries you set up within the database? Those queries, also known as views, can be selected from the Table drop-down list. They replace having to type in all that SQL code within the Advanced screen.

  2. Select the Test button. The Test Value dialog box will appear. Because you know that the username will be set to the only record within the database, enter it into the text field as shown in Figure 31.29. Select OK.

    Figure 31.29. Enter a test value into the text field.

    graphics/31fig29.jpg

  3. The results are shown in the Test SQL Statement window. Remember, the recordset will retrieve all the information exactly as you see it within Figure 31.30. The filter you created creates the WHERE clause with the value of the username and matches it up with the appropriate value within the database table. Select OK.

    Figure 31.30. The results show exactly what the recordset will filter.

    graphics/31fig30.jpg

  4. Select OK to create the new customer recordset.

  5. With the recordset created, you are now ready to drag all the appropriate items into their respective fields within the table. The result will look similar to Figure 31.31.

    Figure 31.31. Drag all the data elements into their respective positions within the table.

    graphics/31fig31.jpg

Generating an Order Number

The creation of a randomly generated order number is always a good idea. This gives you a unique way of distinguishing the vast numbers of orders that you will eventually receive. It also provides a way for users to reference their orders if they ever need to contact you with a question or concern. You can create a randomly generated number by inserting some simple ASP code into your page. To do so, follow these steps:

  1. Place your cursor inside the cell that will display the order number and switch to code view.

  2. Insert the code as it appears within Figure 31.32.

    Figure 31.32. Insert the randomizer code to create an order number.

    graphics/31fig32.jpg

You can test the randomized code by launching the Web store in the browser. Navigate to the view catalog page and select an item. Next, click Check Out, as shown in Figure 31.33.

Figure 31.33. Select the checkout link to navigate to the checkout.asp page.

graphics/31fig33.jpg

Figure 31.34 shows how the randomize function displays a five-digit number. Click Refresh to randomize to a new number.

Figure 31.34. The randomize code displays a five-digit randomized number.

graphics/31fig34.jpg

Writing to the Orders Table

The last order of business is to save all the information that the merchant needs into the orders table. Remember that to make the application seamless, you would want to integrate some third-party merchant software. For simplicity's sake, you are going to write all the information to the database, allowing the merchant to extract the data as they see fit. A quick review of the orders table, shown in Figure 31.35, shows the data that you need to account for.

Figure 31.35. The orders table contains an ID from all the necessary tables.

graphics/31fig35.jpg

You may be wondering why you are not including fields for all the information that is contained within the checkout.asp page. The beauty in relationships is that it lets you account for the rest of the data items within a given page through the use of the unique ID. Later, when you want to extract all the information from a given table, you look it up by the ID that is contained within the orders table. This will make more sense toward the end of the section. To begin to write to the orders table, follow the steps outlined next:

  1. Review how the information will be written to the orders table. You will use the Insert Record behavior, but remember that the Insert Record behavior requires form objects with data within them to extract. You can solve this problem by inserting hidden form fields next to all the data items within the checkout.asp page. You will need hidden form fields for the CustomerID, ProductID, Quantity, and OrderNumber fields. Insert new hidden form fields by placing your cursor next to the data item and selecting Hidden Field from the Form Objects submenu of the Insert menu. The result is shown in Figure 31.36.

    Figure 31.36. Insert hidden form fields for Quantity and Product ID.

    graphics/31fig36.jpg

  2. Copy the two values and place them within the value attribute of the hidden fields.

     <%= (UCCart1.GetColumnValue("ProductID",UCCart1_i)) %>  <%= (UCCart1.GetColumnValue("Quantity",UCCart1_i)) %> 
  3. This guarantees that the values are written not only to the table cells, but into the hidden form fields as well. Repeat the same steps for the Order Number and Customer ID. The result is shown in Figure 31.37.

    Figure 31.37. Insert hidden form fields for Customer ID and Order Number.

    graphics/31fig37.jpg

  4. This time, copy the following items into the value attribute of the hidden form fields:

     <%= rndNum %>  <%= (rsCustomer.Fields.Item("CustomerID").value) %> 
  5. Now that the form fields are inserted, you can create your Insert Record behavior.

    WARNING

    Make sure all the hidden form fields are named appropriately.

  6. Select Insert Record from the Server Behaviors drop-down menu, as shown in Figure 31.38.

    Figure 31.38. Insert the Insert Record server behavior.

    graphics/31fig38.jpg

  7. The Insert Record dialog box will appear. Notice how only the hidden form fields appear within the Form Elements box. Match up the appropriate form objects with their respective field name within the orders table, as shown in Figure 31.39.

    Figure 31.39. Modify the Form Elements box to match up the form objects with the recordset field names.

    graphics/31fig39.jpg

  8. Save your work and test it in the browser. Make sure you log in; otherwise, the Customer won't be read correctly within the checkout.asp page.

  9. Select an item from the viewcatalog.asp page. Click Checkout and select the Process Order button. You will be redirected back to the viewcatalog.asp page.

Figure 31.40 shows that if you open the orders table within Access, the appropriate information was indeed written.

Figure 31.40. All the appropriate data was written to the orders table.

graphics/31fig40.jpg

If you open the customers table, you will find that the user was in fact the user whose CustomerID appears within the CustomerID column. If you open the products table, you will notice that the DVD selected is the DVD that appears within the orders table. Later, if you need to query the tables for the products and customers, you can filter the results based on the IDs that appear within the orders table.


    Team-Fly    
    Top


    Macromedia Dreamweaver MX Unleashed
    Macromedia Dreamweaver MX 2004 Unleashed
    ISBN: 0672326310
    EAN: 2147483647
    Year: 2002
    Pages: 321

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net