
// Begin external Javascript Shopping Cart source routines. ------------------

// Initialize Global Variables -----------------------------------------------

// Shopping cart and order form HTML documents.
var cartFile = "cart.html", orderFile = "orderform.html";

// Define the URL used to access the secured order form.
//var secureURL= "https://www22.quik.com/~wiz/shop/";    // end with slash
var secureURL= "https://healingwithnutrition.com/shop/";    // end with slash

// Localize the information for the specific site using the shopping cart.
function initCart(url,cart,order) {
	if (url)  secureURL = url;
	if (cart) cartFile  = cart;
	if (order)orderFile = order;

	if (url && url.charAt(url.length-1) != "/") secureURL += "/";
}

// ---------------------------------------------------------------------------

// Save domain information and then automatically secure QUIK accounts.
myHost = location.host;
cookieDomain = myHost.substring(myHost.lastIndexOf(".",myHost.length-5)+1);
//if (location.protocol != "https:" && cookieDomain == "quik.com")
if (location.protocol != "https:" && cookieDomain == "healingwithnutrition.com")
  //location.href = "https://www22.quik.com"+location.pathname;
  location.href = "https://healingwithnutrition.com"+location.pathname;

if (location.href.toLowerCase().indexOf("healingwithnutrition") > 0)
  //secureURL = "https://www22.quik.com/healingwithnutrition/products/";
  secureURL = "https://healingwithnutrition.com/products/";

// Shopping cart data separation characters.
var ItemSepr  = "~", AttrSepr  = "|", ValueSepr = ":";

// Field replacement tags.
var idTag       = '<!--:id:-->';
var nameTag     = '<!--:name:-->';
var qtyTag      = '<!--:qty:-->';
var tqtyTag     = '<!--:totalqty:-->';
var priceTag    = '<!--:price:-->';
var tpriceTag   = '<!--:totalprice:-->';
var subtotalTag = '<!--:subtotal:-->';

// Style sheet class definitions.
var str = '<style type="text/css">\n<!--\n'+
'.bg {font:normal 14pt arial,helvetica,sans-serif;}\n'+
'.sm {font:normal  8pt arial,helvetica,sans-serif;}\n'+
'.hi {font:bold   10pt arial,helvetica,sans-serif;}\n'+
'.lo {font:normal 10pt arial,helvetica,sans-serif;}\n'+
'.rt {font:normal 10pt arial,helvetica,sans-serif;text-align:right;}\n'+
'-->\n</style>';
document.writeln(str);

// Main Shopping Cart Functions ----------------------------------------------

// The main routines necessary for a working shopping cart provide the
// ability to add an item to the shopping cart, remove an item from the
// shopping cart, change the quantities of items in the cart, and display
// the contents of the shopping cart in various ways including the
// display of a limited (small) view of the contents of the shopping cart
// so that what has already been placed in the cart can be seen while
// shopping continues.

// ---------------------------------------------------------------------------

// Format and display the shopping cart before the order is placed.
// Parameters:
//   [width] is the width of the cart as a number or percent string.
//   [title] is a string containing the name of the shopping cart.
//   [colors] is a string containing a comma-separated list of table colors.
//
// Example:
// To set the shopping cart width to the browser screen width, the 
// title to "Current Cart Contents", and the cart column heading row 
// to a background of dark green with white text, you would code:
//    Cart("100%","Current Cart Contents","thcolor=#006600,thtcolor=#FFFFFF");
//
function Cart(width, title, colors, header, footer, row) {
  width = width || "90%";            // default cart width
  title = title || "Shopping Cart";  // default cart title

  // Parse comma-separated list of color fields and values.
  var bgcolor = getValueOf("bgcolor",'#FFFFFF',colors);  // background
  var thcolor = getValueOf("thcolor",'#CCCC99',colors);  // table heading
  var tdcolor = getValueOf("tdcolor",'#EFEFEF',colors);  // table data
  var tpcolor = getValueOf("tpcolor",'#D0D0D0',colors);  // total price
  var thtcolor= getValueOf("thtcolor",'#000000',colors); // heading text

  // Shopping cart title and column headings formatting.
  if (!window.myCart) window.myCart = new Object();
  myCart.header = header || 
'\n<TABLE WIDTH="'+width+'" BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD ALIGN="right">\n\n'+
'<TABLE WIDTH="100%" BORDER=1 CELLSPACING=0 CELLPADDING=4 BGCOLOR="'+bgcolor+'"><TR><TD>\n'+
'<TABLE WIDTH="100%" BORDER=0 CELLSPACING=1 CELLPADDING=1>\n <TR><TD COLSPAN=5>'+
'<SPAN ID="title" CLASS="bg">'+title+'</SPAN></TD></TR>\n <TR BGCOLOR="'+thcolor+'">\n  '+
'<TH ALIGN="left" WIDTH="90%"><SPAN CLASS="hi"><FONT COLOR="'+thtcolor+'">&nbsp;&nbsp;Item</SPAN></TH>\n  '+
'<TH NOWRAP><SPAN CLASS="hi"><FONT COLOR="'+thtcolor+'">&nbsp;Quantity&nbsp;</SPAN></TH>\n  '+
'<TH NOWRAP><SPAN CLASS="hi"><FONT COLOR="'+thtcolor+'">&nbsp;Unit Price&nbsp;</SPAN></TH>\n  '+
'<TH NOWRAP><SPAN CLASS="hi"><FONT COLOR="'+thtcolor+'">&nbsp;Total Price&nbsp;</SPAN></TH>\n  '+
'<TH><SPAN CLASS="hi"><FONT COLOR="'+thtcolor+'">&nbsp;</SPAN></TH>\n </TR>';

  // Shopping cart totals and control buttons formatting.
  myCart.footer = footer || '<TR>\n  <TD COLSPAN=5>\n   '+
'<TABLE WIDTH="100%" BORDER=1 CELLSPACING=0 CELLPADDING=0><TR><TD></TD></TR></TABLE>\n  '+
'</TD>\n </TR><TR>\n  <TD COLSPAN=2 ALIGN="right">\n   '+
'<INPUT TYPE="button" CLASS="hi" NAME="ACTION" VALUE="Recalculate" onClick="Recalc(this.form)"></TD>\n  '+
'<TD ALIGN="right"><SPAN CLASS="hi">Subtotal:&nbsp;</SPAN></TD>\n  '+
'<TD ALIGN="right" BGCOLOR="'+tpcolor+'"><SPAN CLASS="hi">'+subtotalTag+'&nbsp;</SPAN></TD>\n </TR></TABLE>\n'+
'</TD></TR></TABLE><BR>\n\n '+
'<INPUT TYPE="button" CLASS="hi" NAME="shop" VALUE="Continue Shopping" onClick="history.go(-1)">\n '+
'<INPUT TYPE="button" CLASS="hi" NAME="checkout" VALUE="Secure Checkout" onClick="return goSecure(this.form)">\n</TD></TR></TABLE>';

  // Item row formatting.
  myCart.row = row || '<TR BGCOLOR="'+tdcolor+'">\n  '+
'<TD><SPAN CLASS="lo">&nbsp;&nbsp;'+nameTag+'&nbsp;</SPAN></TD>\n  '+
'<TD ALIGN="center">\n   <INPUT TYPE="Text" CLASS="rt" NAME="qty'+idTag+
'" VALUE="'+qtyTag+'" SIZE="3"></TD>\n  '+
'<TD ALIGN="right"><SPAN CLASS="lo">'+priceTag+'&nbsp;</SPAN></TD>\n '+
'<TD ALIGN="right"><SPAN CLASS="hi">'+tpriceTag+'&nbsp;</SPAN></TD>\n  '+
'<TD><INPUT TYPE="button" CLASS="hi" NAME="del'+idTag+'" VALUE="Remove" \n   '+
'onClick="this.form.qty'+idTag+'.value=0; Recalc(this.form)"></TD>\n </TR>';

  // Get the contents of the shopping cart and see if it's empty.
  var basket = getBasket();
  if (basket) showCart(myCart, basket);
  else EmptyCart(width, bgcolor);
}

// Format and display the shopping cart to review as the order is being placed.
// Parameters:
//   [width] is the width of the cart as a number or percent string.
//   [colors] is a string containing a comma-separated list of table colors.
function ReviewCart(width, colors, header, footer, row) {
  width = width || "90%";            // default cart width

  // Parse comma-separated list of color fields and values.
  var bgcolor = getValueOf("bgcolor",'#CCCCCC',colors);  // background
  var thcolor = getValueOf("thcolor",'#C0C0C0',colors);  // table heading
  var tdcolor = getValueOf("tdcolor",'#FFFFFF',colors);  // table data
  var tpcolor = getValueOf("tpcolor",'#EFEFEF',colors);  // total price
  var thtcolor= getValueOf("thtcolor",'#000000',colors); // heading text

  // Shopping cart title and column headings formatting.
  if (!window.myCart) window.myCart = new Object();
  myCart.header = header || 
'\n<TABLE WIDTH="'+width+'" BORDER=0 CELLSPACING=0 CELLPADDING=0 BGCOLOR="'+bgcolor+'"><TR><TD>\n'+
'<TABLE WIDTH="100%" BORDER="0" CELLSPACING="1" CELLPADDING="3"><TR BGCOLOR="'+thcolor+'">\n\t'+
'<TH ALIGN="left" WIDTH="90%"><SPAN CLASS="hi"><FONT COLOR="'+thtcolor+'">&nbsp;&nbsp;Item</SPAN></TH>\n\t'+
'<TH NOWRAP><SPAN CLASS="hi"><FONT COLOR="'+thtcolor+'">&nbsp;Quantity&nbsp;</SPAN></TH>\n\t'+
'<TH NOWRAP><SPAN CLASS="hi"><FONT COLOR="'+thtcolor+'">&nbsp;Unit Price&nbsp;</SPAN></TH>\n\t'+
'<TH NOWRAP><SPAN CLASS="hi"><FONT COLOR="'+thtcolor+'">&nbsp;Total Price&nbsp;</SPAN></TH></TR>';

  // Shopping cart totals and control buttons formatting.
  myCart.footer = footer || '<TR BGCOLOR="'+tdcolor+'">'+
'<TD COLSPAN=3 ALIGN=right><SPAN CLASS="hi">Subtotal:&nbsp;</SPAN></TD>\n\t'+
'<TD ALIGN="RIGHT" BGCOLOR="'+tpcolor+'"><SPAN CLASS="hi">'+subtotalTag+
'&nbsp;</SPAN></TD>\n</TR></TABLE>\n</TD></TR></TABLE><BR>\n\n\t';

  // Item row formatting.
  myCart.row = row || '<TR BGCOLOR="'+tdcolor+'">\n\t'+
'<TD><SPAN CLASS="lo">&nbsp;&nbsp;'+nameTag+'&nbsp;</SPAN></TD>\n\t'+
'<TD ALIGN="center"><SPAN CLASS="lo">'+qtyTag+'</SPAN></TD>\n\t'+
'<TD ALIGN="right"><SPAN CLASS="lo">'+priceTag+'&nbsp;</SPAN></TD>\n\t'+
'<TD ALIGN="right"><SPAN CLASS="hi">'+tpriceTag+'&nbsp;</SPAN></TD></TR>';

  // Get the contents of the shopping cart and see if it's empty.
  var basket = getBasket();
  if (basket) showCart(myCart, basket);
  else EmptyCart(width, bgcolor);
}

// Format and display a small shopping cart for viewing with item catalog.
function SmallCart(width, title, colors, type, header, footer, row) {
  title = title || "Shopping Cart";  // default cart title
  width = width || "115";            // default cart width

  // Parse comma-separated list of color fields and values.
  var bgcolor = getValueOf("bgcolor",'#FFFFFF',colors);  // background
  var thcolor = getValueOf("thcolor",'#CCCC99',colors);  // table heading
  var tdcolor = getValueOf("tdcolor",'#EFEFEF',colors);  // table data
  var tpcolor = getValueOf("tpcolor",'#D0D0D0',colors);  // total price
  var thtcolor= getValueOf("thtcolor",'#000000',colors); // heading text

  var id=("smallCart"+(type||0)), myCart, basket = getBasket();
  if (!(myCart = window[id])) { 
    myCart = window[id] = new Object(); myCart.id = id;
    myCart.header = new Array(); myCart.footer = new Array(); myCart.row = new Array();
    for (var i=0; i<2; i++) {

      // Shopping cart title and column headings formatting.
      myCart.header[i] = header || 
'\n<table width="'+width+'" border=0 cellpadding=2 cellspacing=0 bgcolor="#808080"><tr><td>\n\n'+
'<table width="100%" border=0 cellpadding=0 cellspacing=0 bgcolor="'+bgcolor+'">'+
'<tr>\n  <td align=center colspan=2 nowrap><span class="hi">'+title+'</td>\n </tr>'+
(i?('<tr>\n  <td nowrap width="90%"><span class="sm">&nbsp;&nbsp;'+((type)?'Total':'Item')+'</span></td>\n  <td align=right><span style="font:normal 8pt arial,helvetica,sans-serif;">Qty&nbsp;&nbsp;</span></td>\n </tr>'):'')+'</table>\n\n'+
'<table width="100%" border=0 cellpadding=2 cellspacing=0>';

      // Shopping cart totals and control buttons formatting.
      myCart.footer[i] = footer || (i?('<tr bgcolor="'+tpcolor+'">\n  '+
'<td'+(type?'':' colspan=2 align="right" ')+'><span class="sm">'+
(type?'&nbsp;':'Total:')+'&nbsp;'+subtotalTag+'&nbsp;</span></td>'+
(type?('<td align="right"><span class="sm">'+tqtyTag+'&nbsp;</span></td>'):'')+'\n </tr></table>\n\n'+
'<table width="100%" border=0 cellpadding=0 cellspacing=0 bgcolor="'+bgcolor+'"><tr>\n  '+
'<th><input type="button" class="hi" value="Checkout" onClick="location.href='+"'"+cartFile+"'"+';"></th>\n '+
'</tr>'):'')+'</table>\n\n</td></tr></table>';

      // Item row formatting.
      myCart.row[i] = row || '<tr bgcolor="'+tdcolor+'">\n  '+
'<td><span class="sm">&nbsp;'+(i?nameTag:'Empty')+'</span></td>\n  '+
'<td align=right><span class="sm">'+qtyTag+'&nbsp;</span></td>\n </tr>';
      if (type) { 
        if (!i) myCart.header[i] += myCart.row[i]; 
        myCart.row[i] = ''; 
      }
    }
  }

  // Get the contents of the shopping cart and see if it's empty.
  if (basket) showCart(myCart, basket, 1);
  else {
    var content = myCart.header[0]+myCart.row[0]+myCart.footer[0],
      css = ' '; //' STYLE="position:relative;left:0;top:0;"';
    document.writeln('<SPAN ID="'+id+'"'+css+'>'+content+'</SPAN>');
  }
}

// Function to display the empty shopping cart message and continue button.
//   [width] is the width of the cart as a number or percent string.
//   [bgcolor] is a string containing the empty cart background color.
//   [msg] is a string containing empty shopping cart message.
function EmptyCart(width, bgcolor, msg, cartFrame) {
  if (!width) width = "90%";            // default cart width
  if (!bgcolor) bgcolor = "#FFFFFF";    // default background color
  if (!msg) msg = "There are no items in your shopping cart.";

  if (!cartFrame) cartFrame = '<TABLE WIDTH="'+width+'" BORDER=0 '+
'CELLSPACING=0 CELLPADDING=0><TR><TD ALIGN="right">'+"\n\n"+
'<TABLE WIDTH="100%" BORDER=1 CELLSPACING=0 CELLPADDING=4 '+
'BGCOLOR="'+bgcolor+'"><TR><TD>'+"\n"+
'<TABLE WIDTH="100%" BORDER=0 CELLSPACING=1 CELLPADDING=1><TR>'+"\n  "+
'<TH><FONT FACE="Arial,Helvetica" SIZE="-1">'+
'&nbsp<BR>'+msg+'<BR>&nbsp</FONT></TH>'+"\n "+
'</TR></TABLE>'+"\n"+'</TD></TR></TABLE><BR>'+"\n\n "+
'<INPUT TYPE="button" NAME="ACTION" VALUE="Continue Shopping" '+
'onClick="history.go(-1)">'+"\n"+'</TD></TR></TABLE>';

  document.writeln(cartFrame);
}

// Function to add a uniquely identified item to the shopping cart.
//   "itemID" is a string containing a unique item id code.
//   "name" is the description of the item displayed in the cart.
//   "price" is a decimal number representing the item cost.
//   [qty] is the total quantity of the current item to purchase.
//   [basket] is a string containing the contents of the cart.
//   Returns true if the item is successfully added to the cart.
function AddToCart(id, name, price, qty, basket) {
  var key;

  // Get the contents of the current shopping cart.
  if (!basket) basket = GetCookie(key = myBasket());
  if (key == null) return false;
  if (!basket) basket = "";

  // Format and add the item to the shopping cart.
  if (basket.indexOf(ItemSepr+id+AttrSepr) == -1) {
    var theItem = boxItem(id, name, price, plusInt(qty, 1));
    SetCookie(myBasket(), basket+theItem, null, "/");
  } else basket = ChangeCartValue(id, "qty", 1, basket, true);
  return true;
}

// Function to remove a specific item from the shopping cart.
//   "id" is a string containing a unique item id code.
//   [basket] is a string containing the contents of the cart.
//   Returns the updated contents of the shopping cart.
function RemoveFromCart(id, basket) {
  if (!basket) basket = getBasket();

  // Locate and remove the item from the shopping cart.
  var beginPos, endPos;
  if ((beginPos = basket.indexOf(ItemSepr+id+AttrSepr)) != -1) {
    endPos = (basket+ItemSepr).indexOf(ItemSepr, beginPos+1); // next item
    basket = basket.substring(0, beginPos)+basket.substring(endPos);
    SetCookie(myBasket(), basket, null, "/");
  }
  return basket;
}

// Function to change an item value in the shopping cart.
//   "id" is a string containing a unique item id code.
//   "name" is the description of an attribute (aspect) of the item.
//   "value" is the value (contents) of the attribute of the item.
//   [basket] is a string containing the contents of the cart.
//   [calc] is true if the value should be added (recalculated)
//   Returns the updated contents of the shopping cart.
function ChangeCartValue(id, name, value, basket, calc) {
  if (!basket) basket = getBasket();

  // Locate and update the specified value.
  var valuePos, endPos, tmpPos, qty;
  if ((valuePos = indexOfItemFieldValue(id, name, basket)) != -1) {
    tmpPos = (basket+ItemSepr).indexOf(ItemSepr, valuePos);
    endPos = (basket+AttrSepr).indexOf(AttrSepr, valuePos);
    if (tmpPos < endPos) endPos = tmpPos;
    qty = basket.substring(valuePos, endPos);
    if (calc || ((""+qty) != (""+value))) {
      if (calc) value += parseFloat(qty);
      basket = basket.substring(0, valuePos)+value+basket.substring(endPos);
      SetCookie(myBasket(), basket, null, "/");
    }
  }
  return basket;
}

// Shopping Cart Form Event Functions -------------------------------

// Function to respond to a buy command from the shopping cart form.
//   "theItem" is the form element (button) containing the item id.
//   [data] is a string containing the item name and price (or null).
//   [stay] is true if the current web page should be refreshed.
//   [id] is a string containing the item id if theItem.name does not.
function Buy(theItem, data, stay, id) {
  var theForm = (theItem && theItem.form)?theItem.form:document.forms[0];
  id = id?id:((theItem && typeof theItem == "object")?theItem.name:theItem);
  var ilen=(""+id).length, tlen, el, tag, value, url, name, price, qty, misc="";

  // Loop to extract form information for the current item.
  for (var i = 0; i < theForm.elements.length; i++) {
    el = theForm.elements[i]; tag = ""+el.name; value = ""+el.value;
	tlen = tag.length; j = tlen - ilen;
    if (j > 0 && tag.substring(j) == (""+id)) {
      tag = tag.substring(0, j).toLowerCase();
      if (value == null && el.type && el.type.toLowerCase().indexOf("sel") == 0)
        value = el.options[el.selectedIndex].value;
      if (tag == "d" || tag == "data") data = data||value;  // data (name|price|link)
      else if (tag == "l" || tag == "link")  url  = value;  // link
      else if (tag == "n" || tag == "name")  name = value;  // name
      else if (tag == "p" || tag == "price") price= value;  // price
      else if (tag == "q" || tag == "qty")   qty  = value;  // quantity
      else if (tag.charAt(tag.length-1) == ":") {   // general (ends with colon)
        if (misc) misc += ", ";
        misc += (el.name.substring(0,j)+" "+el.value);
      }
    }
  }

  // Parse the item data to get the name and price of the item.
  var pos = data.indexOf(AttrSepr);
  name = name || data.substring(0,pos);
  price= price|| data.substring(pos+1);
  pos = price.indexOf(AttrSepr);
  if (pos > 0) {
    url = url || price.substring(pos+1);
    price = price.substring(0, pos);
  }
  if (url)  name = '<a href='+url+'>'+name+'</a>';
  if (misc) name+= ("<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<i>"+misc+"</i>");
  qty = qty || 1;

  // Add a quantity of items to the shopping cart.
  if (!AddToCart(id, name, price, qty)) return;

  // Either refresh the current web page that may display a small
  // shopping cart image, or go to the shopping cart full web page.
  if (stay) {
    var tmp = null;
    if (document.all && document.readyState == "complete")
      for (var n in window)
        if (n.toLowerCase().indexOf("cart")>=0) 
          showCart(tmp=window[n], getBasket(), 1);
    if (!tmp) location.reload(true);
  } else location.href = cartFile+"?"+(new Date()).getTime();
}

// Function to get item quantities from the shopping cart form.
//   [theForm] is the form containing the shopping cart.
//   [basket] is a string containing the contents of the cart.
function Recalc(theForm, basket) {
  if (!theForm) theForm = document.forms[0]; // default to first form
  if (!basket) basket = getBasket();

  // Loop through the elements of the form containing the shopping
  // cart to locate quantity form fields to update.
  var el, id, qty, tmp;
  for (var i = 0; i < theForm.elements.length; i++) {
    el = theForm.elements[i]; id = el.name;
    if (id.substring(0, 3).toLowerCase() == "qty") {
      id = id.substring(3);
      if ((beginPos = basket.indexOf(ItemSepr+id+AttrSepr)) != -1) {
        qty = plusInt(el.value, 0);
        if (qty == 0) basket = RemoveFromCart(id, basket);
        else basket = ChangeCartValue(id, "qty", qty, basket);
      }
    }
  }
  if (document.all && document.all["cart"]) showCart(myCart,basket);  
  else location.reload(true);
}

// Shopping Cart "Internal" Support Functions --------------------------------

// Get object property information (similar to Netscape's toSource()).
// Parameter:
//   "obj" is a reference to the object to parse for literal property display.
function getSource(obj) {
  var what, which, str="{ ";
  if (!obj) obj=this;                       // function as object method
  for (var n in obj) {                      // loop to access object properties
    what=obj[n]; which=typeof what;         // format output as object literal
    if (which.toLowerCase()!="function" &&  // ignore event handlers and
     (n+'').toUpperCase().indexOf("ERTEXT")<0 &&   // object layer content
     (n+'').indexOf("erHTML")<0 && (n+'').indexOf("on")!=0)
      str += n+":"+((what+"")?((what=="[object]"&&what.tagName)?
        ("<"+what.tagName+">"):what):("(empty "+which+")"))+"; ";
  }
  return str+"}";
}

// Replace every occurance of one substring with another.
// Parameters:
//   "str" is the string containing substrings to replace.
//   "find" is the original substring to replace.
//   "add" is the replacement substring.
function replaceAll(str, find, add) {
  var what = typeof find;
  if (what == "string" || what == "number") {
    find = ""+find; add = ""+add;
    for (var i=0; (i=str.indexOf(find,i)) >= 0; i += add.length)
      str = str.substring(0,i)+add+str.substring(i+find.length);
  } else {
    for (var n=0; n < find.length; n++) {
      find[n] = "" + find[n]; add[n] = add[n] + "";
      if (find[n])
        for (var i=0; (i=str.indexOf(find[n],i)) >= 0; i += add[n].length)
          str = str.substring(0,i)+add[n]+str.substring(i+find[n].length);
    }
  }
  return str;
}

// Get the value of a name in a name=value comma-separated list.
// Parameters:
//   "name" is the string containing the name to search for.
//   "defaultValue" is the string containing the default value for the name.
//   "str" is the string being parsed.
function getValueOf(name, defaultValue, str) {
  if (!str) return defaultValue;

  var pos, find, out;
  if (typeof str == "string") {                           // remove spaces
    while((pos=str.indexOf(" "))>=0) str=str.substring(0,pos)+str.substring(pos+1);
    find = ","+name+"="; pos = (","+str).indexOf(find);   // match the name
    if (pos < 0) return defaultValue; else pos += (find.length-1);
    out = str.substring(pos,(str+",").indexOf(",",pos));  // get the value

  } else for (var n=0; n < str.length; n++) {             // process object list
    find = str[n].name || str[n].id;                      // match the name
    if (find == name) { out = str[n].value; break; }      // get the value
  }
  if (!out.length) out = defaultValue;
  return out;
}

// Generate a random number.
// Parameter:
//   "max" is the maximum value the random number can be.
Seed = 999;
function randomNum(max) {
   if (Math.random) return Math.floor(Math.random() * max);
   Seed = ((new Date()).getTime() * Math.abs(Math.cos(Seed)));
   return Math.floor(Seed) % max;
}

// Get a valid (non-negative integer) quantity.
// Parameters:
//   "qty" is the variable used to get the non-negative integer.
//   "defaultNum" is the default number used if no valid number is found.
function plusInt(qty, defaultNum) {
  if ((""+qty).charAt(0) < "0" || (""+qty).charAt(0) > "9") qty = defaultNum;
  return parseInt(qty);
}

// Format a number as a dollar amount.
// Parameter:
//   "amount" is the number or string being formatted as a dollar amount.
function dollars(amount) {
  amount = parseFloat(amount) + 0.005;       // round to the nearest penny
  var str = "$"+amount;                      // create $ sign string
  str = str.substring(0,str.indexOf(".")+3); // trim after 2 decimal places
  return str;
}

// Format item information to add to the shopping cart.
// Data Format:
//   ~ id | name : {value} | price : {value} | qty : {value}
function boxItem(id,name,price,qty) {
  return "" + ItemSepr + id + AttrSepr + "name" + ValueSepr + name + 
    AttrSepr + "price"+ ValueSepr + price + AttrSepr + "qty" + ValueSepr + qty;
}

// Get the value of a specified item attribute.
// Parameters:
//   "id" is the item identification code.
//   "name" is the name of the field containing the data.
//   [basket] is the current contents of the shopping cart.
function valueOfItemField(id,name,basket) {
  if (!basket) basket = getBasket();

  // Get the value position, then the next item or attribute marker position.
  var out = "", valuePos, itmPos, fldPos;
  if ((valuePos = indexOfItemFieldValue(id,name,basket)) != -1) {
    itmPos = (basket+ItemSepr).indexOf(ItemSepr,valuePos);
    fldPos = (basket+AttrSepr).indexOf(AttrSepr,valuePos);
    out = basket.substring(valuePos,((itmPos < fldPos)?itmPos:fldPos))
  }
  return out;
}

// Get the position of the value of a specific item attribute.
// Parameters:
//   "id" is the item identification code.
//   "name" is the name of the field containing the data.
//   [basket] is the current contents of the shopping cart.
function indexOfItemFieldValue(id,name,basket) {
  if (!basket) basket = getBasket();

  var pos = basket.indexOf(ItemSepr+id+AttrSepr);    // item in cart
  if (pos != -1) {
    var find = AttrSepr + name + ValueSepr;
    pos = basket.indexOf(find,pos);         // name in item
    if (pos != -1) pos += find.length;      // value past name
  }
  return pos;
}

// Get a uniquely identified shopping cart name.
var idName = 'cartId', cartPrefix = 'cart';
function myBasket() {
  var id = GetCookie(idName);
  if (!id || id.charAt(0) < "0" || id.charAt(0) > "9") {
    id = randomNum(999)+(new Date()).getTime();
    SetCookie(idName, id, null, "/");
    if (GetCookie(idName) != id) {  // check if cookies are enabled
      alert("You must have cookies enabled for this to work.");
      return null;
    }
  }
  return cartPrefix+id;
}

// Get the contents of the shopping cart from the url or cookies.
function getBasket() {
  var basket = GetCookie(myBasket());
  if (!location.search) return basket;

  // See if the shopping cart is contained in the URL.
  var str = location.search;
  var pos = str.indexOf(cartPrefix);
  if (pos < 0) return basket;

  // Locate the contents of the shopping cart.
  str = str.substring(pos);
  pos = str.indexOf("=");
  if (pos < 5) return basket;

  // Get the shopping cart session identifier.
  var id = str.substring(4,pos);

  // Get the shopping cart contents.
  str = str.substring(pos+1);
  pos = str.indexOf("&");
  if (pos < 0) pos = str.length;
  basket = unescape(str.substring(0,pos));

  // Restore the cookie information for the current domain.
  SetCookie(idName, id, null, "/");
  SetCookie(myBasket(), basket, null, "/");
  return basket;
}

// Display the formatted contents of the shopping cart.
function showCart(obj, basket, limit) {
  var header, footer, row;
  if (typeof obj.header == "string") {
    header = obj.header; footer = obj.footer; row = obj.row;
  } else {
    var i = basket ? 1 : 0;
    header = obj.header[i]; footer = obj.footer[i]; row = obj.row[i];
  }
  var content = header;

  // Loop to display each item in the shopping cart.
  var beginPos, endPos=0, pos, urlTag="", id, name, price, qty, tprice, tmp;
  for (var theTotal=0, theQty=0; (beginPos=basket.indexOf(ItemSepr,endPos))>=0;
    theQty += parseInt(qty), theTotal += tprice) {

    endPos = basket.indexOf(AttrSepr,beginPos);       // quantity
    tmp = replaceAll(row,idTag,id = basket.substring(beginPos+1,endPos));
    tmp = replaceAll(tmp,qtyTag,qty = valueOfItemField(id,"qty",basket));

    price = valueOfItemField(id,"price",basket);      // unit price
    tmp = replaceAll(tmp,priceTag,dollars(price));

    tprice = plusInt(qty,1)*parseFloat(price);        // total price
    tmp = replaceAll(tmp,tpriceTag,dollars(tprice));

    name = valueOfItemField(id,"name",basket);        // description
    if (limit) {
      if (name.substring(0,2).toLowerCase() == "<a") {
        pos = name.indexOf(">");
        urlTag = name.substring(0,pos+1);
        name = name.substring(pos+1,name.toLowerCase().indexOf("</a>"));
      }
      pos = name.toLowerCase().indexOf("<br>");
      if (pos != -1) name = name.substring(0,pos);
      if (name.length > 12) name = name.substring(0,12)+"...";
      if (urlTag.length) { name = urlTag+name+"</a>"; urlTag = ""; }
    }
    content += tmp = replaceAll(tmp,nameTag,name);
  }

  // Replace the total number of items and cost of all items.
  tmp = replaceAll(footer, tqtyTag, theQty);
  content += replaceAll(tmp, subtotalTag, dollars(theTotal));

  // Wrap the shopping cart in a positioned element for direct DHTML updating.
  var id = obj.id || 'cart';
  if (document.all && (tmp == document.all[id])) tmp.innerHTML = content;
  else {
    var css = ' '; //' style="position:relative;top:0;left:0;"',
      spanon = '<span id="'+id+'"'+css+'>', spanoff = '</span>';
    if (!document.forms.length || document.forms[0].name == "buy") 
      { spanon += '<form>'; spanoff = '</form>'+spanoff; }
    document.writeln(spanon+content+spanoff);
  }
}

// Order Form Event Functions ------------------------------------------------

// Make sure the order is placed via a secure web address.
function goSecure(theForm) {
  var pos, url, path, dir, file, protocol = location.protocol.toLowerCase();

  // If unknown protocol, first try a direct submit, then build cart url.
  if (protocol.indexOf("http") < 0) { 
    if (theForm.action) { theForm.submit(); return true; }
    url = location.href;
    pos = url.lastIndexOf("/");
    if (pos < 0) pos = url.lastIndexOf("\\");
    location.href = url.substring(0,pos+1)+orderFile;  // no domain change
    return true;
  }

  // If no specified form submit action, build the complete secure url.
  var safe = (protocol.indexOf("https:") == 0);
  if (!theForm.action || typeof theForm.action == "object") {
    if (safe) {
      url = location.href; path = location.pathname;  // get web url and path
      pos = path.indexOf("#");                        // find end of filename
      if (pos < 0) pos = url.indexOf("?");
      if (pos < 0) pos = url.length;
      path= path.substring(0,pos);
      pos = path.lastIndexOf("/");
      dir = path.substring(0,pos+1);                  // get directory wo/ file
      file= path.substring(pos+1);                    // get filename wo/ directory
      url = url.substring(0,url.indexOf(dir));
      location.href = url+dir+orderFile;               // no domain change
      return true;
    } else url = secureURL+orderFile;

  } else {
    url = theForm.action.toLowerCase(); pos = url.indexOf("://") + 1;
    if ((pos && url.indexOf("https:")==0) || safe) {location.href=url;return true;}

    if (pos <= 0) {                                    // remove invalid domain
      pos = url.indexOf(".com");
      if (pos > 0) path = url.substring(pos+4); else path = url;
    } else path = url.substring(pos+2);
    pos = path.indexOf("/");
    if (pos >= 0) path = path.substring(pos+1);
    pos = path.lastIndexOf("/");                      // get the submit action
    if (pos < 0) { dir = ""; file = path; }           // directory and filename
    else { dir = path.substring(0,pos+1); file = path.substring(pos+1); }
    if (safe) {                                       // get current secure url
      url = location.href; pos = url.lastIndexOf("/");
      if (pos > 0) url = url.substring(0,pos+1);
      if (dir && url.indexOf(dir) > 0) dir = "";
      location.href = url+dir+file;                   // no domain change
      return true;
    } else url = secureURL;                           // or use default url
    if (dir && url.indexOf(dir) > 0) dir = "";
    url += dir+file;
  }

  // Include shopping cart in url to pass to a different secure domain.
  var id = myBasket();
  var basket = GetCookie(id);
  location.href = url+"?"+id+"="+escape(basket);
  return true;
}

// Verify bank card number.
// Parameter:
//   "theItem" is the form field containing the entered bank card number or
//   a number can be passed directly to return a valid bank card number.
//   [which] is optionally the type of bank card to specifically check.
function verifyBankCard(theItem,which) {
  var isObj=(typeof theItem=="object"), n=""+(isObj?theItem.value:theItem);
  var digit, len;

  // Check for tester.
  if (n.toLowerCase().indexOf("tester") >= 0) return n;

  // Remove non-numeric characters.
  for (var i = n.length; i-- > 0;)
    if((digit=n.charAt(i))<"0" || digit>"9") n=n.substring(0,i)+n.substring(i+1);

  // Check American Express (3), VISA (4), Mastercard (5), and Discover (6).
  which = which ? (""+which).charAt(0).toUpperCase() : "";
  if (!(len=n.length) || ((digit=n.charAt(0))<"3" || digit>"6") ||
    (which && (which=="A" && digit!="3") || (which=="V" && digit!="4") ||
    (which=="M" && digit!="5") || (which=="D" && digit!="6")) ||
    (digit=="3" && len!=15) || (digit=="4" && (len!=13 && len!=16)) || 
    (digit=="5" && len!=16) || (digit=="6" && len!=16)) {
    if (isObj) {  // display error and reprompt if invalid bank card.
      alert("Please enter a valid bank card number.");
      if (theItem.focus) theItem.focus();
    }
    return '';
  }

  // Use the Luhn Check Digit Algorithm to perform the bank card checksum.
  for (var i = 0, tmp = 0, sum = 0, len = n.length-1; i < len; i++) {
    tmp = parseInt(n.charAt(len - i - 1)) * (1 + ((i + 1) % 2));
    sum += ((tmp < 10) ? tmp : (tmp - 9));
  }
  if ((10 - (sum % 10)) != n.charAt(len)) {
    if (isObj) {  // display error and reprompt if invalid bank card.
      alert("Please enter a valid bank card number.");
      if (theItem.focus) theItem.focus();
    }
    return '';
  }

  // Save the valid bank card numeric digits.
  if (isObj) theItem.value = n;
  return n;
}

// Verify and save order information.
// Parameter:
//   "theForm" is the form containing the order information.
function verifyOrder(theForm) {
  var i, j, el, info="", name, value, tmp;
  if (typeof theForm.action != "object") {            // check secure server
    var pos = theForm.action.indexOf(":");
    var type = (pos > 0) ? theForm.action.substring(0,pos+1) : location.protocol;
    if (type.toLowerCase() != "https:")
      if (!confirm("This order form is not secure.\nDo you want to submit the order anyway?"))
        return false;
  }

  // Loop to check each field in the order form.
  for (i = 0; i < theForm.elements.length; i++) {
    el = theForm.elements[i]; name = el.name.toLowerCase();
    if ((theForm.elements["ship-bill"].checked && name.indexOf("bill") == 0) ||
      (el.type && el.type == "hidden")) continue;     // skip hidden & same info

    if (el.type && el.type.indexOf("select") >= 0) {  // fill select list
      for (value = "", j = el.selectedIndex; j < el.options.length; j++)
        if (el.options[j].selected) {
          if (value.length) value += ItemSepr;
          value += ((tmp = el.options[j].value)?tmp:el.options[j].text);
        }
    } else fillOrderName(theForm, name, (value = el.value));

    if (!value) {                     // check for required fields
      if (name.indexOf("address2") < 0 && name.indexOf("phone") < 0 && 
        name.indexOf("email") < 0 && name.indexOf("comments") < 0 &&
        name.indexOf("opt") != 0) {
        alert("Please enter missing information.");
        if (el.focus) el.focus();
		return false;
      }

    } else if (theForm.elements["save"].checked &&   // save shipping info
      (name.indexOf("ship") == 0 || name.indexOf("bill") == 0)) {
      info += (AttrSepr+name+ValueSepr+value);
    }
  }

  // Create a cookie to hold the shipping info.
  var expdate = new Date();
  FixCookieDate(expdate); // Correct Mac date bug - call once for given Date
  expdate.setTime(expdate.getTime() + (365 * 86400 * 1000)); // 1 year from now 
  SetCookie ("shipInfo", info, expdate, "/");
  return true;
}

// Fill out first, last and full name information.
// Parameter:
//   "theForm" is the form where the order information is to be placed.
//   "name" is the name of the form field.
//   "value" is the name of the saved form field information.
var foundOnce = false;
function fillOrderName(theForm, name, value) {
  var i, pos = name.lastIndexOf("-"), tmp, el;
  if (pos <= 0 || !value) return;

  // Split full name into first and last name.
  if (name.substring(pos) == "-name") {
    var last = theForm.elements[name.substring(0,pos+1)+"lastname"];
    var first= theForm.elements[name.substring(0,pos+1)+"firstname"];
    if ((pos = value.lastIndexOf(",")) > 0) {         // lastname, firstname
      if (first && !first.value) {
        for(tmp=value.substring(pos+1),i=0;i<tmp.length && tmp.charAt(i)==" ";i++);
        first.value = tmp.substring(i);
      }
      if (last && !last.value) {
        for(tmp=value.substring(0,pos-1),i=tmp.length;i>0 && tmp.charAt(i-1)==" ";i--);
        last.value = tmp.substring(0,i);
      }
    } else if ((pos = value.indexOf(" ")) > 0) {      // firstname lastname
      if (first && !first.value) first.value = value.substring(0,pos);
      if (last && !last.value) {
        for (tmp=value.substring(pos+1),i=0;i<tmp.length && tmp.charAt(i)==" ";i++);
        last.value = tmp.substring(i);
      }
    }

  // Get full name by combining the first and last name.
  } else if ((tmp = name.substring(pos)) == "-firstname" || tmp == "-lastname") {
    el = theForm.elements[name.substring(0,pos+1)+"name"];
    if (el)
      if (!el.value) { el.value = value; foundOnce = true; }
      else if (foundOnce && el.value.indexOf(value) < 0) {
        if (tmp == "-lastname") el.value += " "+value;
        else el.value = value+" "+el.value;
      }
  }
}

// Automatically fill out information in the order form.
// Parameter:
//   "theForm" is the form where the order information is to be placed.
function filloutOrder(theForm) {
  var info = GetCookie("shipInfo");
  if (!info) return;

  // Loop to try to fill out each field in the order form.
  var el, pos, name, value, tmp, opt;
  for (var i = 0; i < theForm.elements.length; i++) {
    el = theForm.elements[i]; name = el.name.toLowerCase();
    if ((pos = info.indexOf(AttrSepr+name+ValueSepr)) < 0) continue;

    // Get the saved value for the order form field.
    value = (info+AttrSepr).substring(pos+name.length+2);
    value = value.substring(0,value.indexOf(AttrSepr));

    // Update the order form field with the saved value.
    if (el.type && el.type == "checkbox") el.checked = true;
    else if (!el.type || el.type.indexOf("select") < 0)  el.value = value;
    else while (value.length) {    // loop through single and multiple selections
      pos = (value+ItemSepr).indexOf(ItemSepr); tmp = value.substring(0,pos);
      for (var k = 0; k < el.options.length; k++) {
        opt = el.options[k].value || el.options[k].text;
        if (tmp==opt) { el.options[el.selectedIndex=k].selected = true; break; }
      }
      value = value.substring(pos+1);
    }
  }
}

// Cookie Functions ----------------------------------------------------------

// For information on the significance of cookie parameters, and on cookies in
// general, please refer to the official cookie spec, at:
//     http://home.netscape.com/newsref/std/cookie_spec.html

// ---------------------------------------------------------------------------

// "Internal" function to return the decoded value of a cookie
// Parameter:
//   "offset" is the position where the value of the specific cookie begins.
function getCookieVal(offset) {
  var endstr = document.cookie.indexOf (";", offset);
  if (endstr < 0) endstr = document.cookie.length;
  return unescape(document.cookie.substring(offset, endstr));
}

// Correct the 2.x Mac date bug.  
// Parameter:
//   "date" is the date to be fixed.
//
// Important Notes:
//   Call this function to fix a date object prior to passing it to SetCookie.
//   This function should only be called *once* for any given date object!  
//   See example at the end of this document.
function FixCookieDate(date) {
  var skew = (new Date(0)).getTime();  // dawn of (Unix) time - should be 0
  if (skew > 0) date.setTime (date.getTime() - skew);
}

// Return the value of the cookie specified by "name".
// Parameter:
//   "name" is a string object containing the cookie name.
//   The return value is a string object containing the existing
//   cookie value (which may be an empty string), or null if the 
//   cookie does not exist.
function GetCookie(name) {
  var arg = name+"=", j;
  for (var alen=arg.length, clen=document.cookie.length, i=0; i < clen; ) {
    j = i + alen;
    if (document.cookie.substring(i,j) == arg) return getCookieVal(j);
    i = document.cookie.indexOf(" ",i) + 1;
    if (i == 0) break; 
  }
  return null;
}

// Create or update a cookie.
// Parameters:
//   "name" is a string object containing the cookie name.
//   "value" is a string object containing the cookie value.
//   [expires] is a date object containing the expiration date of
//     the cookie.  If omitted or null, expires the cookie at the
//     end of the current session.
//   [path] is a string object indicating the path for which the 
//      cookie is valid. If omitted or null, uses the path of the 
//      calling document.
//   [domain] is a string object indicating the domain for which 
//      the cookie is valid.  If omitted or null, uses the domain 
//      of the calling document.
//   [secure] is a boolean (true/false) value indicating whether 
//      cookie transmission requires a secure channel (HTTPS).  
//
// The first two parameters are required.  The others, if supplied, 
// must be passed in the order listed above.  To omit an unused 
// optional field, use null as a place holder.  For example, to 
// call SetCookie using name, value and path, you would code:
//     SetCookie("myCookieName", "myCookieValue", null, "/");
//
// Trailing omitted parameters do not require a placeholder.
//
// To set a secure cookie for path "/myPath", that expires after 
// the current session, you might code:
//     SetCookie("name", "value", "/myPath", null, true);
//
function SetCookie(name,value,expires,path,domain,secure) {
  document.cookie = name+"="+escape(value)+
    (expires?"; expires="+expires.toGMTString():"")+(path?"; path="+path:"")+
    (domain?"; domain="+domain:"")+(secure?"; secure":"");
}

// Delete a cookie. (Sets expiration date to start of epoch)
//   "name" is a string object containing the cookie name
//   [path] is a string object containing the path of the cookie 
//            to delete.  This MUST be the same as the path used 
//            to create the cookie, or null/omitted if no path 
//            was specified when creating the cookie.
//   [domain] is a string object containing the domain of the 
//            cookie to delete.  This MUST be the same as the 
//            domain used to create the cookie, or null/omitted 
//            if no domain was specified when creating the cookie.
function DeleteCookie(name,path,domain) {
  if (GetCookie(name)) document.cookie = name+"="+(path?"; path="+path:"")+
    (domain?"; domain="+domain:"")+"; expires=Thu, 01-Jan-70 00:00:01 GMT";
}

// Examples:
//   var expdate = new Date ();
//   FixCookieDate(expdate); // Correct Mac date bug - call once for given Date
//   expdate.setTime(expdate.getTime() + (24 * 60 * 60 * 1000)); // 24 hrs from now 
//   SetCookie ("ccpath", "http://www.hidaho.com/colorcenter/", expdate);

// End external Javascript Shopping Cart source routines. --------------------
