function chkCookie(name) {
	var labelName = name + '=';
	var ca = document.cookie.split(';');
	for(var i=0;i < ca.length;i++) {
		var c = ca[i];
		while (c.charAt(0)==' ') c = c.substring(1,c.length);
		if (c.indexOf(labelName) == 0)
		{
			return c.substring(labelName.length,c.length);
		}
	}
	return null;
}

;(function(){
	function update(array, args)
	{
		var aryLen = array.length, 
			argLen = args.length;
		
		while(argLen--)
			array[aryLen + argLen] = args[argLen];
		
		return array;
	}
	
	function merge(array, args)
	{
		return update(Array.prototype.slice.call(array, 0), args);
	}
	
	Function.prototype.expose = function(context)
	{
		if(arguments.length < 2 && typeof arguments[0] === 'undefined') 
			return this;
			
		var __function = this,
			__args = Array.prototype.slice(arguments, 1);
			
		return function() {
			var args = merge(__args, arguments);
			return __function.apply(context, args);
		}
	}
	
	Function.prototype.argNames = function() {
		var names = this.toString().match(/^[\s\(]*function[^(]*\(([^)]*)\)/)[1]
								   .replace(/\/\/.*?[\r\n]|\/\*(?:.|[\r\n])*?\*\//g, '')
								   .replace(/\s+/g, '').split(',');
		
		return names.length == 1 && !names[0] ? [] : names;
	}
	
	Function.prototype.delay = function(timeout)
	{
	   var __function = this,
		  args = Array.prototype.slice(arguments, 1),
		  timeout = timeout * 1000;
		  
		  return window.setTimeout(function(){
			 return __function.apply(__function, args);
		  }, timeout);
	}
	
	Function.prototype.defer = function()
	{
	  var args = [0.01].concat(arguments);
	  
	  return this.delay.apply(this, args);
	}
})();
/***
 * Lowes Javascript Library.
 * 
 * This is licensed only for use in providing the Lowes.com service, 
 * or any part thereof, and is subject to the Lowes.com Terms and Conditions. 
 * You may not port this file to another platform without Lowes.com's written consent. 
 **/

;(function()  {
/**
 * Library for native String extensions
 */
	
/**
 * Extend String to add format ($$) function that will
 * mimic C's sprintf function. Replace %@ character set
 * with param/values passed to the method.
 *
 * @package String
 */

String.prototype.format = String.prototype.$$ = function() 
{
	// Grab all our arguments
	var args = arguments;
	
	// Predefined an loop index.
	var idx = 0;

	// return the replaced values
	return this.replace(/%@([0-9]+)?/g, function(s, argIndex) 
	{
		argIndex = (argIndex) ? parseInt(argIndex,0)-1 : idx++;
		s = args[argIndex];

		return ((s===null) ? '(null)' : (s===undefined) ? '' : s).toString();
	});
}

/**
 * Extend String to add words (w) method that will split
 * a space seperated string into an array
 *
 * @package String
 */
String.prototype.words = String.prototype.w = function()
{
	return this.split(' ');
}

/**
 * Extend String to add method to uppercase just
 * the first word of a sentence.
 *
 * @package String
 */
String.prototype.ucFirstSentence = function()
{
	/* Grab first letter, uppercase it, and put it back together with rest of the string */
	return this.substring(0,1).toUpperCase() + this.substring(1, this.length);
}

/**
 * Extend String to add method to uppercase the first letter
 * of each word in a sentence.
 *
 * @package String
 */
String.prototype.ucFirstWord = function()
{
	/* Grab an array of words from passed sentence */
	var stringArray = this.w();
	
	/* Setup complete string container var */
	var finalString = '';
	
	/***
	 * Loop through all words in the string array, change the 
	 * first letter of current word to a capital letter, and put 
	 * back together with the rest of the word 
	 **/
	for(item in stringArray)
		finalString += stringArray[item].substring(0,1).toUpperCase() + stringArray[item].substring(1, stringArray[item].length) + ' ';
	
	/* Trim/Clean up the final string and return it */
	return finalString.substring(0, (finalString.length - 1));
}

/***
 * Extend String to add method that will take camelCase
 * syntax and convert it into a space seperated 'sentence'
 *
 * @package String
 **/
String.prototype.deCamel = function()
{
	/* Look for camelCase pattern, replace with character, set to lower case and return value */
	return this.replace(new RegExp("([A-Z])", "g"), (typeof arguments[0] !== 'undefined')? arguments[0] : "_" + "$1").toLowerCase();
}

/**
 * Extend String to add method that will parse and convert links to
 * valid html (a) links.
 *
 * @package String
 */
String.prototype.linkify = function()
{
	/***
	* Extend String to add a parse routine to convert urls to links. Adding
	* html into the string.
	**/
	return (function(urlString){
		/* Setup matching pattern to patch http/s, ftp, file url types */
		var pattern = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig;
		
		/***
		 * If there is www with no protocol:// pattern, we need 
		 * to go a head and add it so the pattern replace will work.
		 *
		 * Note: this will not parse anything without www., unless
		 * it begins with protocol://
		 **/
		return (!urlString.match(pattern))? 
			urlString.replace('www.', 'http://').replace(pattern,"<a href='$1'>$1</a>") : 
			urlString.replace(pattern,"<a href='$1'>$1</a>");		
	})(this);
}


/**
 * Extend String to include a method that will add
 * escape slashes to strings.
 *
 * @package String
 */
String.prototype.addslashes = function() 
{
	var str = this;
	str=str.replace(/\'/g,'\\\'');
	str=str.replace(/\"/g,'\\"');
	str=str.replace(/\\/g,'\\\\');
	str=str.replace(/\0/g,'\\0');
	return str;
},

/**
 * Extend String to include a method that will remove
 * escape slashes from strings.
 *
 * @package String
 */
String.prototype.stripslashes = function() 
{
	var str = this;
	str=str.replace(/\\'/g,'\'');
	str=str.replace(/\\"/g,'"');
	str=str.replace(/\\\\/g,'\\');
	str=str.replace(/\\0/g,'\0');
	return str;
},

/**
 * Extend String to include a method that will remove
 * dead space from the begining and end of a string.
 *
 * @package String
 */
String.prototype.trim = function(str)
{
	return this.replace(/(?:^\s+|\s+$)/g, "");
}

})();
;(function(){
	Array.prototype.remove = function(from, to)
	{
		var rest = this.splice((to || from) + 1 || this.length);
		this.length = from < 0? this.length + from : from;
		
		return this.push.apply(this, rest);
	}
})();
/***
 * Lowes Javascript Library.
 * 
 * This is licensed only for use in providing the Lowes.com service, 
 * or any part thereof, and is subject to the Lowes.com Terms and Conditions. 
 * You may not port this file to another platform without Lowes.com's written consent. 
 **/

;(function(){
	/***
	 * Native Object utilities/methods
	 **/
	
	function size(object)
	{
		var size = 0,
			key;

		for(key in object)
		{
			if(object.hasOwnProperty(key))
				size++;
		}

		return size;
	}
	
	/***
	 * Method for extending an Object's context
	 **/
	function extend(destination, source)
	{
		for(var item in source)
			destination[item] = source[item];
		
		return destination;
	}
	
	/***
	 * Take one Object and return an exact copy of it
	 **/
	function clone(object)
	{
		return extend({}, object);
	}
	
	/***
	 * Extend native Object element to add functionality
	 * and make the methods globally accessible through the 
	 * native Object
	 **/
	extend(Object, {
		extend: extend,
		clone: clone,
		size: size
	});
})();
(function(){
  var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
  // The base Class implementation (does nothing)
  this.Class = function(){};
  
  // Create a new Class that inherits from this class
  Class.extend = function(prop) {
	var _super = this.prototype;
	
	// Instantiate a base class (but only create the instance,
	// don't run the init constructor)
	initializing = true;
	var prototype = new this();
	initializing = false;
	
	// Copy the properties over onto the new prototype
	for (var name in prop) {
	  // Check if we're overwriting an existing function
	  prototype[name] = typeof prop[name] == "function" && 
		typeof _super[name] == "function" && fnTest.test(prop[name]) ?
		(function(name, fn){
		  return function() {
			var tmp = this._super;
			
			// Add a new ._super() method that is the same method
			// but on the super-class
			this._super = _super[name];
			
			// The method only need to be bound temporarily, so we
			// remove it when we're done executing
			var ret = fn.apply(this, arguments);		
			this._super = tmp;
			
			return ret;
		  };
		})(name, prop[name]) :
		prop[name];
	}
	
	// The dummy class constructor
	function Class() {
	  // All construction is actually done in the init method
	  if ( !initializing && this.init )
		this.init.apply(this, arguments);
	}
	
	// Populate our constructed prototype object
	Class.prototype = prototype;
	
	// Enforce the constructor to be what we expect
	Class.constructor = Class;

	// And make this class extendable
	Class.extend = arguments.callee;
	
	return Class;
  };
})();
/*
	http://www.JSON.org/json2.js
	2010-08-25

	Public Domain.

	See http://www.JSON.org/js.html

	This is a reference implementation. You are free to copy, modify, or
	redistribute.
*/

// Create a JSON object only if one does not already exist. We create the
// methods in a closure to avoid creating global variables.

if (!this.JSON) {
	this.JSON = {};
}

(function () {

	function f(n) {
		// Format integers to have at least two digits.
		return n < 10 ? '0' + n : n;
	}

	if (typeof Date.prototype.toJSON !== 'function') {

		Date.prototype.toJSON = function (key) {

			return isFinite(this.valueOf()) ?
				   this.getUTCFullYear()   + '-' +
				 f(this.getUTCMonth() + 1) + '-' +
				 f(this.getUTCDate())	   + 'T' +
				 f(this.getUTCHours())	   + ':' +
				 f(this.getUTCMinutes())   + ':' +
				 f(this.getUTCSeconds())   + 'Z' : null;
		};

		String.prototype.toJSON =
		Number.prototype.toJSON =
		Boolean.prototype.toJSON = function (key) {
			return this.valueOf();
		};
	}

	var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
		escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
		gap,
		indent,
		meta = {	// table of character substitutions
			'\b': '\\b',
			'\t': '\\t',
			'\n': '\\n',
			'\f': '\\f',
			'\r': '\\r',
			'"' : '\\"',
			'\\': '\\\\'
		},
		rep;


	function quote(string) {

// If the string contains no control characters, no quote characters, and no
// backslash characters, then we can safely slap some quotes around it.
// Otherwise we must also replace the offending characters with safe escape
// sequences.

		escapable.lastIndex = 0;
		return escapable.test(string) ?
			'"' + string.replace(escapable, function (a) {
				var c = meta[a];
				return typeof c === 'string' ? c :
					'\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
			}) + '"' :
			'"' + string + '"';
	}


	function str(key, holder) {

// Produce a string from holder[key].

		var i,			// The loop counter.
			k,			// The member key.
			v,			// The member value.
			length,
			mind = gap,
			partial,
			value = holder[key];

// If the value has a toJSON method, call it to obtain a replacement value.

		if (value && typeof value === 'object' &&
				typeof value.toJSON === 'function') {
			value = value.toJSON(key);
		}

// If we were called with a replacer function, then call the replacer to
// obtain a replacement value.

		if (typeof rep === 'function') {
			value = rep.call(holder, key, value);
		}

// What happens next depends on the value's type.

		switch (typeof value) {
		case 'string':
			return quote(value);

		case 'number':

// JSON numbers must be finite. Encode non-finite numbers as null.

			return isFinite(value) ? String(value) : 'null';

		case 'boolean':
		case 'null':

// If the value is a boolean or null, convert it to a string. Note:
// typeof null does not produce 'null'. The case is included here in
// the remote chance that this gets fixed someday.

			return String(value);

// If the type is 'object', we might be dealing with an object or an array or
// null.

		case 'object':

// Due to a specification blunder in ECMAScript, typeof null is 'object',
// so watch out for that case.

			if (!value) {
				return 'null';
			}

// Make an array to hold the partial results of stringifying this object value.

			gap += indent;
			partial = [];

// Is the value an array?

			if (Object.prototype.toString.apply(value) === '[object Array]') {

// The value is an array. Stringify every element. Use null as a placeholder
// for non-JSON values.

				length = value.length;
				for (i = 0; i < length; i += 1) {
					partial[i] = str(i, value) || 'null';
				}

// Join all of the elements together, separated with commas, and wrap them in
// brackets.

				v = partial.length === 0 ? '[]' :
					gap ? '[\n' + gap +
							partial.join(',\n' + gap) + '\n' +
								mind + ']' :
						  '[' + partial.join(',') + ']';
				gap = mind;
				return v;
			}

// If the replacer is an array, use it to select the members to be stringified.

			if (rep && typeof rep === 'object') {
				length = rep.length;
				for (i = 0; i < length; i += 1) {
					k = rep[i];
					if (typeof k === 'string') {
						v = str(k, value);
						if (v) {
							partial.push(quote(k) + (gap ? ': ' : ':') + v);
						}
					}
				}
			} else {

// Otherwise, iterate through all of the keys in the object.

				for (k in value) {
					if (Object.hasOwnProperty.call(value, k)) {
						v = str(k, value);
						if (v) {
							partial.push(quote(k) + (gap ? ': ' : ':') + v);
						}
					}
				}
			}

// Join all of the member texts together, separated with commas,
// and wrap them in braces.

			v = partial.length === 0 ? '{}' :
				gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
						mind + '}' : '{' + partial.join(',') + '}';
			gap = mind;
			return v;
		}
	}

// If the JSON object does not yet have a stringify method, give it one.

	if (typeof JSON.stringify !== 'function') {
		JSON.stringify = function (value, replacer, space) {

// The stringify method takes a value and an optional replacer, and an optional
// space parameter, and returns a JSON text. The replacer can be a function
// that can replace values, or an array of strings that will select the keys.
// A default replacer method can be provided. Use of the space parameter can
// produce text that is more easily readable.

			var i;
			gap = '';
			indent = '';

// If the space parameter is a number, make an indent string containing that
// many spaces.

			if (typeof space === 'number') {
				for (i = 0; i < space; i += 1) {
					indent += ' ';
				}

// If the space parameter is a string, it will be used as the indent string.

			} else if (typeof space === 'string') {
				indent = space;
			}

// If there is a replacer, it must be a function or an array.
// Otherwise, throw an error.

			rep = replacer;
			if (replacer && typeof replacer !== 'function' &&
					(typeof replacer !== 'object' ||
					 typeof replacer.length !== 'number')) {
				throw new Error('JSON.stringify');
			}

// Make a fake root object containing our value under the key of ''.
// Return the result of stringifying the value.

			return str('', {'': value});
		};
	}


// If the JSON object does not yet have a parse method, give it one.

	if (typeof JSON.parse !== 'function') {
		JSON.parse = function (text, reviver) {

// The parse method takes a text and an optional reviver function, and returns
// a JavaScript value if the text is a valid JSON text.

			var j;

			function walk(holder, key) {

// The walk method is used to recursively walk the resulting structure so
// that modifications can be made.

				var k, v, value = holder[key];
				if (value && typeof value === 'object') {
					for (k in value) {
						if (Object.hasOwnProperty.call(value, k)) {
							v = walk(value, k);
							if (v !== undefined) {
								value[k] = v;
							} else {
								delete value[k];
							}
						}
					}
				}
				return reviver.call(holder, key, value);
			}


// Parsing happens in four stages. In the first stage, we replace certain
// Unicode characters with escape sequences. JavaScript handles many characters
// incorrectly, either silently deleting them, or treating them as line endings.

			text = String(text);
			cx.lastIndex = 0;
			if (cx.test(text)) {
				text = text.replace(cx, function (a) {
					return '\\u' +
						('0000' + a.charCodeAt(0).toString(16)).slice(-4);
				});
			}

// In the second stage, we run the text against regular expressions that look
// for non-JSON patterns. We are especially concerned with '()' and 'new'
// because they can cause invocation, and '=' because it can cause mutation.
// But just to be safe, we want to reject all unexpected forms.

// We split the second stage into 4 regexp operations in order to work around
// crippling inefficiencies in IE's and Safari's regexp engines. First we
// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
// replace all simple value tokens with ']' characters. Third, we delete all
// open brackets that follow a colon or comma or that begin the text. Finally,
// we look to see that the remaining characters are only whitespace or ']' or
// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.

			if (/^[\],:{}\s]*$/
.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
.replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {

// In the third stage we use the eval function to compile the text into a
// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
// in JavaScript: it can begin a block or an object literal. We wrap the text
// in parens to eliminate the ambiguity.

				j = eval('(' + text + ')');

// In the optional fourth stage, we recursively walk the new structure, passing
// each name/value pair to a reviver function for possible transformation.

				return typeof reviver === 'function' ?
					walk({'': j}, '') : j;
			}

// If the text is not JSON parseable, then a SyntaxError is thrown.

			throw new SyntaxError('JSON.parse');
		};
	}
}());
/**
 * Lowes Javascript Library.
 * 
 * This is licensed only for use in providing the Lowes.com service, 
 * or any part thereof, and is subject to the Lowes.com Terms and Conditions. 
 * You may not port this file to another platform without Lowes.com's written consent. 
 */


/**
 * Lowes Namespace Object that will be the parent of all 
 * Lowes JS library classes.  
 *
 * @Package: Lowes
 * @Author WCope
 * @version 1.0.0
 */

;(function($){

	// If Lowes object has already been created, use it,
	// other wise create a new Lowes Namespace.
	var Lowes = window.Lowes || {}
	Lowes.Version = "1.0.0";
	/**
	 * Class that contains core methods for use in the
	 * Lowesjs framework.  Contains all utility methods.
	 *
	 * @class Lowes.Core	
	 */
	var Core = Class.extend({
		/**
		 * Initial method called when class instance
		 * is created.
		 *
		 * @constructor
		 */
		init: function()
		{
			var params;
			
			// Loop all Lowes.js script includes.
			 $('head script[src*=lowes.js]').each(function(){
					// Create script element object.
					var $this = $(this);
					var settings = {};
					
					// Grab the src attribute and remove settings off the end, 
					// and add it to the loca settings object. 
					$this.attr('src').replace(new RegExp("([^?=&]+)(=([^&]*))?", "g"), function(){
						settings[arguments[1]] = arguments[3];
					});
					
					// Override the class defaults for the following settings.
					Lowes.DEBUG = settings.debug || false;
			})
			
			// Quick check for console.
			this.__consoleLogCheck();
			
			// Browser test object
			this.__getBrowser();
		},
		
		/**
		 * Make sure we have a console to use (Thanks IE).
		 *
		 * @private
		 */
		__consoleLogCheck: function()
		{
			// If it's not there, set it empty.
			if(!window.console)
				window.console = { log: function() {}, dir: function() {} };
		},
		
		/**
		 * Just setup a Browser object to test against.
		 *
		 * @private
		 **/
		__getBrowser: function()
		{
			// Add a Browser object to Lowes global namespace.
			Lowes.Browser = (function(){
				// Grab the user agent.
				var userAgent = navigator.userAgent;
				
				// Go ahead and get the odd ball out the way.
				var isOpera = Object.prototype.toString.call(window.opera) == '[object Opera]';
				
				// Return an object easy to test against
				return {
					IE:				  !!window.attachEvent && !isOpera,
					Opera:		   isOpera,
					Safari:			  /(chrome).*(safari)/ig.test(userAgent)? false : true,
					Chrome:			  /(chrome).*(safari)/ig.test(userAgent)? true : false,
					Firefox:	   /(firefox)/ig.test(userAgent),
					MobileSafari:  /apple.*mobile/ig.test(userAgent)
				}
			})();
		}
	});
	
	// Expose Lowes to the world.
	window.Lowes = Lowes;
	
	// Expose core class to Lowes object
	window.Lowes.Core = Core;
	
	// Let's run this badboy!
	new Lowes.Core();
})(jQuery);
/**
 * Lowes Javascript Library.
 * 
 * This is licensed only for use in providing the Lowes.com service, 
 * or any part thereof, and is subject to the Lowes.com Terms and Conditions. 
 * You may not port this file to another platform without Lowes.com's written consent. 
 */

/**
 * @Package Lowes.Cookie
 * @Author WCope
 * @version <%=VERSION=%>
 */

(function(){
	// Grab Lowes namespace object or create a new one.
	var Lowes = window.Lowes || {};

	/**
	 * Class for working with browser cookies. Simplifies setting, getting, deleting
	*
	 * @class Lowes.Cookie
	 */
	var Cookie = Class.extend({
	   /**
		* Default method called when Cookie class is instantiated.
		*
		* @constructor
		*/
	  init: function()
	  {
		 // Right now i can't see doing anything here,
		 // but we will leave it for good measure.
	  },
	  
	  /**
	   * Cookie class method to retreive a cookie from the
	   * browser with a specified name.
	   *
	   * @param {String} Name of the cookie.
	   */
	  get: function(name)
	  {
		var ck = readCookie(name);
		if(ck)
		{
			return ck;
		}
		else
		{
			return {};
		}
	  },
	  
	  /**
	   * Create a cookie and set it's value in the browser.
	   *
	   * @param {String} The name of the cookie to create
	   * @param {String} The value to set the cookie with given name
	   * @param {String} The date of expiration
	   */
	set: function(name, value, date)
	{
		createCookie(name, value, date);
	  },
	  
	  /**
	   * Cookie class method to remove a cookie from the browser
	   *
	   * @params {String} Name of cookie to delete 
	   */
	  del: function(name)
	  {
		 // To delete, we just the value to nothing and 
		 // force it to expire.
		 this.set(name, "",- 1);
	  }
   });

   // Add the Cookie Class to Lowes namespace
   Lowes.Cookie = Cookie;
   
   // Expose the updated Lowes namespace to the world
   window.Lowes = Lowes;
})();
/**
 * Lowes Javascript Library.
 * 
 * This is licensed only for use in providing the Lowes.com service, 
 * or any part thereof, and is subject to the Lowes.com Terms and Conditions. 
 * You may not port this file to another platform without Lowes.com's written consent. 
 */

/**
 * @Package Lowes.Prefs
 * @Author Wcope
 * @version <%=VERSION=%>
 */

(function(){
   // Grab Lowes namespace object or create a new one.
   var Lowes = window.Lowes || {};
   
   /**
	* Simplified Cookie based preferences for users
	*/
   var Prefs = {
	  // Stores our preferences, key/value pair.
	  data: { },
	  cookie: new Lowes.Cookie(),

	  /**
	   * Grabs our preferences cookie (json string) and 
	   * loads the result object into our local object.
	   */
	  load: function()
	  {
		//read cookie, get() returns cookie value
		 var prefsCookie = this.cookie.get("lowes-prefs");

		 if(typeof prefsCookie !== 'undefined')
		 {
			try {
				this.data = JSON.parse(prefsCookie);
			}
			catch(e) {
				//error handling
			}
			
		 }
	  },
	  
	  /**
	   * Saves our preferences, as a JSON string, to our cookie path
	   *
	   * @param {Date} Date object for when cookie should expire.
	   * @param {String} Path to set the cookie too.
	   */
	  save: function(expires, path)
	  {
		 // Store our cookie
		 this.cookie.set('lowes-prefs', JSON.stringify(this.data), "");
		 //createCookie('lowes-prefs', JSON.stringify(this.data), null);
	  }
   };
   
   // Add our class to Lowes namespace
   Lowes.Prefs = Prefs;
   // Expose Updated Lowes namespace to global.
   window.Lowes = Lowes;
})();
/**
 * Lowes Javascript Library.
 * 
 * This is licensed only for use in providing the Lowes.com service, 
 * or any part thereof, and is subject to the Lowes.com Terms and Conditions. 
 * You may not port this file to another platform without Lowes.com's written consent. 
 */

/**
 * @Package Lowes.Utils
 * @Author WCope
 * @version <%=VERSION=%>
 */

(function(){
	// Grab Lowes namespace object or create a new one.
	var Lowes = window.Lowes || {};
	
	Lowes.PageTypes = {
		Other		: 0,
		List		: 1,
		Details		: 2,
		Category	: 3
	};
	
	var Utils = Class.extend({
	/**
	 * Initial method called when class is instantiated
	 */
	init: function() 
	{
		// Blank for now.
	},
	   
	/**
	 * Convert URL query string into a native javascript object.
	 */
	urlQueryObject: function()
	{
		// Wrap in a closure since we are dealing with a global object "window.location"
		return (function(){
			// Split off our url query string and setup our result object
			var query = window.location.href.split('?')[1],
			qryObject = {};

			if ( typeof query == 'undefined' ) {
				return qryObject;
			}
				 
			
			 // Split the query string again to seperate query params.
			query = query.split('&');
			
			// Loop through our params
			for(var i=0; i < query.length; i++)
			{
			   // Split the query param string into a key/value based of '='
			   var keyVal = query[i].split('=');

			   // Add our key/value to our result object.
			   qryObject[keyVal[0]] = keyVal[1];
			}
			
			// Hand the result object back.
			return qryObject;
		  });
	   },
	   
	   /**
		* Convert a javascript object into a url query string
		*
		* @param {Object} Passed to be converted.
		*/
		urlQueryString: function(object)
		{
			// Setup our result string.
			var query = "";
		   
			// Loop through object items and convert it to a key/value string.
			for(var item in object) {
				query += "%@=%@&".$$(item, object[item]);
			}
			  
		  // Strip off the trialing & and return the value
		  return query.substring(0, (query.length -1));
		},
		
		/**
		 * Simple random number generator
		 *
		 * @param {Integer} The starting number for range.
		 * @param {Integer} The ending number for the range.
		 */
		randomNumber: function(from, to)
	   {
		  // Just make sure our from and to are integers.
		  from = parseInt(from);
		  to = parseInt(to);

		  // return a random number between our params.
		  return Math.floor(Math.random() * ( to - from )) + from;
	   },
	   
		getLowesPageType: function()
		{
			if( document.location.href.indexOf('pc_') !== -1 ) {
			
				return Lowes.PageTypes.Category;
			
			} else if ( document.location.href.indexOf('pl_') !== -1 ) {
			
				return Lowes.PageTypes.List;
			
			} else if ( document.location.href.indexOf('pd_') !== -1 ) {
			
				return Lowes.PageTypes.Details;
			
			} else {
			
				return Lowes.PageTypes.Other;
			}
		}
	});
	
	// Add our class to Lowes namespace
	Lowes.Utils = Utils;
	
	// Expose Updated Lowes namespace to global.
	window.Lowes = Lowes;
})();
/**
 * Lowes Javascript Library.
 * 
 * This is licensed only for use in providing the Lowes.com service, 
 * or any part thereof, and is subject to the Lowes.com Terms and Conditions. 
 * You may not port this file to another platform without Lowes.com's written consent. 
 */

/**
 * Lowes.UI Namespace Object that will be the parent of all 
 * Lowes UI components library classes.	 
 *
 * @Package: Lowes.UI
 * @Author WCope
 * @version <%=VERSION=%>
 */

;(function($){
	// Grab Lowes namespace object or create a new one.
	var Lowes = window.Lowes || {};


	// Grab Lowes UI namespace object or create a new one.
	Lowes.UI = Lowes.UI || {};

	// Silly I know, just some consts for position.
	Lowes.UI.position = {
		TOP: 0,
		BOTTOM: 1,
		LEFT: 2,
		RIGHT: 3
	};


	/**
	 * Base class that will contain common methods
	 * used across all UI components.
	 *
	 * @class Lowes.UI.Core
	 */
	var Core = Class.extend({
		
		/**
		 * Initial method called when class instance
		 * is created.
		 *
		 * @constructor
		 */
		init: function()
		{
		}
	})

	Lowes.UI.Core = Core;
	window.Lowes = Lowes;
})(jQuery);
/**
 * Lowes Javascript Library.
 * 
 * This is licensed only for use in providing the Lowes.com service, 
 * or any part thereof, and is subject to the Lowes.com Terms and Conditions. 
 * You may not port this file to another platform without Lowes.com's written consent. 
 */

/**
 * @Package Lowes.UI.Accordion
 * @member Lowes.UI
 * @Author WCope
 * @version <%=VERSION=%>
 */

;(function($){
	// Grab Lowes namespace object or create a new one.
	var Lowes = window.Lowes || {};

	// Grab Lowes UI namespace object or create a new one.
	Lowes.UI = Lowes.UI || {};
	
	// Quick check to make sure our UI.Core class is there
	// to extend or create a new one.
	Lowes.UI.Core = Lowes.UI.Core || Class.extend({});
	
	/**
	 * Class for creating and managing
	 * the Accordion UI Component.
	 *
	 * @class Lowes.UI.Accordion
	 */
	var Accordion = Lowes.UI.Core.extend({
		
		/**
		 * Initialize the Accordion object and setup options
		 *
		 * @constructor
		 * @param {String} Selector for html element that contains Accordion elements.
		 * @param {Object} Options to use when setting up the component.
		 */
		init: function(container, options)
		{
			if(!Lowes.DEBUG && $(container).length < 1)
				return; 
			// Check to make sure we have a container param.
			if(typeof container !== 'string' || typeof container === 'undefined')
				throw "No container element (selector) provided to create Accordion";
			else
				this.container = container;

			// Check to make sure that if options were passed, they are objects.
			if(Lowes.DEBUG && typeof options !== 'undefined' && typeof options !== 'object')
				throw "Accordion options param must be an object";
			
			// Setup options, if not defined fall back to defaults.
			var options			= options || {};
			this.defaultClass	= options.defaultClass	|| false;
			this.effect			= options.effect		|| 'fade';
			this.handles		= options.handles		|| "h2 > a";
			this.contents		= options.contents		|| "div";
			this.starting		= options.starting		|| function() {};
			this.finished		= options.finished		|| function() {};
			this.fireEvent		= options.event			|| 'click';
			this.speed			= options.speed			|| 'fast';
			this.leaveOpen		= options.leaveOpen		|| false;
		},
		
		/**
		 * Method handle creating the event handlers for
		 * component interaction.
		 */
		create:function()
		{
			// Give elements context within container so calls to index() won't involve the entire DOM
			this.handles = "%@ > %@".$$(this.container, this.handles);
			
			this.contents = "%@ > %@".$$(this.container, this.contents);
			
			this.defaultClass = "%@ > %@".$$(this.container, this.defaultClass);
			
			// We just need to assign our event listener to our handle elements.
			$(this.handles).live(this.fireEvent, (this.leaveOpen)? this.__bindEventLeaveOpen.expose(this) : this.__bindEventSingleShow.expose(this));
			
			// Unless we want to leave content open, let's make sure all are closed
			// unless the defaultClass is set and a content element has it set.
			if(!this.leaveOpen)
			{
				// Grab our content elements
				var contents = $(this.contents);
				// Close them all
				contents.css("display", 'none');

				// If we have a default class, let's show that one.
				if(this.defaultClass)
				{
					// Get element that is open by default
					var defaultOpenElement = $(this.defaultClass);
					
					// Show it and add styling class of "active"
					defaultOpenElement.css('display', 'block').addClass('active');
					
					// Get index of default opened element for referencing its corresponding tab
					var index = defaultOpenElement.index(this.contents);
					
					// Make sure we style handle, too
					$($(this.handles)[index]).addClass('active');
				}
			}
		},
		
		/**
		 * When the assigned event is fired, excute content displaying/movement.
		 * but leave the rest of the content areas open (toggle with handle click).
		 *
		 * @private
		 * @param {Object} The event object.
		 */
		__bindEventLeaveOpen: function(event)
		{
			// Keep it from doing whatever it is it does.
			event.preventDefault();
			
			// Grab our current handle HTML object.
			var handle = $(event.currentTarget);
			
			// Remove the active class from the previously active handle
			handle.toggleClass('active');
			
			// Current handle tag.
			var handleElement = event.currentTarget;
			
			// Handle's index.
			var index = handle.index(this.handles);
			
			// All the content elements that correspond with it's handle
			var contents = $(this.contents);
			
			// Active content element.
			var relatedContent = contents[index];
			var active = $(relatedContent);
			
			// If we have a url to pull content from for our active content element
			// Pull it and set the html of our active content to the returned response.
			if(typeof active.attr('href') !== 'undefined' && active('attr') != '')
			{
				// Make nonasync ajax call (to wait for completion) and fill our active content element.
				active.html($.ajax({
					method: 'get',
					url: active.attr('href'),
					async:false,
					error: function(err)
					{
						throw err;
					}
				}).responseText);
			}

			active.toggleClass('active');

			// Effect toggle we have to use because jQuery only does slideToggle which is lame.
			active[ (active.css('display') == 'none')? this.__effectBuilder(true) : this.__effectBuilder(false) ](this.speed, this.finished.apply(this, [handleElement, relatedContent]));
		},
		
		/**
		 * When the assigned event is fired, excute content displaying/movement.
		 *
		 * @private
		 * @param {Object} The event object.
		 */
		__bindEventSingleShow: function(event)
		{
			// Keep it from doing whatever it is it does.
			event.preventDefault();
			
			// Grab the html element that fired the event.
			var handle = $(event.currentTarget);
			
			// Remove the active class from the previously active handle
			$(this.handles).filter('.active').removeClass('active');
			
			// Have a class to style for the firing tab
			handle.addClass('active');
			
			var handleElement = event.currentTarget;
			
			// The position of the handle
			var index = handle.index(this.handles);

			// Grab our related content area's that correspond with our handles.
			var contents = $(this.contents);

			// Content element related to target handle.
			var relatedContent = contents[index];
			
			$(relatedContent).addClass('active');
			
			// Call our starting method callback.
			this.starting.apply(this, [handleElement, relatedContent]);
			
			// Only execute if our content isn't showing.
			if($(relatedContent).css('display') == 'none')
			{
				// Just a check flag for when we start with all closed.
				var opened = false;
				
				// If so, loop through our contents
				for(var i=0; i < contents.length; i++)
				{

					// Grab our current content element from our loop
					var current = $(contents[i]);

					// If we need to, let's close it and open the related content index.
					if(current.css('display') != 'none')
					{
						current.removeClass('active');
						
						// Ok opening our active content now, so don't do it later.
						opened = true;
						
						// Close out our opened one, and when it's done, open the active one.
						current[this.__effectBuilder(false)](this.speed, function(event){
							// Related content html object.
							var active = $(contents[index]);

							// If we have a url to pull content from for our active content element
							// Pull it and set the html of our active content to the returned response.
							if(typeof active.attr('href') !== 'undefined' && active('attr') != '')
							{
								// Make nonasync ajax call (to wait for completion) and fill our active content element.
								active.html($.ajax({
									method: 'get',
									url: active.attr('href'),
									async:false,
									error: function(err)
									{
										throw err;
									}
								}).responseText);
							}

							// Show active content and call our finished callback method.
							active[this.__effectBuilder(true)](this.speed, this.finished.apply(this, [handleElement, relatedContent]));

						}.expose(this));
					}
				}
				
				// So none were open, let's open one now.
				if(!opened)
					$(contents[index])[this.__effectBuilder(true)](this.speed, this.finished.apply(this, [handleElement, relatedContent]));
			}
			
		},
		
		/**
		 * Quick method to get the proper effect to use when showing/hiding elements
		 *
		 * @private
		 * @param {BOOL} True to show, false to hide.
		 */
		__effectBuilder: function(display)
		{
			// Make sure we are given accepted effects, otherwise let us know.
			if(this.effect != 'fade' && this.effect != 'slide')
				throw "Only Fade and Slide effect is supported";
			
			// return the proper effect with direction based off BOOL display param.
			return (this.effect == 'fade')? ((display)? 'fadeIn'	: 'fadeOut') : ((display)? 'slideDown'	: 'slideUp');
		},
		
		/**
		 * Removes events from the given handles, thus
		 * removing the Accordion effect.
		 */
		destroy: function()
		{
			// Remove the set event from all our handles.
			$(this.container + " > " + this.handles).unbind(this.fireEvent);
		}
	});
	
	// Add Accordion to our UI Namesapce
	Lowes.UI.Accordion = Accordion;
	
	// Expose to the world.
	window.Lowes = Lowes;
	
})(jQuery);
/**
 * Lowes Javascript Library.
 * 
 * This is licensed only for use in providing the Lowes.com service, 
 * or any part thereof, and is subject to the Lowes.com Terms and Conditions. 
 * You may not port this file to another platform without Lowes.com's written consent. 
 */

/**
 * @Package Lowes.UI.Carousel
 * @member Lowes.UI
 * @Author MHead
 * @version <%=VERSION=%>
 */
;(function($){
	// Grab Lowes namespace object or create a new one.
	var Lowes = window.Lowes || {};

	// Grab Lowes UI namespace object or create a new one.
	Lowes.UI = Lowes.UI || {};
	
	// Quick check to make sure our UI.Core class is there
	// to extend or create a new one.
	Lowes.UI.Core = Lowes.UI.Core || Class.extend({});
	
	/**
	 * Class for creating and managing
	 * the Carousel UI Component.
	 *
	 * @class Lowes.UI.Carousel
	 */
	var Carousel = Lowes.UI.Core.extend({
		init: function(container, options)
		{
			if(!Lowes.DEBUG && $(container).length < 1)
				return;
			// Check to make sure we have a container param.
			if(typeof container !== 'string' || typeof container === 'undefined')
				throw "No container element (selector) provided to create Carousel";
			else
				this.container = container;

			// Check to make sure that if options were passed, they are objects.
			if(typeof options !== 'undefined' && typeof options !== 'object')
				throw "Carousel options param must be an object";
				
			var options				 = options					 || {};
			this.container			 = container				 || '.horizontal_carousel';
			this.prev				 = options.prev				 || '%@ > .prev'.$$(this.container);
			this.next				 = options.next				 || '%@ > .next'.$$(this.container);
			this.carousel			 = options.carousel			 || '.carousel';
			this.visible			 = options.visible			 || 4;
			this.speed				 = options.speed			 || 1000;
			this.scroll				 = options.scroll			 || 1;
			this.controlBar			 = options.controlBar		 || false;
			this.controlBarMode		 = options.controlBarMode	 || 'status'; //only show status, or allow movement
			this.orientation		 = options.orientation		 || 'horizontal';
			this.callback			 = options.callback			 || function() {};
			this.fireEvent			 = options.event			 || 'click';
			this.loop				 = (options.loop !== false) ? true : false;
			this.position			 = 0;
		},
		
		create:function()
		{
			//container will hold carousel and control bar, possibly the prev/next arrows, too
			this.$container = $container = $(this.container);
			
			//get the selector that represents the carousel items (usually a <ul>)
			this.$carousel = $carousel = $('%@ > %@'.$$(this.container, this.carousel));
			
			this.$carouselItems = $carouselItems = $carousel.children();

			//create mask for the viewport
			var maskDiv = document.createElement('div');
			
			//wrap mask around carousel items
			$carousel.wrap(maskDiv);
			
			var $mask = $carousel.parent();
			
			
			//if # of items < # visible, don't show controlbar
			if(this.$carouselItems.length <= this.visible)
			{
				this.controlBar = false;
			}
			
			if(this.controlBar && this.orientation == 'horizontal')
			{
				var numberOfControls = Math.ceil(($carouselItems.length)/this.visible);
								
				var $controlContainer = $(document.createElement('div')).addClass('control_bar');
				
				var upperLimit = $carouselItems.length - this.visible;
				//generates elements and creates map
				for(var i=0; i<numberOfControls; i++)
				{
					var control = document.createElement('a');
					control.setAttribute('href', '#control'+i);
					$controlContainer.append(control);	
					
					
					var low = i * this.visible;
					
					//check to see if the low position is outside the upperLimit
					if(low > upperLimit)
					{
						low = low - (low - upperLimit);
					}
										
					var high = low + this.visible - 1;
					for(var j=low; j<=high; j++)
					{
						var $el = $($carouselItems.get(j));
						if($el.hasClass('control_%@'.$$(i-1)))
						{
							//don't allow multiple control classes
							$el.removeClass('control_%@'.$$(i-1))
						}
						$el.addClass('control_'+i);
					}
				}
				
				this.$controls = $controls = $controlContainer.find('a');
				$controls.filter(':first').addClass('active');
				if(this.controlBarMode != 'status')
				{
					$controls.live('click', this.__bindControlBarEvent.expose(this));
				}
				//else, mode is 'status', show just use controlbar to show status
				
				$container.append($controlContainer);
			}

			if(this.loop){
				var $prepend = $carouselItems.slice($carouselItems.length-this.visible).clone();
				var $append = $carouselItems.slice(0, this.visible).clone();
				$carousel.prepend($prepend).append($append);		
				
				//make sure the selectorChildren variable reflects recent changes
				this.$carouselItems = $carouselItems = $carousel.children();
				
				//position must compensate for prepended elements
				this.position += $prepend.length;
			}			

			this.upperLimit = $carouselItems.length - this.visible;
			
			//setup the appropriate orientation and add width or height values to the Carousel object
			if(this.orientation == 'horizontal')
			{
				//horizontal
				this.childOuterWidth = $carouselItems.filter(':first').outerWidth(true);
				this.childWidth = $carouselItems.filter(':first').width();
				
				this.totalWidth = ($carouselItems.length * this.childOuterWidth);
				this.visibleWidth = (this.childOuterWidth * this.visible);

				//set carousel CSS rules first, order matters here
				$carousel.css({ 'position': 'absolute', 'left': -(this.position * this.childOuterWidth), 'width': this.totalWidth });
				
				$mask.css({ 'position': 'relative', 'width': this.visibleWidth, 'height': $carousel.height(), 'overflow': 'hidden', 'float': 'left', 'display': 'inline' });
				

			}
			else
			{
				//vertical
				this.childOuterHeight = $carouselItems.filter(':first').outerHeight(true);
				this.childHeight = $carouselItems.filter(':first').height();
				
				this.totalHeight = ($carouselItems.length * this.childOuterHeight);
				this.visibleHeight = (this.childOuterHeight * this.visible);

				//set carousel CSS rules first, order matters here
				$carousel.css({ 'position': 'absolute', 'top': -(this.position * this.childOuterHeight), 'height': this.totalHeight });
				
				$mask.css({ 'position': 'relative', 'height': this.visibleHeight, 'overflow': 'hidden' });
			}
			
			var $prevButton = this.$prevButton = $(this.prev);
			$prevButton.bind(this.fireEvent, this.__bindDirectionEvent.expose(this));

			var $nextButton = this.$nextButton = $(this.next);
			$nextButton.bind(this.fireEvent, this.__bindDirectionEvent.expose(this));	
			
			this.updateArrows();
		},
		
		__bindDirectionEvent: function(event)
		{
			event.preventDefault();
			//prevent animation build up the lazy man's way
			if(this.$carousel.is(':animated'))
				return; 
			
			//determine the direction it should scroll based on class of button that fired event
			var newPosition = ($(event.currentTarget).hasClass('prev')) ? this.position - this.scroll : this.position + this.scroll;	
						
			//if not looping and the next position to scroll to would put the carousel out of visible range, return
			if(!this.loop && (newPosition < 0 || newPosition > this.upperLimit))
				return;
			
			//if looping and the carousel would go out of visible range, adjust the position before scrolling
			if(this.loop && (newPosition < 0 || newPosition > this.upperLimit)) 
			{
				var adjustment;
				var divisor = (this.$carouselItems.length - (this.visible * 2));
	
				(this.position < divisor) ? adjustment = this.position + divisor : adjustment = this.position - divisor;
					
				(newPosition >= 0) ? newPosition = (newPosition % divisor) : newPosition = newPosition + divisor;
				
				if(this.orientation == 'horizontal')
					this.$carousel.css('left', -(adjustment * this.childOuterWidth));
				else
					this.$carousel.css('top', -(adjustment * this.childOuterHeight));
			}

			this.spinCarousel(newPosition);
		},
		
		__bindControlBarEvent: function(event)
		{
			event.preventDefault();
			var index = $(event.currentTarget).attr('href').slice(8);
			var newPosition = parseInt(index) * this.visible;
			
			if(this.loop)
			{
				//compensate for prepended/appended items
				newPosition += this.visible;
			}			
			
			//make sure the newPosition wouldn't be outside of the visible limit
			if(newPosition > this.upperLimit)
			{
				newPosition = newPosition - (newPosition - this.upperLimit);
			}
			
			this.spinCarousel(newPosition);
			
		},
		
		__onSlideEndCallback: function(event)
		{
			if(this.controlBar)
			{
				var controlClass = $(this.$carouselItems.get(this.position)).attr('class');
				//use regex to pull out "control_{num}" in case other classes are added to elements in future versions
				var controlNumber = /control_[0-9]+/.exec(controlClass).toString().split('_')[1];
				
				var $currentControl = this.$controls.filter('[href=#control'+controlNumber+']');
				this.$controls.filter('.active').removeClass('active');
				$currentControl.addClass('active');
			}
			
			this.updateArrows();

		},
		
		updateArrows: function()
		{
			//if at the beginning or end and "loop" is false, set arrow to disabled
			if(!this.loop)
			{
				//disable prev arrow
				if(this.position == 0)
				{
					this.$prevButton.addClass('disabled prev_disabled');
				}
				else
				{
					this.$prevButton.removeClass('disabled prev_disabled');
				}
				
				if(this.position == this.upperLimit)
				{
					this.$nextButton.addClass('disabled next_disabled');
				}
				else
				{
					this.$nextButton.removeClass('disabled next_disabled');
				}
			
			}		
		},
		
		spinCarousel: function(newPosition)
		{
			this.position = newPosition;

			if(this.orientation == 'horizontal')
				this.$carousel.animate({ 'left': -(this.childOuterWidth * newPosition) }, this.speed, this.__onSlideEndCallback.expose(this));
			else
				this.$carousel.animate({ 'top': -(this.childOuterHeight * newPosition) }, this.speed, this.__onSlideEndCallback.expose(this));			
		}
	});
	// Add Carousel to our UI Namesapce
	Lowes.UI.Carousel = Carousel;
	
	// Expose to the world.
	window.Lowes = Lowes;
})(jQuery);
/**
 * Lowes Javascript Library.
 * 
 * This is licensed only for use in providing the Lowes.com service, 
 * or any part thereof, and is subject to the Lowes.com Terms and Conditions. 
 * You may not port this file to another platform without Lowes.com's written consent. 
 */

/**
 * @Package Lowes.UI.Modal
 * @member Lowes.UI
 * @Author WCope
 * @version <%=VERSION=%>
 */

;(function($){
	// Grab Lowes namespace object or create a new one.
	var Lowes = window.Lowes || {};

	// Grab Lowes UI namespace object or create a new one.
	Lowes.UI = Lowes.UI || {};
	
	// Quick check to make sure our UI.Core class is there
	// to extend or create a new one.
	Lowes.UI.Core = Lowes.UI.Core || Class.extend({});
	
	/**
	 * Class for creating and managing
	 * the Modal/Dialog UI Component.
	 *
	 * @class Lowes.UI.Accordion
	 */
	var Modal = Lowes.UI.Core.extend({

		/**
		 * Initialize the Modal object and setup options
		 *
		 * @constructor
		 * @param {Object} Options to use when setting up the component.
		 */
		init: function(options)
		{
			// Grab some options, or default to empty.
			var options		= options || {};
			
			// Setup our options, with defaults if needed.
			this.backdrop	= (typeof options.backdrop === 'undefined')? true : options.backdrop;
			this.effect		= options.effect	 || 'fade';
			this.url		= options.url		 || false;
			this.useHeight	= options.height	 || '300px';
			this.useWidth	= options.width		 || '300px';
			this.background = options.background || 'white';
			this.closeText	= options.closeText	 || 'X';
			this.open		= options.open		 || false;
			this.callback	= options.callback	 || function() {};
			this.speed		= options.speed		 || 'fast';
			this.content	= options.load		 || false;
			this.attach		= (typeof options.attach !== "undefined")? options.attach : false;
			this.classes	= options.classes || [];
			this.modalId   = options.id || "lowes-modal-id-element";
			
			// Regardes of classes the user wants, let's
			// push or own class on the end to make sure
			// we can get to it.
			this.classes.push('lowes-ui-modal');
			
			// Build modal Id
			//this.modalId = "lowes-modal-id-element";
			
			
			// Let's make a modal.
			this.__modal();
			
			// If they want a backdrop, GIVE IT TO THEM!
			if(this.backdrop)
				this.__backdrop();
			
			// Open on instatiation?!
			if(this.open)
				this.show();

			// If a content object is provided, let's load it up.
			if(this.content)
				this.load(this.content);
		},
		
		/**
		 * When called, show the modal that has been created.
		 */
		show: function(callback) {
		 var showCallback = callback || function() {};
		 
			// If they want a backdrop
			if(this.backdrop) 
			{
				// let's make the backdrop appear, then throw the modal on top of it.
				$(this.backdropElement)[this.__effectBuilder(true)](this.speed, function(){
					// Show the modal.
					$(this.modalBox)[this.__effectBuilder(true)](this.speed, function(){
						  showCallback();
					});
				}.expose(this));
			}
			else
			{
				// No backdrop, just show the modal.
				$(this.modalBox)[this.__effectBuilder(true)](this.speed);
			}
		},

		/**
		 * Load the desired content into the content area of the current modal
		 *
		 * @param {Object} Sets type and content to use.  Can only have a length of 1.
		 */
		load: function(loadObject)
		{
			// Make sure our object is there and it's only 1 entity.
			/*
			if(typeof loadObject == undefined && Object.size(loadObject) > 1)
				throw "Object provided for load method, must have a count of 1";
			
			alert(typeof loadObject.html);
			
			// Hack? Grab the key and run the correct content process method.
			if(typeof loadObject.ajax != undefined)
				this.__loadAjax(loadObject.ajax);
			else if(typeof loadObject.text != undefined)
				this.__loadText(loadObject.text);
			else if(typeof loadObject.html != undefined)
				this.__loadHtml(loadObject.html);
			else
				throw "No valid load type provided. (choices: ajax, text, html)";
			*/
			// Hack: Quick Win/Fix
			this.__loadHtml(loadObject);
		},

		/**
		 * If attach option is given, build the proper position for our modal.
		 *
		 * @private
		*/
		__attach: function()
		{
			// Grab the element ot attach to and it's attributes.
			var attachTo = $(this.attach.element);
			var position = attachTo.offset();
			var width = attachTo.width();
			var height = attachTo.height();
			
			// Container object for return.
			var usePosition = {};
			
			// Where do you want it? Default to bottom.
			switch(position)
			{
				case Lowes.UI.position.TOP:
					// Set top of our modal to our attachment minus it's height (move us up).
					usePosition.top = position.top - height;
					// Line it up.
					usePosition.left = position.left;
				break;

				default:
				case Lowes.UI.position.BOTTOM:
					// Set our modal's position right below our attachement
					usePosition.top = position.top + height;
					// Line it up
					usePosition.left = position.left;
				break;
			}
			
			// return our position object.
			return usePosition;
		},

		/**
		 * Load the content area with the html passed.
		 *
		 * @private
		 * @param {String} String containing HTML.
		 */
		__loadHtml: function(html)
		{
			// Just set our html, old skewl.
			$(this.contentArea).html(html);
		},
		
		/**
		 * Add provided text to the content area of the modal.
		 *
		 * @private
		 * @param {String} the text to use in the content area.
		 */
		__loadText: function(text)
		{
			// Clear out our Content area.
			this.contentArea.innerHTML = "";
			
			// Create a nice text node and stick it in our content area.
			this.contentArea.appendChild(document.createTextNode(text));
		},
		
		__loadAjax: function(url)
		{
			// Clear out our Content area.
			this.contentArea.innerHTML = "";

			// Because we want our content when our modal shows. We use async
			// to stop everything until we get what we want.
			// Then set our innerHTML to the response (hack?).
			this.contentArea.innerHTML = $.ajax({
						type: 'get',
						url: url,
						async: false
					}).responseText;
		},
		
		/**
		 * Just handles setting up which effect we want to use to show and hide our modal
		 *
		 * @private
		 * @param {Bool} Show it or not?
		 */
		__effectBuilder: function(display)
		{
			// Make sure we are given accepted effects, otherwise let us know.
			if(this.effect != 'fade' && this.effect != 'slide')
				throw "Only Fade and Slide effect is supported";
			
			// return the proper effect with direction based off BOOL display param.
			return (this.effect == 'fade')? ((display)? 'fadeIn'	: 'fadeOut') : ((display)? 'slideDown'	: 'slideUp');
		},
		
		/**
		 * Build our model on the fly or use one if it's there.
		 *
		 * @private
		 */
		__modal: function()
		{
			// Predefine our modal variable.
			var modal = null;
			
			// If we alread have a modal hiding in the dom, use that.
			if( $('.lowes-ui-modal').length > 0 )
			{
				modal = $('.lowes-ui-modal')[0];
			}

			// If not, let's build one
			else
			{
				// Create our modal element and set it's id and classes.
				modal = document.createElement('div');
				modal.setAttribute('id', this.modalId);
				modal.setAttribute('class', this.classes.join(" "));
				
				// Style our modal to insure positioning and visibility.
				$(modal).css({
					zIndex:999,
					position:'absolute',
					background:this.background,
					width:this.useWidth,
					height:this.useHeight,
					display: 'none'
				})
				
				var left;
				var top;
				
				// Are we creating attachment issues?
				if(this.attach != false)
				{
					// Call our private method to give us our position.
					var position = this.__attach();
					
					// Position our modal.
					$(modal).css({
						top:position.top,
						left:position.left
					});
				}
				// No attachment issues here....
				else
				{
					// grab the int value of the users desired width and height.
					left  = parseInt(this.useWidth.replace(/px$/, ''));
					top	  = parseInt(this.useHeight.replace(/px$/, ''));

					// Divde them up so we can position this thing, center screen.
					left  = "-%@px".$$(parseInt((left / 2)));
					top	  = "-%@px".$$(parseInt((top / 2)));

					// Set our centered position.
					$(modal).css({
						top:'50%',
						left:'50%',
						margin:"%@ 0 0 %@".$$(top, left)
					})
				}
				
				
				// Expose the modal to our current context.
				this.modalBox = modal;
				
				// Build our exit button/link.
				this.__exit();
				
				// Add our Content area.
				this.__contentArea();
				
				// Add the modal to our current DOM.
				document.body.appendChild(this.modalBox);
				
				// Bind our little exit deal with our close method.
				$('.lowes-ui-modal-exit').live('click', this.close.expose(this));
			}
		},

		/**
		 * Closes our Modal (and backdrop). 
		 *
		 * @param {Object} The event object that fired, causing the close, or default to current context's close object.
		 */
		close: function(evt){
			// If there is no event object, just create an empty object.
			var evt = evt || {};

			// Grab our Exit link, either way.	This is our reference point for finding the modal.

			var aTarget = $(this.exitA);
			
			// If we have a backdrop
			if(this.backdrop)
			{
				// Get rid our modal, then fade out our backdrop. If there is a callback, fire it.
				aTarget.parent('div').parent('div')[this.__effectBuilder(false)](this.speed, function(){
					$(this.backdropElement)[this.__effectBuilder(false)](this.speed, this.callback);
				}.expose(this));
			}
			else
			{
			   /*
			   if(aTarget.length > 0)
				   // Get rid of our modal and fire the callback.
				   aTarget.parent('div').parent('div')[this.__effectBuilder(false)](this.speed, this.callback);
				else
				   $('.lowes-ui-modal')[this.__effectBuilder(false)](this.speed, this.callback);
				*/
				
				$("#%@".$$(this.modalId))[this.__effectBuilder(false)](this.speed, this.callback);
			}
			
			
		},
		
		/**
		 * Completely remove the backdrop and modal from the DOM
		 */
		destroy: function()
		{
			document.body.removeChild(this.modalBox);
			document.body.removeChild(this.backdropElement);
		},
		
		/**
		 * Create our content area for our Modal.
		 *
		 * @private
		 */
		__contentArea: function()
		{
			// Create our container element
			var content = document.createElement('div');

			// expose it to our current context.
			this.contentArea = content;
			
			// Add our default class.
			this.contentArea.setAttribute('class', 'lowes-ui-modal-content');
			
			// Append it to our modal.
			this.modalBox.appendChild(this.contentArea);
		},
		
		/**
		 * Create our way out of this place.  Exit element and container.
		 *
		 * @private
		 */
		__exit: function()
		{
		   /*
			// Create our container for the link.
			var exit = document.createElement('div');
			exit.setAttribute('class', 'lowes-ui-modal-exit-container');

			// Create our link
			var a = document.createElement('a');
			
			// Set our classes.
			a.setAttribute("class", "lowes-ui-modal-exit");
			
			// Do this for Chad.
			a.setAttribute("href", "javascript:;");

			//Set the content of our exit with provided copy and/or html.
			a.innerHTML = this.closeText;
			
			// Set our must have styles.
			$(exit).css({
				marginRight:'2px',
				marginTop:'2px',
				textAlign:'right'
			});
			
			// Expose to our context.
			this.exitA = a;
			
			// Add our link to our exit container
			exit.appendChild(a);
			
			// Add our exit container to our modal.
			this.modalBox.appendChild(exit);
			*/
		},
		
		/**
		 * Creates a backdrop/overlay for the modal to be display on top of.
		 *
		 * @private
		 */
		__backdrop: function()
		{
			// Create our element.
			var div = document.createElement('div');
			div.setAttribute('id', 'lowes-modal-id-element-backdrop');
			
			// Setup our must have styles.
			$(div).css({
			   zIndex:998,
				position:'absolute',
				top:0,
				left:0,
				right:0,
				bottom:0,
				height: $(document).height() /*"100%"*/,
				width:"100%",
				background:'black', // Could be an option later
				opacity:0.6, // Could be an option later.
				display:"none"
			});
			
			// Add our backdrop to our current context
			this.backdropElement = div;
			
			// And throw it in the DOM.
			document.body.appendChild(div);
		}
	});
	
	// Add Modal to our UI Namesapce
	Lowes.UI.Modal = Modal;
	
	// Expose to the world.
	window.Lowes = Lowes;
	
})(jQuery);
/**
 * Lowes Javascript Library.
 * 
 * This is licensed only for use in providing the Lowes.com service, 
 * or any part thereof, and is subject to the Lowes.com Terms and Conditions. 
 * You may not port this file to another platform without Lowes.com's written consent. 
 */

/**
 * @Package Lowes.UI.Tabs
 * @member Lowes.UI
 * @Author WCope
 * @version <%=VERSION=%>
 */

;(function($){
	// Grab Lowes namespace object or create a new one.
	var Lowes = window.Lowes || {};

	// Grab Lowes UI namespace object or create a new one.
	Lowes.UI = Lowes.UI || {};
	
	// Quick check to make sure our UI.Core class is there
	// to extend or create a new one.
	Lowes.UI.Core = Lowes.UI.Core || Class.extend({});
	
	/**
	 * Class for creating and managing
	 * the Tabs UI Component.
	 *
	 * @class Lowes.UI.Tabs
	 */
	var Tabs = Lowes.UI.Core.extend({
		
		/**
		 * Initialize the Tabs object and setup options
		 *
		 * @constructor
		 * @param {String} UL List selector for tabs
		 * @param {String} Selector that holds corrasponding content.
		 * @param {Object} Options to use when setting up the component.
		 */
		init: function(tabs, tabContent, options)
		{
			if(!Lowes.DEBUG && $(tabs).length < 1)
				return;
				
			// Run a few checks to make sure our tabs element is a ul and defined.
			if(typeof tabs == 'undefined' || tabs == '' || $(tabs).length < 1)
				throw "Tabs UL must be provided, please make sure argument is correct";
			
			// Run a couple checks to make sure we have content container for our tabs.
			if(typeof tabContent == 'undefined' || tabContent == '')
				throw "Tabs Content container must be provided, please sure argument is correct";

			// Set our object variables for other methods to access.
			this.tabs = tabs;
			this.tabContent = tabContent;
			
			// No options? Set an empty object.
			var options = options || {};
			
			// Check for options other wise use a default.
			this.activeClass = options.activeClass || 'active';
			this.event		 = options.event || 'click';
		},
		
		/**
		 * Method handle creating the event handlers for
		 * component interaction.
		 */
		create:function()
		{
			// Grab our tab html objects that will fire our events.
			var tabs = $("%@ > li > a:first-child".$$(this.tabs));
			
			// Loop through our tabs and setup it's content.
			for(var i=0; i < tabs.length; i++)
			{
				// Current tab and related content.
				var tab = $(tabs[i]);
				
				//clean up href...thanks coremetrics
				var cleanHref = tab.attr('href').split('?')[0];
				tab.attr('href', cleanHref);
				
				var content = $(tab.attr('href'));
				
				// Hide the content for now.
				content.hide();

				// If a tab as the class set to show it as the default active 
				// tab and content, show it's related content.
				if(tab.hasClass(this.activeClass))
				{
					// Let's show the related content.
					content.show();
					// Ensure parent has class "active" because this is the <li>
					tab.parent().addClass(this.activeClass);
				}
				// If there is no default class used on the tab,
				// let's just start at zero.
				else if(i == 0)
				{
					// Set our first tab to active and show it's content.
					tab.addClass('active');
					// Ensure parent has class "active" because this is the <li>
					tab.parent().addClass(this.activeClass);
					content.show();
				}
			}
			
			// Bind up our event to the tab elements.
			tabs.live(this.event, this.__bindEvent.expose(this));
		},
		
		/**
		 * Setup event handlers for tabs to expose related content.
		 *
		 * @private
		 * @param {Object} Object with event details.
		 */
		__bindEvent: function(event)
		{
			// Stop our initial event.
			event.preventDefault();

			// Grab the tab that is clicked
			var tab = $(event.currentTarget);
			
			// Grab our currently clicked tab.
			var activeTab = $("%@ > li > a.active:first".$$(this.tabs));

			// If you clicked an already open tab, just return and do nothing.
			if(activeTab.attr('href') == tab.attr('href'))
				return;
			
			// Go ahead and remove the active class.
			activeTab.removeClass(this.activeClass);
			
			activeTab.parent().removeClass(this.activeClass)
			
			// Hide our activeTab's related content.
			$( "%@ > %@".$$(this.tabContent, activeTab.attr('href')) ).hide();
			
			
			// Since it's our new active tab
			tab.addClass(this.activeClass);

			tab.parent().addClass(this.activeClass);
			
			// Grab current content related to active tab.
			var currentContent = $(tab.attr('href'));
			
			// If we have a data-url attribute, we need to use ajax with
			// value of our data-url, otherwise move on.
			var dataUrl = currentContent.attr('data-url') || false;

			// Do we need to use ajax?
			if(dataUrl)
			{
				// Make our ajax request
				$.ajax({
					url: dataUrl,
					method: currentContent.attr('data-method') || 'get',
					dataType:'html',
					async: false,
					success: function(data)
					{
						// We are successful so set the content to returned html
						currentContent.html(data);
						// and show.
						currentContent.show();
					},
					error: function(err)
					{
						// On error just dump to console.
						console.log("ERROR:");
						console.log("Tab Ajax Call error response:");
						console.log(arguments);
					}
				});
			}
			else
			{
				// Didn't need ajax call so just show our content.
				currentContent.show();
			}
		},
		
		/**
		 * remove tab setup and events from our elements.
		 */
		destroy: function()
		{
			// Kill the event listeners.
			$("%@ > li > a:first-child".$$(this.tabs)).unbind(this.event);
		}

	});
	
	// Add Tabs to our UI Namesapce
	Lowes.UI.Tabs = Tabs;
	
	// Expose to the world.
	window.Lowes = Lowes;
	
})(jQuery);
/**
 * Lowes Javascript Library.
 * 
 * This is licensed only for use in providing the Lowes.com service, 
 * or any part thereof, and is subject to the Lowes.com Terms and Conditions. 
 * You may not port this file to another platform without Lowes.com's written consent. 
 */

/**
 * @Package Lowes.UI.Slideshow
 * @member Lowes.UI
 * @Author MHead
 * @version <%=VERSION=%>
 */

;(function($){
	// Grab Lowes namespace object or create a new one.
	var Lowes = window.Lowes || {};

	// Grab Lowes UI namespace object or create a new one.
	Lowes.UI = Lowes.UI || {};
	
	// Quick check to make sure our UI.Core class is there
	// to extend or create a new one.
	Lowes.UI.Core = Lowes.UI.Core || Class.extend({});
	
	/**
	 * Class for creating and managing
	 * the Slideshow UI Component.
	 *
	 * @class Lowes.UI.Slideshow
	 */
	var Slideshow = Lowes.UI.Core.extend({
		
		/**
		 * Initialize the Slideshow object and setup options
		 *
		 * @constructor
		 * @param {String} UL List selector for slideshow
		 * @param {String} Selector that holds corrasponding content.
		 * @param {Object} Options to use when setting up the component.
		 */
		init: function(container, options)
		{
			if(!Lowes.DEBUG && $(container).length < 1)
				return;
				
			// Run a few checks to make sure our slideshow element is a ul and defined.
			if(typeof container == 'undefined' || container == '' || $(container).length < 1)
				throw "Slideshow container must be provided, please make sure argument is correct";
			
			// Check to make sure that if options were passed, they are objects.
			if(typeof options !== 'undefined' && typeof options !== 'object')
				throw "Carousel options param must be an object";
			
			// No options? Set an empty object.
			var options			   = options || {};
			this.container		   = container				 || '.slideshow';
			this.controls		   = options.controls		 || '.slideshow_controls';
			this.speed			   = options.speed			 || 5000;
			this.paused			   = options.paused			 || (options.paused !== true) ? false : true;
		},
		
		/**
		 * Method handle creating the event handlers for
		 * component interaction.
		 */
		create:function()
		{	
			this.timeoutId = 0;
			
			this.$slideshow = $(this.container);
			
			this.$slides = this.$slideshow.children();
			
			this.currentSlideIndex = 0;
			
			//get all controls except the pause button
			this.$controls = $(this.controls).find('li:not(.pause)');
			
			this.$pauseButton = $(this.controls).find('li.pause');
						
			this.$controls.bind('click', this.__bindEvent.expose(this));
			
			this.$slideshow.bind('mouseenter', function(){ clearTimeout(this.timeoutId); }.expose(this))
							.bind('mouseleave', this.autoSlide.expose(this));
			
			this.$pauseButton.bind('click', this.__bindPauseEvent.expose(this));
			
			//prime the auto sliding
			this.autoSlide();
		},
		
		/**
		 * Setup event handlers for slideshow to expose related content.
		 *
		 * @private
		 * @param {Object} Object with event details.
		 */
		__bindEvent: function(event)
		{
			event.preventDefault();
			
			var newSlideIndex = this.$controls.index(event.currentTarget);

			this.paused = false;

			this.goToSlide(newSlideIndex);
		},

		__bindPauseEvent: function(event)
		{
			event.preventDefault();
			
			//already paused, resume
			if(this.paused)
			{
				this.$pauseButton.removeClass('active');
				
				this.paused = false;
				
				this.autoSlide();
			}
			else
			{
				//pause it
				this.$pauseButton.addClass('active');
				
				this.paused = true;
				
				clearTimeout(this.timeoutId);
			}
		},
		
		goToSlide: function(newSlideIndex)
		{
			clearTimeout(this.timeoutId);
			
			var $currentSlide = $(this.$slides.get(this.currentSlideIndex));
			var $nextSlide = $(this.$slides.get(newSlideIndex));
			
			//check for "paused" status here to catch a race condition
			if(!this.paused && !$nextSlide.is('.active')) //&& !$currentSlide.is(':animated'))
			{
				//ensure next slide is showing behind fading current slide
				$nextSlide.show();
				
				$currentSlide.fadeOut(500,
					function()
					{
						$currentSlide.removeClass('active');
						
						$nextSlide.addClass('active');
						
						this.currentSlideIndex = newSlideIndex;
						
						//slide again
						this.autoSlide();
					}.expose(this)
				);
				
				
				//update controls
				this.$pauseButton.removeClass('active');
				this.$controls.filter('.active').removeClass('active');
				$(this.$controls.get(newSlideIndex)).addClass('active');
			}
		},
		
		getNextSlide: function()
		{
			//get next slideId 
			var $currentControl = this.$controls.filter('.active');
			
			var index = this.$controls.index($currentControl);

			var nextSlideIndex = (index + 1) % this.$controls.length;
			
			return nextSlideIndex;
		},
		
		autoSlide: function()
		{
			if(!this.paused)
			{
				this.timeoutId = setTimeout(
					function()
					{ 
						this.goToSlide(this.getNextSlide());
					}.expose(this), this.speed);
			}
			else
			{
				clearTimeout(this.timeoutId);
			}				
		}

	});
	
	// Add Slideshow to our UI Namesapce
	Lowes.UI.Slideshow = Slideshow;
	
	// Expose to the world.
	window.Lowes = Lowes;
	
})(jQuery);
/**
 * Lowes Javascript Library.
 * 
 * This is licensed only for use in providing the Lowes.com service, 
 * or any part thereof, and is subject to the Lowes.com Terms and Conditions. 
 * You may not port this file to another platform without Lowes.com's written consent. 
 */

/**
 * @Package Lowes.Module
 * @Author Wcope
 * @version 1.0.0
 */

;(function(){
   // Grab Lowes namespace object or create a new one.
   var Lowes = window.Lowes || {};
   
   /**
	* Just a container for specific modules built using 
	* LowesJS library. Items extending Module class will
	* Not be included in the main build of LowesJS.
	*/
   var Module = false;
   
   // Add our class to Lowes namespace
   Lowes.Module = Module;
   
   // Expose Updated Lowes namespace to global.
   window.Lowes = Lowes;
})();


/**
 * Lowes Javascript Library.
 * 
 * This is licensed only for use in providing the Lowes.com service, 
 * or any part thereof, and is subject to the Lowes.com Terms and Conditions. 
 * You may not port this file to another platform without Lowes.com's written consent. 
 */

;(function(){
	
	var Lowes = window.Lowes || {};
	
	var cm_track = true;
	
	var AutoZip = Class.extend({
		
		init: function() { 
			// Bind click event for customer care and store associates
			
		},
		
		run: function( percentage )
		{	
			var	rand = Math.floor( Math.random() * 101 );
			
			// Only run if percentage is defined
			if(typeof percentage != 'undefined')
			{
				var prefs = Lowes.Prefs, declinedZip, autozip;
				prefs.load();
				
				//autozip = (typeof prefs.data.autozip != 'undefined' && prefs.data.autozip.run == false);
								
				declinedZip = (typeof prefs.data.zipin != 'undefined' && prefs.data.zipin.show == false);
				
				// If user is not zipped in already and didn't already decline the modal
				if(!chkCookie('selectedStore1') && !declinedZip/* && !autozip*/)
				{
					// Zip auto user
					if(rand <= percentage)
					{
						// AutoZipping, so modal shouldn't show
						prefs.data.zipin = { "show": false };
		
						var ajaxUrl = '/LowesStoreSearchCmd?ajaxReq=true&storeId=10151&langId=-1';
			
						// Grab the user ZIP and set cookie
						$.ajax({
							url: ajaxUrl,
							dataType: 'text',
							async: true,
							success: function(r)
							{
								/* Remove the \ that excapes the apostrophe in Lowe's, then turn that string into a JSON object */
								var JSON_str = r.replace(/\\/g,"");	
								try {
									var JSON = $.parseJSON(JSON_str);
								
									if ( JSON['selectedStore1'] )
									{
										
										createCookie('selectedStore1', JSON['selectedStore1'], 30);
										
										if ( JSON['zipCode'] )
										{
											$('#storeSearchForm').find('input[name=zipCode]').val(JSON['zipCode']).end().submit();
										}
									}
								}
								catch(e)
								{
									//an international IP will have bad JSON value returned
									//caught a problem trying to parse JSON; just return
									return;
								}
							}
						});
				
						// Setup Coremetrics tracking
						if ( cm_track )
						{
							cmCreatePageElementTag("Auto Zip Test", "TESTING");
						}
					}
					else if(rand > 50 && rand <= 75)
					{
						// Split Standard Zip into two groups: A 
						if ( cm_track )
						{
							cmCreatePageElementTag("Standard Zip Test A", "TESTING");
						}
					}
					else 
					{
						// Split Standard Zip into two groups: B
						if ( cm_track )
						{
							cmCreatePageElementTag("Standard Zip Test B", "TESTING");
						}
					}

					// This simply gives us the ability to console to see what percentage we ended up with
					window.__custPercentage = rand + '%';
				}

				// Save preferences.
				prefs.save();				
			}
		}
	});	

	// Add our class to Lowes namespace
   Lowes.AutoZip = AutoZip;
   
   // Expose Updated Lowes namespace to global.
   window.Lowes = Lowes;		
})(jQuery);

$(function(){
	/*$('#disable-autozip').click(
		function(e)
		{
			e.preventDefault();
			
			var prefs = Lowes.Prefs;
			prefs.load();
			prefs.data.autozip = { "run": false };
			prefs.save();
		}.expose(this);
	);*/
	var autoZip = new Lowes.AutoZip();
	autoZip.run(50);
});


/**
 * @Package Lowes.Module.Zipin
 * @Author Wcope
 * @version 1.0.0
 */

;(function(){
   /**
	* Zipin is the dialog/module/tooltip used to prompt users
	* to enter their zipcode
	*/
   var Zipin = Class.extend({
	  /**
	   * Initial method called when class is instantiated
	   * @constructor
	   *
	   * @param {Object} Content, defines a key of content type and value of content source.
	   * @param {String} Element selector to attach to (optional). If not provided, defaults to modal.
	   */
	  init: function(content, attach) 
	  {			
		 // Grab our prefs
		 this.prefs = Lowes.Prefs;
		 this.prefs.load();
		
		 this.prefs.data.zipin = (typeof this.prefs.data.zipin === 'undefined') ? {
			"show"		: true // Do we show the zip-in element?
		 } : this.prefs.data.zipin; // We don't need defaults, we have some already.
		 // Let's write our prefs just to be safe
		 this.prefs.save();
		 
		 // Call our utility method that returns our page type.
		 this.pageType = new Lowes.Utils().getLowesPageType();
		 
		 // An ugly little html string that we use to inject our zip-in dialog.
		 this.zipDiv =	'<div id="zip-code-avail" class="zip-code-dialog-box">';
		 this.zipDiv += '	<h3 style="font-size:14px">Enter Your ZIP Code to Discover More than 50,000 Available Products at Amazing Prices <a href="javascript:;" class="btn_close" id="close-this-zip">close</a></h3>';
		 this.zipDiv += '	<div class="zip-avail-form">';
		 this.zipDiv += '	   <form action="LowesStoreSearchCmd" method="post" name="zipin" id="zipin">';
		 this.zipDiv += '		 <input type="hidden" value="true" name="masthead"/>';
		 this.zipDiv += '		 <input type="hidden" value="TopCategoriesDisplayView" name="URL"/>';
		 this.zipDiv += '		 <input type="hidden" value="StoreLocatorDisplayView" name="findStoreErrorURL"/>';
		 this.zipDiv += '		 <input type="hidden" value="TopCategoriesDisplayView" name="mastheadURL"/>';
		 this.zipDiv += '		 <input type="hidden" value="10151" name="storeId"/>';
		 this.zipDiv += '		 <input type="hidden" value="10051" name="catalogId"/>';
		 this.zipDiv += '		 <input type="hidden" value="-1" name="langId"/>';
		 this.zipDiv += '		 <input type="hidden" value="" name="firstReferURL"/>';
		 this.zipDiv += '		 <input type="hidden" value="" name="NttParam"/>';
		 this.zipDiv += '		 <input type="hidden" value="" name="isQvSearch"/>';
		 this.zipDiv += '		 <input type="hidden" value="" name="qvRedirect"/>';
		 this.zipDiv += '		 <input type="text" id="zipcode_text_box" name="zipCode" class="text">';
		 this.zipDiv += '		  <input type="image" src="/images/zip_images/btn-zip-submit.gif" class="btn">' ;
		 this.zipDiv += '	   </form>' ;
		 this.zipDiv += '	   <p class="find-zip">' ;
		 this.zipDiv += '		  <a href="/StoreLocatorDisplayView?storeId=10151&amp;catalogId=10051">Don&#146;t Know Your Zip?</a>' ;
		 this.zipDiv += '	   </p>' ;
		 this.zipDiv += '	</div>' ;
		 this.zipDiv += '	<div class="zip-avail-npc">' ;
		 this.zipDiv += '	   <p>Enter your ZIP code today, and Lowe?s will help you find more than 50,000 products in your area. Pricing and selection vary by location, so find your store today, and enjoy your personalized shopping experience.</p>' ;
		 this.zipDiv += '	   <p class="register">' ;
		 this.zipDiv += '		  <a href="/webapp/wcs/stores/servlet/UserRegistrationForm?langId=-1&amp;storeId=10151&amp;catalogId=10051&amp;new=Y" class="learn-more">' ;
		 this.zipDiv += '			 Register with Lowe&#146;s to personalize your shopping experience' ;
		 this.zipDiv += '		  </a>' ;
		 this.zipDiv += '	   </p>';
		 this.zipDiv += '	</div>';
		 this.zipDiv += '	<br style="clear:both;">';
		 this.zipDiv += '</div>';
		 
		 this.modalA  = '  <div id="zip-code-avail-a" class="zip-code-dialog-box">';
		 this.modalA += '	  <a href="javascript:;" class="btn_close" id="close-this-zip">close</a>';
		 this.modalA += '	  <img src="/images/zip_images/modal_woman_1.gif" class="featured_img" />';
		 this.modalA += '	  <div class="zip-avail-npc">';
		 this.modalA += '		 <h3 class="price_availability">Get Pricing &amp; Availability</h3>';
		 this.modalA += '		 <p>We use your ZIP code to give you up-to-the-minute pricing and availability in your area.</p>';
		 this.modalA += '	  </div>';
		 this.modalA += '	  <div class="zip-avail-form">';
		 this.modalA += '		 <form action="LowesStoreSearchCmd" method="post" name="zipin" id="zipin">';
		 this.modalA += '			<input value="true" name="masthead" type="hidden" />';
		 this.modalA += '			<input value="TopCategoriesDisplayView" name="URL" type="hidden" />';
		 this.modalA += '			<input value="StoreLocatorDisplayView" name="findStoreErrorURL" type="hidden" />';
		 this.modalA += '			<input value="TopCategoriesDisplayView" name="mastheadURL" type="hidden" />';
		 this.modalA += '			<input value="10151" name="storeId" type="hidden" />';
		 this.modalA += '			<input value="10051" name="catalogId" type="hidden" />';
		 this.modalA += '			<input value="-1" name="langId" type="hidden" />';
		 this.modalA += '			<input value="" name="firstReferURL" type="hidden" />';
		 this.modalA += '			<input value="" name="NttParam" type="hidden" />';
		 this.modalA += '			<input value="" name="isQvSearch" type="hidden" />';
		 this.modalA += '			<input value="" name="qvRedirect" type="hidden" />';
		 this.modalA += '			<input id="zipcode_text_box" name="zipCode" class="text" type="text" />';
		 this.modalA += '			<input src="/images/zip_images/btn-zip-submit.gif" class="btn" type="image" />';
		 this.modalA += '		 </form>';
		 this.modalA += '	  </div>';
		 this.modalA += '	  <br style="clear: both;">';
		 this.modalA += '  </div>';
	  },
	  
	  /**
	   * Insert the html for our zip-in dialog below our pagination toolbar.
	   *
	   * @private
	   */
	  __showOnListPage: function()
	  {
		 // Take our html "template" and place it right after our pagination toolbar.
		 $(this.templateString).insertAfter('.bottomBar');
		 
		 // Bind our close link to a click event.
		 $('#close-this-zip').live('click', function(evt){
			// We don't want this link to fire
			evt.preventDefault();

			$('.zip-code-dialog-box').slideUp('fast', function(){
			   //cmCreatePageElementTag(window.lowes_zipin_close_tag, "Testing", "close");
			});

		 }.expose(this));
	  },
	  
	  /**
	   * Build a formal modal and display it to the user with content using the template string
	   *
	   * @private
	   */
	  __showDefault: function(modalType)
	  {
		 var classes = [],
			 width,
			 height;
		 
		 switch(this.pickAModal)
		 {
			case 1:
			   //classes = [];
			   width = '738px';
			   height = '155px';
			break;
			
			case 2:
			   //classes = ['a'];
			   width = '620px';
			   height = '230px';
			break;
			
			case 3:
			   //classes = ['b'];
			   width = '620px';
			   height = '230px';
			break;
		 }
		 
		 // Setup our modal object.
		 this.modal	 = new Lowes.UI.Modal({
			border: "" /*"1px solid #024d9e"*/,
			background:"none",
			height: height,
			width: width,
			load: this.templateString,
			/*load: {html: this.zipDiv},*/
			effect: 'slide',
			classes: classes
		 });
		 
		 // Bind our close links to a click event to our close method.
		 $('#close-this-zip').live('click', function(evt){
			evt.preventDefault();
			
			$('#lowes-modal-id-element-backdrop').fadeOut('fast', function(){
			   $('#lowes-modal-id-element').fadeOut('fast', function(){
				  //cmCreatePageElementTag(window.lowes_zipin_close_tag, "Testing", "close");
			   });
			});
			
			
		 });
		 
		 // Show our modal.
		 this.modal.show(function(){
			$('#zipcode_text_box').focus();
		 });
	  },
	  
	  __submitEvent: function(submit_tag)
	  {
		 this.prefs.load();
		 this.prefs.data.zipin.show = false;
		 this.prefs.save();
		 
		 var submit_tag = submit_tag;
		 
		 $('#zipin').live('submit', function(e){
			try
			{
			   //cmCreatePageElementTag(submit_tag, "Testing", "submit");				
			   return true;
			}
			catch(e)
			{
			   alert("Form submit failed");
			   return false;
			}
		 });
	  },
	  
	  /**
	   * Test to see if the modal should be show, if so show it
	   * otherwise do nothing.
	   */
	  show: function()
	  {
		 this.prefs.load();
		 //$('body').prepend('<div style="position:absolute;left:0;top:0;">Data: '+this.prefs.data+' | Zipin: ' + this.prefs.data.zipin + '</div>')
		 /**
		  * A collection of IF checks to handle whether we show the modal or not
		  */
		 if(document.location.href.indexOf('http://www.lowes.com/cd_Giftlist+Builder_198984609_') > -1) return;
		 if(typeof this.prefs.data.zipin.show != 'undefined' && !this.prefs.data.zipin.show) return;
		 if(document.location.href.indexOf('LowesStoreSearchCmd') > -1) return;
		 
		 // Quick test to ensure the user isn't already zipped in
		 if(!chkCookie('selectedStore1'))
		 //if(true)
		 {
			this.pickAModal = 2; //1 + (Math.floor(Math.random()*3));
			//var pickAModal = parseInt(new Lowes.Utils().randomNumber(0,3));
			//if(typeof this.prefs.data.zipin.lottoPicked == 'undefined' || this.prefs.data.zipin.lottoPicked == false)
			if(true) // Lotto removed
			{
				  // Grab our random number for the lotto
				  //var showIt = new Lowes.Utils().randomNumber(1, 10);

				  // If you are picked in our lotto, let's get ready to display our dialog.
				 //if(showIt <= 5)
				 if(true) // For removal of lotto.
				 {
						
					   // Since we won the lotto, set our pref so we know later.
					   //this.prefs.data.zipin.lottoPicked = true;
					   
					   // Write our prefs.
					   //this.prefs.save();

					   // Make sure we are allowed to show the dialog.
					   if(this.prefs.data.zipin.show)
					   //if(true)
					   {

						  this.templateString = this.modalA;
						  this.__submitEvent("Woman_Zip_In_Modal_Submit");
						  window.lowes_zipin_close_tag = "Woman_Zip_In_Modal_Close";

						  // Test for page type so we know which type of dialog to show.
						  switch(this.pageType)
						  {
							 // If we are on a list page, we inject below pagination tool bar.
							  case Lowes.PageTypes.List:
								 this.templateString = this.zipDiv;
								 // Fire our show method for list page type.
								 this.__showOnListPage();
							  break;

							  default:
								 // Show our modal
								 this.__showDefault();
							  break;
						   }
					   }
					   
				  }
				  else
				  {
					 // You weren't picked so remain a loser and all false, better luck next time.
					 this.prefs.data.zipin.lottoPicked = false;

					 // Update our prefs.
					 this.prefs.save();
					 
				  }
			   }
			   
			}
	  },
	  
	  /**
	   * Close method to handle when a user cancels the Zip In modal
	   * instead of actually zipping in.  This will tell our store/class
	   * not to show the modal anymore.
	   *
	   * @param {String} Selector of the element that will fire our close event.
	   */
	  cancelClose: function(modal)
	  {
		 this.prefs.load();
		 // If we didn't show it we don't need to close it.
		 if(this.prefs.data.zipin.show)
		 //if(true)
		 {
			// What type of dialog did we show?
			switch(this.pageType)
			{
			   // For a list page, let's slide up the dialog and get rid of it.
			   case Lowes.PageTypes.List:
					 $('#zip-code-avail').slideUp('fast');
			   break;
			
			   // Otherwise just close the modal.
			   default:
				  $('#lowes-modal-id-element-backdrop').fadeOut('fast', function(){
					 $('#lowes-modal-id-element').fadeOut('fast');
				  });
				  
				  $('#zip-code-avail').slideUp('fast');
				  
					 //modal.close();
			   break;
			}
		 
			// Since you cancel you can't see it again!
			this.prefs.data.zipin.show = false;
			
			// Safe preferences.
			this.prefs.save();
		 }
	  }
	   
   })
   
   $(function(){
	  new Zipin().show();
   });
   
   
   // Add our class to Lowes namespace
   //Lowes.Module.Zipin = Zipin;
   
   // Expose Updated Lowes namespace to global.
   //window.Lowes = Lowes;
})();
