text: /*!
   * mincart
   * The Mini Cart is a great way to improve your PayPal shopping cart integration.
   *
   * @version 3.0.6
   * @author Jeff Harrell <https://github.com/jeffharrell/>
   * @url http://www.mincartjs.com/
   * @license MIT <https://github.com/jeffharrell/mincart/raw/master/LICENSE.md>
   */
  
  ;(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
  
  
  //
  // The shims in this file are not fully implemented shims for the ES5
  // features, but do work for the particular use cases there is in
  // the other modules.
  //
  
  var toString = Object.prototype.toString;
  var hasOwnProperty = Object.prototype.hasOwnProperty;
  
  // Array.isArray is supported in IE9
  function isArray(xs) {
    return toString.call(xs) === '[object Array]';
  }
  exports.isArray = typeof Array.isArray === 'function' ? Array.isArray : isArray;
  
  // Array.prototype.indexOf is supported in IE9
  exports.indexOf = function indexOf(xs, x) {
    if (xs.indexOf) return xs.indexOf(x);
    for (var i = 0; i < xs.length; i++) {
      if (x === xs[i]) return i;
    }
    return -1;
  };
  
  // Array.prototype.filter is supported in IE9
  exports.filter = function filter(xs, fn) {
    if (xs.filter) return xs.filter(fn);
    var res = [];
    for (var i = 0; i < xs.length; i++) {
      if (fn(xs[i], i, xs)) res.push(xs[i]);
    }
    return res;
  };
  
  // Array.prototype.forEach is supported in IE9
  exports.forEach = function forEach(xs, fn, self) {
    if (xs.forEach) return xs.forEach(fn, self);
    for (var i = 0; i < xs.length; i++) {
      fn.call(self, xs[i], i, xs);
    }
  };
  
  // Array.prototype.map is supported in IE9
  exports.map = function map(xs, fn) {
    if (xs.map) return xs.map(fn);
    var out = new Array(xs.length);
    for (var i = 0; i < xs.length; i++) {
      out[i] = fn(xs[i], i, xs);
    }
    return out;
  };
  
  // Array.prototype.reduce is supported in IE9
  exports.reduce = function reduce(array, callback, opt_initialValue) {
    if (array.reduce) return array.reduce(callback, opt_initialValue);
    var value, isValueSet = false;
  
    if (2 < arguments.length) {
      value = opt_initialValue;
      isValueSet = true;
    }
    for (var i = 0, l = array.length; l > i; ++i) {
      if (array.hasOwnProperty(i)) {
        if (isValueSet) {
          value = callback(value, array[i], i, array);
        }
        else {
          value = array[i];
          isValueSet = true;
        }
      }
    }
  
    return value;
  };
  
  // String.prototype.substr - negative index don't work in IE8
  if ('ab'.substr(-1) !== 'b') {
    exports.substr = function (str, start, length) {
      // did we get a negative start, calculate how much it is from the beginning of the string
      if (start < 0) start = str.length + start;
  
      // call the original function
      return str.substr(start, length);
    };
  } else {
    exports.substr = function (str, start, length) {
      return str.substr(start, length);
    };
  }
  
  // String.prototype.trim is supported in IE9
  exports.trim = function (str) {
    if (str.trim) return str.trim();
    return str.replace(/^\s+|\s+$/g, '');
  };
  
  // Function.prototype.bind is supported in IE9
  exports.bind = function () {
    var args = Array.prototype.slice.call(arguments);
    var fn = args.shift();
    if (fn.bind) return fn.bind.apply(fn, args);
    var self = args.shift();
    return function () {
      fn.apply(self, args.concat([Array.prototype.slice.call(arguments)]));
    };
  };
  
  // Object.create is supported in IE9
  function create(prototype, properties) {
    var object;
    if (prototype === null) {
      object = { '__proto__' : null };
    }
    else {
      if (typeof prototype !== 'object') {
        throw new TypeError(
          'typeof prototype[' + (typeof prototype) + '] != \'object\''
        );
      }
      var Type = function () {};
      Type.prototype = prototype;
      object = new Type();
      object.__proto__ = prototype;
    }
    if (typeof properties !== 'undefined' && Object.defineProperties) {
      Object.defineProperties(object, properties);
    }
    return object;
  }
  exports.create = typeof Object.create === 'function' ? Object.create : create;
  
  // Object.keys and Object.getOwnPropertyNames is supported in IE9 however
  // they do show a description and number property on Error objects
  function notObject(object) {
    return ((typeof object != "object" && typeof object != "function") || object === null);
  }
  
  function keysShim(object) {
    if (notObject(object)) {
      throw new TypeError("Object.keys called on a non-object");
    }
  
    var result = [];
    for (var name in object) {
      if (hasOwnProperty.call(object, name)) {
        result.push(name);
      }
    }
    return result;
  }
  
  // getOwnPropertyNames is almost the same as Object.keys one key feature
  //  is that it returns hidden properties, since that can't be implemented,
  //  this feature gets reduced so it just shows the length property on arrays
  function propertyShim(object) {
    if (notObject(object)) {
      throw new TypeError("Object.getOwnPropertyNames called on a non-object");
    }
  
    var result = keysShim(object);
    if (exports.isArray(object) && exports.indexOf(object, 'length') === -1) {
      result.push('length');
    }
    return result;
  }
  
  var keys = typeof Object.keys === 'function' ? Object.keys : keysShim;
  var getOwnPropertyNames = typeof Object.getOwnPropertyNames === 'function' ?
    Object.getOwnPropertyNames : propertyShim;
  
  if (new Error().hasOwnProperty('description')) {
    var ERROR_PROPERTY_FILTER = function (obj, array) {
      if (toString.call(obj) === '[object Error]') {
        array = exports.filter(array, function (name) {
          return name !== 'description' && name !== 'number' && name !== 'message';
        });
      }
      return array;
    };
  
    exports.keys = function (object) {
      return ERROR_PROPERTY_FILTER(object, keys(object));
    };
    exports.getOwnPropertyNames = function (object) {
      return ERROR_PROPERTY_FILTER(object, getOwnPropertyNames(object));
    };
  } else {
    exports.keys = keys;
    exports.getOwnPropertyNames = getOwnPropertyNames;
  }
  
  // Object.getOwnPropertyDescriptor - supported in IE8 but only on dom elements
  function valueObject(value, key) {
    return { value: value[key] };
  }
  
  if (typeof Object.getOwnPropertyDescriptor === 'function') {
    try {
      Object.getOwnPropertyDescriptor({'a': 1}, 'a');
      exports.getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
    } catch (e) {
      // IE8 dom element issue - use a try catch and default to valueObject
      exports.getOwnPropertyDescriptor = function (value, key) {
        try {
          return Object.getOwnPropertyDescriptor(value, key);
        } catch (e) {
          return valueObject(value, key);
        }
      };
    }
  } else {
    exports.getOwnPropertyDescriptor = valueObject;
  }
  
  },{}],2:[function(require,module,exports){
  
  // not implemented
  // The reason for having an empty file and not throwing is to allow
  // untraditional implementation of this module.
  
  },{}],3:[function(require,module,exports){
  var process=require("__browserify_process");// Copyright Joyent, Inc. and other Node contributors.
  //
  // Permission is hereby granted, free of charge, to any person obtaining a
  // copy of this software and associated documentation files (the
  // "Software"), to deal in the Software without restriction, including
  // without limitation the rights to use, copy, modify, merge, publish,
  // distribute, sublicense, and/or sell copies of the Software, and to permit
  // persons to whom the Software is furnished to do so, subject to the
  // following conditions:
  //
  // The above copyright notice and this permission notice shall be included
  // in all copies or substantial portions of the Software.
  //
  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
  // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
  // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
  // USE OR OTHER DEALINGS IN THE SOFTWARE.
  
  var util = require('util');
  var shims = require('_shims');
  
  // resolves . and .. elements in a path array with directory names there
  // must be no slashes, empty elements, or device names (c:\) in the array
  // (so also no leading and trailing slashes - it does not distinguish
  // relative and absolute paths)
  function normalizeArray(parts, allowAboveRoot) {
    // if the path tries to go above the root, `up` ends up > 0
    var up = 0;
    for (var i = parts.length - 1; i >= 0; i--) {
      var last = parts[i];
      if (last === '.') {
        parts.splice(i, 1);
      } else if (last === '..') {
        parts.splice(i, 1);
        up++;
      } else if (up) {
        parts.splice(i, 1);
        up--;
      }
    }
  
    // if the path is allowed to go above the root, restore leading ..s
    if (allowAboveRoot) {
      for (; up--; up) {
        parts.unshift('..');
      }
    }
  
    return parts;
  }
  
  // Split a filename into [root, dir, basename, ext], unix version
  // 'root' is just a slash, or nothing.
  var splitPathRe =
      /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;
  var splitPath = function(filename) {
    return splitPathRe.exec(filename).slice(1);
  };
  
  // path.resolve([from ...], to)
  // posix version
  exports.resolve = function() {
    var resolvedPath = '',
        resolvedAbsolute = false;
  
    for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
      var path = (i >= 0) ? arguments[i] : process.cwd();
  
      // Skip empty and invalid entries
      if (!util.isString(path)) {
        throw new TypeError('Arguments to path.resolve must be strings');
      } else if (!path) {
        continue;
      }
  
      resolvedPath = path + '/' + resolvedPath;
      resolvedAbsolute = path.charAt(0) === '/';
    }
  
    // At this point the path should be resolved to a full absolute path, but
    // handle relative paths to be safe (might happen when process.cwd() fails)
  
    // Normalize the path
    resolvedPath = normalizeArray(shims.filter(resolvedPath.split('/'), function(p) {
      return !!p;
    }), !resolvedAbsolute).join('/');
  
    return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';
  };
  
  // path.normalize(path)
  // posix version
  exports.normalize = function(path) {
    var isAbsolute = exports.isAbsolute(path),
        trailingSlash = shims.substr(path, -1) === '/';
  
    // Normalize the path
    path = normalizeArray(shims.filter(path.split('/'), function(p) {
      return !!p;
    }), !isAbsolute).join('/');
  
    if (!path && !isAbsolute) {
      path = '.';
    }
    if (path && trailingSlash) {
      path += '/';
    }
  
    return (isAbsolute ? '/' : '') + path;
  };
  
  // posix version
  exports.isAbsolute = function(path) {
    return path.charAt(0) === '/';
  };
  
  // posix version
  exports.join = function() {
    var paths = Array.prototype.slice.call(arguments, 0);
    return exports.normalize(shims.filter(paths, function(p, index) {
      if (!util.isString(p)) {
        throw new TypeError('Arguments to path.join must be strings');
      }
      return p;
    }).join('/'));
  };
  
  
  // path.relative(from, to)
  // posix version
  exports.relative = function(from, to) {
    from = exports.resolve(from).substr(1);
    to = exports.resolve(to).substr(1);
  
    function trim(arr) {
      var start = 0;
      for (; start < arr.length; start++) {
        if (arr[start] !== '') break;
      }
  
      var end = arr.length - 1;
      for (; end >= 0; end--) {
        if (arr[end] !== '') break;
      }
  
      if (start > end) return [];
      return arr.slice(start, end - start + 1);
    }
  
    var fromParts = trim(from.split('/'));
    var toParts = trim(to.split('/'));
  
    var length = Math.min(fromParts.length, toParts.length);
    var samePartsLength = length;
    for (var i = 0; i < length; i++) {
      if (fromParts[i] !== toParts[i]) {
        samePartsLength = i;
        break;
      }
    }
  
    var outputParts = [];
    for (var i = samePartsLength; i < fromParts.length; i++) {
      outputParts.push('..');
    }
  
    outputParts = outputParts.concat(toParts.slice(samePartsLength));
  
    return outputParts.join('/');
  };
  
  exports.sep = '/';
  exports.delimiter = ':';
  
  exports.dirname = function(path) {
    var result = splitPath(path),
        root = result[0],
        dir = result[1];
  
    if (!root && !dir) {
      // No dirname whatsoever
      return '.';
    }
  
    if (dir) {
      // It has a dirname, strip trailing slash
      dir = dir.substr(0, dir.length - 1);
    }
  
    return root + dir;
  };
  
  
  exports.basename = function(path, ext) {
    var f = splitPath(path)[2];
    // TODO: make this comparison case-insensitive on windows?
    if (ext && f.substr(-1 * ext.length) === ext) {
      f = f.substr(0, f.length - ext.length);
    }
    return f;
  };
  
  
  exports.extname = function(path) {
    return splitPath(path)[3];
  };
  
  },{"__browserify_process":5,"_shims":1,"util":4}],4:[function(require,module,exports){
  // Copyright Joyent, Inc. and other Node contributors.
  //
  // Permission is hereby granted, free of charge, to any person obtaining a
  // copy of this software and associated documentation files (the
  // "Software"), to deal in the Software without restriction, including
  // without limitation the rights to use, copy, modify, merge, publish,
  // distribute, sublicense, and/or sell copies of the Software, and to permit
  // persons to whom the Software is furnished to do so, subject to the
  // following conditions:
  //
  // The above copyright notice and this permission notice shall be included
  // in all copies or substantial portions of the Software.
  //
  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
  // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
  // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
  // USE OR OTHER DEALINGS IN THE SOFTWARE.
  
  var shims = require('_shims');
  
  var formatRegExp = /%[sdj%]/g;
  exports.format = function(f) {
    if (!isString(f)) {
      var objects = [];
      for (var i = 0; i < arguments.length; i++) {
        objects.push(inspect(arguments[i]));
      }
      return objects.join(' ');
    }
  
    var i = 1;
    var args = arguments;
    var len = args.length;
    var str = String(f).replace(formatRegExp, function(x) {
      if (x === '%%') return '%';
      if (i >= len) return x;
      switch (x) {
        case '%s': return String(args[i++]);
        case '%d': return Number(args[i++]);
        case '%j':
          try {
            return JSON.stringify(args[i++]);
          } catch (_) {
            return '[Circular]';
          }
        default:
          return x;
      }
    });
    for (var x = args[i]; i < len; x = args[++i]) {
      if (isNull(x) || !isObject(x)) {
        str += ' ' + x;
      } else {
        str += ' ' + inspect(x);
      }
    }
    return str;
  };
  
  /**
   * Echos the value of a value. Trys to print the value out
   * in the best way possible given the different types.
   *
   * @param {Object} obj The object to print out.
   * @param {Object} opts Optional options object that alters the output.
   */
  /* legacy: obj, showHidden, depth, colors*/
  function inspect(obj, opts) {
    // default options
    var ctx = {
      seen: [],
      stylize: stylizeNoColor
    };
    // legacy...
    if (arguments.length >= 3) ctx.depth = arguments[2];
    if (arguments.length >= 4) ctx.colors = arguments[3];
    if (isBoolean(opts)) {
      // legacy...
      ctx.showHidden = opts;
    } else if (opts) {
      // got an "options" object
      exports._extend(ctx, opts);
    }
    // set default options
    if (isUndefined(ctx.showHidden)) ctx.showHidden = false;
    if (isUndefined(ctx.depth)) ctx.depth = 2;
    if (isUndefined(ctx.colors)) ctx.colors = false;
    if (isUndefined(ctx.customInspect)) ctx.customInspect = true;
    if (ctx.colors) ctx.stylize = stylizeWithColor;
    return formatValue(ctx, obj, ctx.depth);
  }
  exports.inspect = inspect;
  
  
  // http://en.wikipedia.org/wiki/ANSI_escape_code#graphics
  inspect.colors = {
    'bold' : [1, 22],
    'italic' : [3, 23],
    'underline' : [4, 24],
    'inverse' : [7, 27],
    'white' : [37, 39],
    'grey' : [90, 39],
    'black' : [30, 39],
    'blue' : [34, 39],
    'cyan' : [36, 39],
    'green' : [32, 39],
    'magenta' : [35, 39],
    'red' : [31, 39],
    'yellow' : [33, 39]
  };
  
  // Don't use 'blue' not visible on cmd.exe
  inspect.styles = {
    'special': 'cyan',
    'number': 'yellow',
    'boolean': 'yellow',
    'undefined': 'grey',
    'null': 'bold',
    'string': 'green',
    'date': 'magenta',
    // "name": intentionally not styling
    'regexp': 'red'
  };
  
  
  function stylizeWithColor(str, styleType) {
    var style = inspect.styles[styleType];
  
    if (style) {
      return '\u001b[' + inspect.colors[style][0] + 'm' + str +
             '\u001b[' + inspect.colors[style][1] + 'm';
    } else {
      return str;
    }
  }
  
  
  function stylizeNoColor(str, styleType) {
    return str;
  }
  
  
  function arrayToHash(array) {
    var hash = {};
  
    shims.forEach(array, function(val, idx) {
      hash[val] = true;
    });
  
    return hash;
  }
  
  
  function formatValue(ctx, value, recurseTimes) {
    // Provide a hook for user-specified inspect functions.
    // Check that value is an object with an inspect function on it
    if (ctx.customInspect &&
        value &&
        isFunction(value.inspect) &&
        // Filter out the util module, it's inspect function is special
        value.inspect !== exports.inspect &&
        // Also filter out any prototype objects using the circular check.
        !(value.constructor && value.constructor.prototype === value)) {
      var ret = value.inspect(recurseTimes);
      if (!isString(ret)) {
        ret = formatValue(ctx, ret, recurseTimes);
      }
      return ret;
    }
  
    // Primitive types cannot have properties
    var primitive = formatPrimitive(ctx, value);
    if (primitive) {
      return primitive;
    }
  
    // Look up the keys of the object.
    var keys = shims.keys(value);
    var visibleKeys = arrayToHash(keys);
  
    if (ctx.showHidden) {
      keys = shims.getOwnPropertyNames(value);
    }
  
    // Some type of object without properties can be shortcutted.
    if (keys.length === 0) {
      if (isFunction(value)) {
        var name = value.name ? ': ' + value.name : '';
        return ctx.stylize('[Function' + name + ']', 'special');
      }
      if (isRegExp(value)) {
        return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
      }
      if (isDate(value)) {
        return ctx.stylize(Date.prototype.toString.call(value), 'date');
      }
      if (isError(value)) {
        return formatError(value);
      }
    }
  
    var base = '', array = false, braces = ['{', '}'];
  
    // Make Array say that they are Array
    if (isArray(value)) {
      array = true;
      braces = ['[', ']'];
    }
  
    // Make functions say that they are functions
    if (isFunction(value)) {
      var n = value.name ? ': ' + value.name : '';
      base = ' [Function' + n + ']';
    }
  
    // Make RegExps say that they are RegExps
    if (isRegExp(value)) {
      base = ' ' + RegExp.prototype.toString.call(value);
    }
  
    // Make dates with properties first say the date
    if (isDate(value)) {
      base = ' ' + Date.prototype.toUTCString.call(value);
    }
  
    // Make error with message first say the error
    if (isError(value)) {
      base = ' ' + formatError(value);
    }
  
    if (keys.length === 0 && (!array || value.length == 0)) {
      return braces[0] + base + braces[1];
    }
  
    if (recurseTimes < 0) {
      if (isRegExp(value)) {
        return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
      } else {
        return ctx.stylize('[Object]', 'special');
      }
    }
  
    ctx.seen.push(value);
  
    var output;
    if (array) {
      output = formatArray(ctx, value, recurseTimes, visibleKeys, keys);
    } else {
      output = keys.map(function(key) {
        return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array);
      });
    }
  
    ctx.seen.pop();
  
    return reduceToSingleString(output, base, braces);
  }
  
  
  function formatPrimitive(ctx, value) {
    if (isUndefined(value))
      return ctx.stylize('undefined', 'undefined');
    if (isString(value)) {
      var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '')
                                               .replace(/'/g, "\\'")
                                               .replace(/\\"/g, '"') + '\'';
      return ctx.stylize(simple, 'string');
    }
    if (isNumber(value))
      return ctx.stylize('' + value, 'number');
    if (isBoolean(value))
      return ctx.stylize('' + value, 'boolean');
    // For some reason typeof null is "object", so special case here.
    if (isNull(value))
      return ctx.stylize('null', 'null');
  }
  
  
  function formatError(value) {
    return '[' + Error.prototype.toString.call(value) + ']';
  }
  
  
  function formatArray(ctx, value, recurseTimes, visibleKeys, keys) {
    var output = [];
    for (var i = 0, l = value.length; i < l; ++i) {
      if (hasOwnProperty(value, String(i))) {
        output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
            String(i), true));
      } else {
        output.push('');
      }
    }
  
    shims.forEach(keys, function(key) {
      if (!key.match(/^\d+$/)) {
        output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
            key, true));
      }
    });
    return output;
  }
  
  
  function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) {
    var name, str, desc;
    desc = shims.getOwnPropertyDescriptor(value, key) || { value: value[key] };
    if (desc.get) {
      if (desc.set) {
        str = ctx.stylize('[Getter/Setter]', 'special');
      } else {
        str = ctx.stylize('[Getter]', 'special');
      }
    } else {
      if (desc.set) {
        str = ctx.stylize('[Setter]', 'special');
      }
    }
  
    if (!hasOwnProperty(visibleKeys, key)) {
      name = '[' + key + ']';
    }
    if (!str) {
      if (shims.indexOf(ctx.seen, desc.value) < 0) {
        if (isNull(recurseTimes)) {
          str = formatValue(ctx, desc.value, null);
        } else {
          str = formatValue(ctx, desc.value, recurseTimes - 1);
        }
        if (str.indexOf('\n') > -1) {
          if (array) {
            str = str.split('\n').map(function(line) {
              return '  ' + line;
            }).join('\n').substr(2);
          } else {
            str = '\n' + str.split('\n').map(function(line) {
              return '   ' + line;
            }).join('\n');
          }
        }
      } else {
        str = ctx.stylize('[Circular]', 'special');
      }
    }
    if (isUndefined(name)) {
      if (array && key.match(/^\d+$/)) {
        return str;
      }
      name = JSON.stringify('' + key);
      if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) {
        name = name.substr(1, name.length - 2);
        name = ctx.stylize(name, 'name');
      } else {
        name = name.replace(/'/g, "\\'")
                   .replace(/\\"/g, '"')
                   .replace(/(^"|"$)/g, "'");
        name = ctx.stylize(name, 'string');
      }
    }
  
    return name + ': ' + str;
  }
  
  
  function reduceToSingleString(output, base, braces) {
    var numLinesEst = 0;
    var length = shims.reduce(output, function(prev, cur) {
      numLinesEst++;
      if (cur.indexOf('\n') >= 0) numLinesEst++;
      return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1;
    }, 0);
  
    if (length > 60) {
      return braces[0] +
             (base === '' ? '' : base + '\n ') +
             ' ' +
             output.join(',\n  ') +
             ' ' +
             braces[1];
    }
  
    return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1];
  }
  
  
  // NOTE: These type checking functions intentionally don't use `instanceof`
  // because it is fragile and can be easily faked with `Object.create()`.
  function isArray(ar) {
    return shims.isArray(ar);
  }
  exports.isArray = isArray;
  
  function isBoolean(arg) {
    return typeof arg === 'boolean';
  }
  exports.isBoolean = isBoolean;
  
  function isNull(arg) {
    return arg === null;
  }
  exports.isNull = isNull;
  
  function isNullOrUndefined(arg) {
    return arg == null;
  }
  exports.isNullOrUndefined = isNullOrUndefined;
  
  function isNumber(arg) {
    return typeof arg === 'number';
  }
  exports.isNumber = isNumber;
  
  function isString(arg) {
    return typeof arg === 'string';
  }
  exports.isString = isString;
  
  function isSymbol(arg) {
    return typeof arg === 'symbol';
  }
  exports.isSymbol = isSymbol;
  
  function isUndefined(arg) {
    return arg === void 0;
  }
  exports.isUndefined = isUndefined;
  
  function isRegExp(re) {
    return isObject(re) && objectToString(re) === '[object RegExp]';
  }
  exports.isRegExp = isRegExp;
  
  function isObject(arg) {
    return typeof arg === 'object' && arg;
  }
  exports.isObject = isObject;
  
  function isDate(d) {
    return isObject(d) && objectToString(d) === '[object Date]';
  }
  exports.isDate = isDate;
  
  function isError(e) {
    return isObject(e) && objectToString(e) === '[object Error]';
  }
  exports.isError = isError;
  
  function isFunction(arg) {
    return typeof arg === 'function';
  }
  exports.isFunction = isFunction;
  
  function isPrimitive(arg) {
    return arg === null ||
           typeof arg === 'boolean' ||
           typeof arg === 'number' ||
           typeof arg === 'string' ||
           typeof arg === 'symbol' ||  // ES6 symbol
           typeof arg === 'undefined';
  }
  exports.isPrimitive = isPrimitive;
  
  function isBuffer(arg) {
    return arg && typeof arg === 'object'
      && typeof arg.copy === 'function'
      && typeof arg.fill === 'function'
      && typeof arg.binarySlice === 'function'
    ;
  }
  exports.isBuffer = isBuffer;
  
  function objectToString(o) {
    return Object.prototype.toString.call(o);
  }
  
  
  function pad(n) {
    return n < 10 ? '0' + n.toString(10) : n.toString(10);
  }
  
  
  var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep',
                'Oct', 'Nov', 'Dec'];
  
  // 26 Feb 16:19:34
  function timestamp() {
    var d = new Date();
    var time = [pad(d.getHours()),
                pad(d.getMinutes()),
                pad(d.getSeconds())].join(':');
    return [d.getDate(), months[d.getMonth()], time].join(' ');
  }
  
  
  // log is just a thin wrapper to console.log that prepends a timestamp
  exports.log = function() {
    console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments));
  };
  
  
  /**
   * Inherit the prototype methods from one constructor into another.
   *
   * The Function.prototype.inherits from lang.js rewritten as a standalone
   * function (not on Function.prototype). NOTE: If this file is to be loaded
   * during bootstrapping this function needs to be rewritten using some native
   * functions as prototype setup using normal JavaScript does not work as
   * expected during bootstrapping (see mirror.js in r114903).
   *
   * @param {function} ctor Constructor function which needs to inherit the
   *     prototype.
   * @param {function} superCtor Constructor function to inherit prototype from.
   */
  exports.inherits = function(ctor, superCtor) {
    ctor.super_ = superCtor;
    ctor.prototype = shims.create(superCtor.prototype, {
      constructor: {
        value: ctor,
        enumerable: false,
        writable: true,
        configurable: true
      }
    });
  };
  
  exports._extend = function(origin, add) {
    // Don't do anything if add isn't an object
    if (!add || !isObject(add)) return origin;
  
    var keys = shims.keys(add);
    var i = keys.length;
    while (i--) {
      origin[keys[i]] = add[keys[i]];
    }
    return origin;
  };
  
  function hasOwnProperty(obj, prop) {
    return Object.prototype.hasOwnProperty.call(obj, prop);
  }
  
  },{"_shims":1}],5:[function(require,module,exports){
  // shim for using process in browser
  
  var process = module.exports = {};
  
  process.nextTick = (function () {
      var canSetImmediate = typeof window !== 'undefined'
      && window.setImmediate;
      var canPost = typeof window !== 'undefined'
      && window.postMessage && window.addEventListener
      ;
  
      if (canSetImmediate) {
          return function (f) { return window.setImmediate(f) };
      }
  
      if (canPost) {
          var queue = [];
          window.addEventListener('message', function (ev) {
              var source = ev.source;
              if ((source === window || source === null) && ev.data === 'process-tick') {
                  ev.stopPropagation();
                  if (queue.length > 0) {
                      var fn = queue.shift();
                      fn();
                  }
              }
          }, true);
  
          return function nextTick(fn) {
              queue.push(fn);
              window.postMessage('process-tick', '*');
          };
      }
  
      return function nextTick(fn) {
          setTimeout(fn, 0);
      };
  })();
  
  process.title = 'browser';
  process.browser = true;
  process.env = {};
  process.argv = [];
  
  process.binding = function (name) {
      throw new Error('process.binding is not supported');
  }
  
  // TODO(shtylman)
  process.cwd = function () { return '/' };
  process.chdir = function (dir) {
      throw new Error('process.chdir is not supported');
  };
  
  },{}],6:[function(require,module,exports){
  
  /*!
   * EJS
   * Copyright(c) 2012 TJ Holowaychuk <tj@vision-media.ca>
   * MIT Licensed
   */
  
  /**
   * Module dependencies.
   */
  
  var utils = require('./utils')
    , path = require('path')
    , dirname = path.dirname
    , extname = path.extname
    , join = path.join
    , fs = require('fs')
    , read = fs.readFileSync;
  
  /**
   * Filters.
   *
   * @type Object
   */
  
  var filters = exports.filters = require('./filters');
  
  /**
   * Intermediate js cache.
   *
   * @type Object
   */
  
  var cache = {};
  
  /**
   * Clear intermediate js cache.
   *
   * @api public
   */
  
  exports.clearCache = function(){
    cache = {};
  };
  
  /**
   * Translate filtered code into function calls.
   *
   * @param {String} js
   * @return {String}
   * @api private
   */
  
  function filtered(js) {
    return js.substr(1).split('|').reduce(function(js, filter){
      var parts = filter.split(':')
        , name = parts.shift()
        , args = parts.join(':') || '';
      if (args) args = ', ' + args;
      return 'filters.' + name + '(' + js + args + ')';
    });
  };
  
  /**
   * Re-throw the given `err` in context to the
   * `str` of ejs, `filename`, and `lineno`.
   *
   * @param {Error} err
   * @param {String} str
   * @param {String} filename
   * @param {String} lineno
   * @api private
   */
  
  function rethrow(err, str, filename, lineno){
    var lines = str.split('\n')
      , start = Math.max(lineno - 3, 0)
      , end = Math.min(lines.length, lineno + 3);
  
    // Error context
    var context = lines.slice(start, end).map(function(line, i){
      var curr = i + start + 1;
      return (curr == lineno ? ' >> ' : '    ')
        + curr
        + '| '
        + line;
    }).join('\n');
  
    // Alter exception message
    err.path = filename;
    err.message = (filename || 'ejs') + ':'
      + lineno + '\n'
      + context + '\n\n'
      + err.message;
    
    throw err;
  }
  
  /**
   * Parse the given `str` of ejs, returning the function body.
   *
   * @param {String} str
   * @return {String}
   * @api public
   */
  
  var parse = exports.parse = function(str, options){
    var options = options || {}
      , open = options.open || exports.open || '<%'
      , close = options.close || exports.close || '%>'
      , filename = options.filename
      , compileDebug = options.compileDebug !== false
      , buf = "";
  
    buf += 'var buf = [];';
    if (false !== options._with) buf += '\nwith (locals || {}) { (function(){ ';
    buf += '\n buf.push(\'';
  
    var lineno = 1;
  
    var consumeEOL = false;
    for (var i = 0, len = str.length; i < len; ++i) {
      var stri = str[i];
      if (str.slice(i, open.length + i) == open) {
        i += open.length
    
        var prefix, postfix, line = (compileDebug ? '__stack.lineno=' : '') + lineno;
        switch (str[i]) {
          case '=':
            prefix = "', escape((" + line + ', ';
            postfix = ")), '";
            ++i;
            break;
          case '-':
            prefix = "', (" + line + ', ';
            postfix = "), '";
            ++i;
            break;
          default:
            prefix = "');" + line + ';';
            postfix = "; buf.push('";
        }
  
        var end = str.indexOf(close, i)
          , js = str.substring(i, end)
          , start = i
          , include = null
          , n = 0;
  
        if ('-' == js[js.length-1]){
          js = js.substring(0, js.length - 2);
          consumeEOL = true;
        }
  
        if (0 == js.trim().indexOf('include')) {
          var name = js.trim().slice(7).trim();
          if (!filename) throw new Error('filename option is required for includes');
          var path = resolveInclude(name, filename);
          include = read(path, 'utf8');
          include = exports.parse(include, { filename: path, _with: false, open: open, close: close, compileDebug: compileDebug });
          buf += "' + (function(){" + include + "})() + '";
          js = '';
        }
  
        while (~(n = js.indexOf("\n", n))) n++, lineno++;
        if (js.substr(0, 1) == ':') js = filtered(js);
        if (js) {
          if (js.lastIndexOf('//') > js.lastIndexOf('\n')) js += '\n';
          buf += prefix;
          buf += js;
          buf += postfix;
        }
        i += end - start + close.length - 1;
  
      } else if (stri == "\\") {
        buf += "\\\\";
      } else if (stri == "'") {
        buf += "\\'";
      } else if (stri == "\r") {
        // ignore
      } else if (stri == "\n") {
        if (consumeEOL) {
          consumeEOL = false;
        } else {
          buf += "\\n";
          lineno++;
        }
      } else {
        buf += stri;
      }
    }
  
    if (false !== options._with) buf += "'); })();\n} \nreturn buf.join('');";
    else buf += "');\nreturn buf.join('');";
    return buf;
  };
  
  /**
   * Compile the given `str` of ejs into a `Function`.
   *
   * @param {String} str
   * @param {Object} options
   * @return {Function}
   * @api public
   */
  
  var compile = exports.compile = function(str, options){
    options = options || {};
    var escape = options.escape || utils.escape;
    
    var input = JSON.stringify(str)
      , compileDebug = options.compileDebug !== false
      , client = options.client
      , filename = options.filename
          ? JSON.stringify(options.filename)
          : 'undefined';
    
    if (compileDebug) {
      // Adds the fancy stack trace meta info
      str = [
        'var __stack = { lineno: 1, input: ' + input + ', filename: ' + filename + ' };',
        rethrow.toString(),
        'try {',
        exports.parse(str, options),
        '} catch (err) {',
        '  rethrow(err, __stack.input, __stack.filename, __stack.lineno);',
        '}'
      ].join("\n");
    } else {
      str = exports.parse(str, options);
    }
    
    if (options.debug) console.log(str);
    if (client) str = 'escape = escape || ' + escape.toString() + ';\n' + str;
  
    try {
      var fn = new Function('locals, filters, escape, rethrow', str);
    } catch (err) {
      if ('SyntaxError' == err.name) {
        err.message += options.filename
          ? ' in ' + filename
          : ' while compiling ejs';
      }
      throw err;
    }
  
    if (client) return fn;
  
    return function(locals){
      return fn.call(this, locals, filters, escape, rethrow);
    }
  };
  
  /**
   * Render the given `str` of ejs.
   *
   * Options:
   *
   *   - `locals`          Local variables object
   *   - `cache`           Compiled functions are cached, requires `filename`
   *   - `filename`        Used by `cache` to key caches
   *   - `scope`           Function execution context
   *   - `debug`           Output generated function body
   *   - `open`            Open tag, defaulting to "<%"
   *   - `close`           Closing tag, defaulting to "%>"
   *
   * @param {String} str
   * @param {Object} options
   * @return {String}
   * @api public
   */
  
  exports.render = function(str, options){
    var fn
      , options = options || {};
  
    if (options.cache) {
      if (options.filename) {
        fn = cache[options.filename] || (cache[options.filename] = compile(str, options));
      } else {
        throw new Error('"cache" option requires "filename".');
      }
    } else {
      fn = compile(str, options);
    }
  
    options.__proto__ = options.locals;
    return fn.call(options.scope, options);
  };
  
  /**
   * Render an EJS file at the given `path` and callback `fn(err, str)`.
   *
   * @param {String} path
   * @param {Object|Function} options or callback
   * @param {Function} fn
   * @api public
   */
  
  exports.renderFile = function(path, options, fn){
    var key = path + ':string';
  
    if ('function' == typeof options) {
      fn = options, options = {};
    }
  
    options.filename = path;
  
    var str;
    try {
      str = options.cache
        ? cache[key] || (cache[key] = read(path, 'utf8'))
        : read(path, 'utf8');
    } catch (err) {
      fn(err);
      return;
    }
    fn(null, exports.render(str, options));
  };
  
  /**
   * Resolve include `name` relative to `filename`.
   *
   * @param {String} name
   * @param {String} filename
   * @return {String}
   * @api private
   */
  
  function resolveInclude(name, filename) {
    var path = join(dirname(filename), name);
    var ext = extname(name);
    if (!ext) path += '.ejs';
    return path;
  }
  
  // express support
  
  exports.__express = exports.renderFile;
  
  /**
   * Expose to require().
   */
  
  if (require.extensions) {
    require.extensions['.ejs'] = function (module, filename) {
      filename = filename || module.filename;
      var options = { filename: filename, client: true }
        , template = fs.readFileSync(filename).toString()
        , fn = compile(template, options);
      module._compile('module.exports = ' + fn.toString() + ';', filename);
    };
  } else if (require.registerExtension) {
    require.registerExtension('.ejs', function(src) {
      return compile(src, {});
    });
  }
  
  },{"./filters":7,"./utils":8,"fs":2,"path":3}],7:[function(require,module,exports){
  /*!
   * EJS - Filters
   * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
   * MIT Licensed
   */
  
  /**
   * First element of the target `obj`.
   */
  
  exports.first = function(obj) {
    return obj[0];
  };
  
  /**
   * Last element of the target `obj`.
   */
  
  exports.last = function(obj) {
    return obj[obj.length - 1];
  };
  
  /**
   * Capitalize the first letter of the target `str`.
   */
  
  exports.capitalize = function(str){
    str = String(str);
    return str[0].toUpperCase() + str.substr(1, str.length);
  };
  
  /**
   * Downcase the target `str`.
   */
  
  exports.downcase = function(str){
    return String(str).toLowerCase();
  };
  
  /**
   * Uppercase the target `str`.
   */
  
  exports.upcase = function(str){
    return String(str).toUpperCase();
  };
  
  /**
   * Sort the target `obj`.
   */
  
  exports.sort = function(obj){
    return Object.create(obj).sort();
  };
  
  /**
   * Sort the target `obj` by the given `prop` ascending.
   */
  
  exports.sort_by = function(obj, prop){
    return Object.create(obj).sort(function(a, b){
      a = a[prop], b = b[prop];
      if (a > b) return 1;
      if (a < b) return -1;
      return 0;
    });
  };
  
  /**
   * Size or length of the target `obj`.
   */
  
  exports.size = exports.length = function(obj) {
    return obj.length;
  };
  
  /**
   * Add `a` and `b`.
   */
  
  exports.plus = function(a, b){
    return Number(a) + Number(b);
  };
  
  /**
   * Subtract `b` from `a`.
   */
  
  exports.minus = function(a, b){
    return Number(a) - Number(b);
  };
  
  /**
   * Multiply `a` by `b`.
   */
  
  exports.times = function(a, b){
    return Number(a) * Number(b);
  };
  
  /**
   * Divide `a` by `b`.
   */
  
  exports.divided_by = function(a, b){
    return Number(a) / Number(b);
  };
  
  /**
   * Join `obj` with the given `str`.
   */
  
  exports.join = function(obj, str){
    return obj.join(str || ', ');
  };
  
  /**
   * Truncate `str` to `len`.
   */
  
  exports.truncate = function(str, len, append){
    str = String(str);
    if (str.length > len) {
      str = str.slice(0, len);
      if (append) str += append;
    }
    return str;
  };
  
  /**
   * Truncate `str` to `n` words.
   */
  
  exports.truncate_words = function(str, n){
    var str = String(str)
      , words = str.split(/ +/);
    return words.slice(0, n).join(' ');
  };
  
  /**
   * Replace `pattern` with `substitution` in `str`.
   */
  
  exports.replace = function(str, pattern, substitution){
    return String(str).replace(pattern, substitution || '');
  };
  
  /**
   * Prepend `val` to `obj`.
   */
  
  exports.prepend = function(obj, val){
    return Array.isArray(obj)
      ? [val].concat(obj)
      : val + obj;
  };
  
  /**
   * Append `val` to `obj`.
   */
  
  exports.append = function(obj, val){
    return Array.isArray(obj)
      ? obj.concat(val)
      : obj + val;
  };
  
  /**
   * Map the given `prop`.
   */
  
  exports.map = function(arr, prop){
    return arr.map(function(obj){
      return obj[prop];
    });
  };
  
  /**
   * Reverse the given `obj`.
   */
  
  exports.reverse = function(obj){
    return Array.isArray(obj)
      ? obj.reverse()
      : String(obj).split('').reverse().join('');
  };
  
  /**
   * Get `prop` of the given `obj`.
   */
  
  exports.get = function(obj, prop){
    return obj[prop];
  };
  
  /**
   * Packs the given `obj` into json string
   */
  exports.json = function(obj){
    return JSON.stringify(obj);
  };
  
  },{}],8:[function(require,module,exports){
  
  /*!
   * EJS
   * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
   * MIT Licensed
   */
  
  /**
   * Escape the given string of `html`.
   *
   * @param {String} html
   * @return {String}
   * @api private
   */
  
  exports.escape = function(html){
    return String(html)
      .replace(/&(?!#?[a-zA-Z0-9]+;)/g, '&amp;')
      .replace(/</g, '&lt;')
      .replace(/>/g, '&gt;')
      .replace(/'/g, '&#39;')
      .replace(/"/g, '&quot;');
  };
   
  
  },{}],9:[function(require,module,exports){
  'use strict';
  
  
  var Product = require('./product'),
      Pubsub = require('./util/pubsub'),
      Storage = require('./util/storage'),
      constants = require('./constants'),
      currency = require('./util/currency'),
      mixin = require('./util/mixin');
  
  
  
  /**
   * Renders the Mini Cart to the page's DOM.
   *
   * @constructor
   * @param {string} name Name of the cart (used as a key for storage)
   * @param {duration} number Time in milliseconds that the cart data should persist
   */
  function Cart(name, duration) {
      var data, items, settings, len, i;
  
      this._items = [];
      this._settings = { bn: constants.BN };
  
      Pubsub.call(this);
      Storage.call(this, name, duration);
  
      if ((data = this.load())) {
          items = data.items;
          settings = data.settings;
  
          if (settings) {
              this._settings = settings;
          }
  
          if (items) {
              for (i = 0, len = items.length; i < len; i++) {
                  this.add(items[i]);
              }
          }
      }
  }
  
  
  mixin(Cart.prototype, Pubsub.prototype);
  mixin(Cart.prototype, Storage.prototype);
  
  
  /**
   * Adds an item to the cart. This fires an "add" event.
   *
   * @param {object} data Item data
   * @return {number} Item location in the cart
   */
  Cart.prototype.add = function add(data) {
      var that = this,
          items = this.items(),
          idx = false,
          isExisting = false,
          product, key, len, i;
  
      // Prune cart settings data from the product
      for (key in data) {
          if (constants.SETTINGS.test(key)) {
              this._settings[key] = data[key];
              delete data[key];
          }
      }
  
      // Look to see if the same product has already been added
      for (i = 0, len = items.length; i < len; i++) {
          if (items[i].isEqual(data)) {
              product = items[i];
              product.set('quantity', product.get('quantity') + (parseInt(data.quantity, 10) || 1));
              idx = i;
              isExisting = true;
              break;
          }
      }
  
      // If not, then try to add it
      if (!product) {
          product = new Product(data);
  
          if (product.isValid()) {
              idx = (this._items.push(product) - 1);
  
              product.on('change', function (key, value) {
                  that.save();
                  that.fire('change', idx, key, value);
              });
  
              this.save();
          }
      }
  
      if (product) {
          this.fire('add', idx, product, isExisting);
      }
  
      return idx;
  };
  
  
  /**
   * Returns the carts current items.
   *
   * @param {number} idx (Optional) Returns only that item.
   * @return {array|object}
   */
  Cart.prototype.items = function get(idx) {
      return (typeof idx === 'number') ? this._items[idx] : this._items;
  };
  
  
  /**
   * Returns the carts current settings.
   *
   * @param {string} name (Optional) Returns only that setting.
   * @return {array|string}
   */
  Cart.prototype.settings = function settings(name) {
      return (name) ? this._settings[name] : this._settings;
  };
  
  
  /**
   * Returns the cart discount.
   *
   * @param {object} config (Optional) Currency formatting options.
   * @return {number|string}
   */
  Cart.prototype.discount = function discount(config) {
      var result = parseFloat(this.settings('discount_amount_cart')) || 0;
  
      if (!result) {
          result = (parseFloat(this.settings('discount_rate_cart')) || 0) * this.subtotal() / 100;
      }
  
      config = config || {};
      config.currency = this.settings('currency_code');
  
      return currency(result, config);
  };
  
  
  /**
   * Returns the cart total without discounts.
   *
   * @param {object} config (Optional) Currency formatting options.
   * @return {number|string}
   */
  Cart.prototype.subtotal = function subtotal(config) {
      var products = this.items(),
          result = 0,
          i, len;
  
      for (i = 0, len = products.length; i < len; i++) {
          result += products[i].total();
      }
  
      config = config || {};
      config.currency = this.settings('currency_code');
  
      return currency(result, config);
  };
  
  
  /**
   * Returns the cart total.
   *
   * @param {object} config (Optional) Currency formatting options.
   * @return {number|string}
   */
  Cart.prototype.total = function total(config) {
      var result = 0;
  
      result += this.subtotal();
      result -= this.discount();
  
      config = config || {};
      config.currency = this.settings('currency_code');
  
      return currency(result, config);
  };
  
  
  /**
   * Remove an item from the cart. This fires a "remove" event.
   *
   * @param {number} idx Item index to remove.
   * @return {boolean}
   */
  Cart.prototype.remove = function remove(idx) {
      var item = this._items.splice(idx, 1);
  
      if (this._items.length === 0) {
          this.destroy();
      }
  
      if (item) {
          this.save();
          this.fire('remove', idx, item[0]);
      }
  
      return !!item.length;
  };
  
  
  /**
   * Saves the cart data.
   */
  Cart.prototype.save = function save() {
      var items = this.items(),
          settings = this.settings(),
          data = [],
          i, len;
  
      for (i = 0, len = items.length; i < len; i++) {
          data.push(items[i].get());
      }
  
      Storage.prototype.save.call(this, {
          items: data,
          settings: settings
      });
  };
  
  
  /**
   * Proxies the toys_checkout event
   * The assumption is the view triggers this and consumers subscribe to it
   *
   * @param {object} The initiating event
   */
  Cart.prototype.toys_checkout = function toys_checkout(evt) {
      this.fire('toys_checkout', evt);
  };
  
  
  /**
   * Destroy the cart data. This fires a "destroy" event.
   */
  Cart.prototype.destroy = function destroy() {
      Storage.prototype.destroy.call(this);
  
      this._items = [];
      this._settings = { bn: constants.BN };
  
      this.fire('destroy');
  };
  
  
  
  
  module.exports = Cart;
  
  },{"./constants":11,"./product":13,"./util/currency":15,"./util/mixin":18,"./util/pubsub":19,"./util/storage":20}],10:[function(require,module,exports){
  'use strict';
  
  
  var mixin = require('./util/mixin');
  
  
  var defaults = module.exports = {
  
      name: 'staplesbmincart',
  
      parent: (typeof document !== 'undefined') ? document.body : null,
  
      action: 'Checkout',
  
      target: '',
  
      duration: 30,
  
      template: '<%var items = cart.items();var settings = cart.settings();var hasItems = !!items.length;var priceFormat = { format: true, currency: cart.settings("currency_code") };var totalFormat = { format: true, showCode: true };%><form method="post" class="<% if (!hasItems) { %>sbmincart-empty<% } %>" action="<%= config.action %>" target="<%= config.target %>">    <button type="button" class="sbmincart-closer">&times;</button>    <ul>        <% for (var i= 0, idx = i + 1, len = items.length; i < len; i++, idx++) { %>        <li class="sbmincart-item">            <div class="sbmincart-details-name">                <a class="sbmincart-name" href="<%= items[i].get("href") %>"><%= items[i].get("toys_item") %></a>                <ul class="sbmincart-attributes">                    <% if (items[i].get("item_number")) { %>                    <li>                        <%= items[i].get("item_number") %>                        <input type="hidden" name="item_number_<%= idx %>" value="<%= items[i].get("item_number") %>" />                    </li>                    <% } %>                    <% if (items[i].discount()) { %>                    <li>                        <%= config.strings.discount %> <%= items[i].discount(priceFormat) %>                        <input type="hidden" name="discount_amount_<%= idx %>" value="<%= items[i].discount() %>" />                    </li>                    <% } %>                    <% for (var options = items[i].options(), j = 0, len2 = options.length; j < len2; j++) { %>                        <li>                            <%= options[j].key %>: <%= options[j].value %>                            <input type="hidden" name="on<%= j %>_<%= idx %>" value="<%= options[j].key %>" />                            <input type="hidden" name="os<%= j %>_<%= idx %>" value="<%= options[j].value %>" />                        </li>                    <% } %>                </ul>            </div>            <div class="sbmincart-details-quantity">                <input class="sbmincart-quantity" data-sbmincart-idx="<%= i %>" name="quantity_<%= idx %>" type="text" pattern="[0-9]*" value="<%= items[i].get("quantity") %>" autocomplete="off" />            </div>            <div class="sbmincart-details-remove">                <button type="button" class="sbmincart-remove" data-sbmincart-idx="<%= i %>">&times;</button>            </div>            <div class="sbmincart-details-price">                <span class="sbmincart-price"><%= items[i].total(priceFormat) %></span>            </div>            <input type="hidden" name="toys_item_<%= idx %>" value="<%= items[i].get("toys_item") %>" />            <input type="hidden" name="amount_<%= idx %>" value="<%= items[i].amount() %>" />            <input type="hidden" name="shipping_<%= idx %>" value="<%= items[i].get("shipping") %>" />            <input type="hidden" name="shipping2_<%= idx %>" value="<%= items[i].get("shipping2") %>" />        </li>        <% } %>    </ul>    <div class="sbmincart-footer">        <% if (hasItems) { %>            <div class="sbmincart-subtotal">                <%= config.strings.subtotal %> <%= cart.total(totalFormat) %>            </div>            <button class="sbmincart-submit" type="submit" data-sbmincart-alt="<%= config.strings.buttonAlt %>"><%- config.strings.button %></button>        <% } else { %>            <p class="sbmincart-empty-text"><%= config.strings.empty %></p>        <% } %>    </div>    <input type="hidden" name="cmd" value="_cart" />    <input type="hidden" name="upload" value="1" />    <% for (var key in settings) { %>        <input type="hidden" name="<%= key %>" value="<%= settings[key] %>" />    <% } %></form>',
  
      styles: '',
  
      strings: {
          button: 'Check Out',
          subtotal: 'Subtotal:',
          discount: 'Discount:',
          empty: 'Your shopping cart is empty'
      }
  
  };
  
  
  /**
   * Mixes in the user config with the default config.
   *
   * @param {object} userConfig Configuration overrides
   * @return {object}
   */
  module.exports.load = function load(userConfig) {
      return mixin(defaults, userConfig);
  };
  
  },{"./util/mixin":18}],11:[function(require,module,exports){
  'use strict';
  
  
  module.exports = {
  
      COMMANDS: { _cart: true, _xclick: true, _donations: true },
  
      SETTINGS: /^(?:business|currency_code|lc|paymentaction|no_shipping|cn|no_note|invoice|handling_cart|weight_cart|weight_unit|tax_cart|discount_amount_cart|discount_rate_cart|page_style|image_url|cpp_|cs|cbt|return|cancel_return|notify_url|rm|custom|charset)/,
  
      BN: 'sbmincart_AddToCart_WPS_US',
  
      KEYUP_TIMEOUT: 500,
  
      SHOWING_CLASS: 'sbmincart-showing',
  
      REMOVE_CLASS: 'sbmincart-remove',
  
      CLOSER_CLASS: 'sbmincart-closer',
  
      QUANTITY_CLASS: 'sbmincart-quantity',
  
      ITEM_CLASS: 'sbmincart-item',
  
      ITEM_CHANGED_CLASS: 'sbmincart-item-changed',
  
      SUBMIT_CLASS: 'sbmincart-submit',
  
      DATA_IDX: 'data-sbmincart-idx'
  
  };
  
  },{}],12:[function(require,module,exports){
  'use strict';
  
  
  var Cart = require('./cart'),
      View = require('./view'),
      config = require('./config'),
      sbmincart = {},
      cartModel,
      confModel,
      viewModel;
  
  
  /**
   * Renders the Mini Cart to the page's DOM.
   *
   * @param {object} userConfig Configuration overrides
   */
  sbmincart.render = function (userConfig) {
      confModel = sbmincart.config = config.load(userConfig);
      cartModel = sbmincart.cart = new Cart(confModel.name, confModel.duration);
      viewModel = sbmincart.view = new View({
          config: confModel,
          cart: cartModel
      });
  
      cartModel.on('add', viewModel.addItem, viewModel);
      cartModel.on('change', viewModel.changeItem, viewModel);
      cartModel.on('remove', viewModel.removeItem, viewModel);
      cartModel.on('destroy', viewModel.hide, viewModel);
  };
  
  
  /**
   * Resets the Mini Cart and its view model
   */
  sbmincart.reset = function () {
      cartModel.destroy();
  
      viewModel.hide();
      viewModel.redraw();
  };
  
  
  
  
  // Export to either node or the brower window
  if (typeof window === 'undefined') {
      module.exports = sbmincart;
  } else {
      if (!window.paypal) {
          window.paypal = {};
      }
  
      window.toys = sbmincart;
  }
  
  },{"./cart":9,"./config":10,"./view":22}],13:[function(require,module,exports){
  'use strict';
  
  
  var currency = require('./util/currency'),
      Pubsub = require('./util/pubsub'),
      mixin = require('./util/mixin');
  
  
  var parser = {
      quantity: function (value) {
          value = parseInt(value, 10);
  
          if (isNaN(value) || !value) {
              value = 1;
          }
  
          return value;
      },
      amount: function (value) {
          return parseFloat(value) || 0;
      },
      href: function (value) {
          if (value) {
              return value;
          } else {
              return (typeof window !== 'undefined') ? window.location.href : null;
          }
      }
  };
  
  
  /**
   * Creates a new product.
   *
   * @constructor
   * @param {object} data Item data
   */
  function Product(data) {
      data.quantity = parser.quantity(data.quantity);
      data.amount = parser.amount(data.amount);
      data.href = parser.href(data.href);
  
      this._data = data;
      this._options = null;
      this._discount = null;
      this._amount = null;
      this._total = null;
  
      Pubsub.call(this);
  }
  
  
  mixin(Product.prototype, Pubsub.prototype);
  
  
  /**
   * Gets the product data.
   *
   * @param {string} key (Optional) A key to restrict the returned data to.
   * @return {array|string}
   */
  Product.prototype.get = function get(key) {
      return (key) ? this._data[key] : this._data;
  };
  
  
  /**
   * Sets a value on the product. This is used rather than manually setting the
   * value so that we can fire a "change" event.
   *
   * @param {string} key
   * @param {string} value
   */
  Product.prototype.set = function set(key, value) {
      var setter = parser[key];
  
      this._data[key] = setter ? setter(value) : value;
      this._options = null;
      this._discount = null;
      this._amount = null;
      this._total = null;
  
      this.fire('change', key);
  };
  
  
  /**
   * Parse and return the options for this product.
   *
   * @return {object}
   */
  Product.prototype.options = function options() {
      var result, key, value, amount, i, j;
  
      if (!this._options) {
          result = [];
          i = 0;
  
          while ((key = this.get('on' + i))) {
              value = this.get('os' + i);
              amount = 0;
              j = 0;
  
              while (typeof this.get('option_select' + j) !== 'undefined') {
                  if (this.get('option_select' + j) === value) {
                      amount = parser.amount(this.get('option_amount' + j));
                      break;
                  }
  
                  j++;
              }
  
              result.push({
                  key: key,
                  value: value,
                  amount: amount
              });
  
              i++;
          }
  
          this._options = result;
      }
  
      return this._options;
  };
  
  
  /**
   * Parse and return the discount for this product.
   *
   * @param {object} config (Optional) Currency formatting options.
   * @return {number|string}
   */
  Product.prototype.discount = function discount(config) {
      var flat, rate, num, limit, result, amount;
  
      if (!this._discount) {
          result = 0;
          num = parseInt(this.get('discount_num'), 10) || 0;
          limit = Math.max(num, this.get('quantity') - 1);
  
          if (this.get('discount_amount') !== undefined) {
              flat = parser.amount(this.get('discount_amount'));
              result += flat;
              result += parser.amount(this.get('discount_amount2') || flat) * limit;
          } else if (this.get('discount_rate') !== undefined) {
              rate = parser.amount(this.get('discount_rate'));
              amount = this.amount();
  
              result += rate * amount / 100;
              result += parser.amount(this.get('discount_rate2') || rate) * amount * limit / 100;
          }
  
          this._discount = result;
      }
  
      return currency(this._discount, config);
  };
  
  
  /**
   * Parse and return the total without discounts for this product.
   *
   * @param {object} config (Optional) Currency formatting options.
   * @return {number|string}
   */
  Product.prototype.amount = function amount(config) {
      var result, options, len, i;
  
      if (!this._amount) {
          result = this.get('amount');
          options = this.options();
  
          for (i = 0, len = options.length; i < len; i++) {
              result += options[i].amount;
          }
  
          this._amount = result;
      }
  
      return currency(this._amount, config);
  };
  
  
  /**
   * Parse and return the total for this product.
   *
   * @param {object} config (Optional) Currency formatting options.
   * @return {number|string}
   */
  Product.prototype.total = function total(config) {
      var result;
  
      if (!this._total) {
          result  = this.get('quantity') * this.amount();
          result -= this.discount();
  
          this._total = parser.amount(result);
      }
  
      return currency(this._total, config);
  };
  
  
  /**
   * Determine if this product has the same data as another.
   *
   * @param {object|Product} data Other product.
   * @return {boolean}
   */
  Product.prototype.isEqual = function isEqual(data) {
      var match = false;
  
      if (data instanceof Product) {
          data = data._data;
      }
  
      if (this.get('toys_item') === data.toys_item) {
          if (this.get('item_number') === data.item_number) {
              if (this.get('amount') === parser.amount(data.amount)) {
                  var i = 0;
  
                  match = true;
  
                  while (typeof data['os' + i] !== 'undefined') {
                      if (this.get('os' + i) !== data['os' + i]) {
                          match = false;
                          break;
                      }
  
                      i++;
                  }
              }
          }
      }
  
      return match;
  };
  
  
  /**
   * Determine if this product is valid.
   *
   * @return {boolean}
   */
  Product.prototype.isValid = function isValid() {
      return (this.get('toys_item') && this.amount() > 0);
  };
  
  
  /**
   * Destroys this product. Fires a "destroy" event.
   */
  Product.prototype.destroy = function destroy() {
      this._data = [];
      this.fire('destroy', this);
  };
  
  
  
  
  module.exports = Product;
  
  },{"./util/currency":15,"./util/mixin":18,"./util/pubsub":19}],14:[function(require,module,exports){
  /* jshint quotmark:double */
  
  
  "use strict";
  
  
  
  module.exports.add = function add(el, str) {
      var re;
  
      if (!el) { return false; }
  
      if (el && el.classList && el.classList.add) {
          el.classList.add(str);
      } else {
          re = new RegExp("\\b" + str + "\\b");
  
          if (!re.test(el.className)) {
              el.className += " " + str;
          }
      }
  };
  
  
  module.exports.remove = function remove(el, str) {
      var re;
  
      if (!el) { return false; }
  
      if (el.classList && el.classList.add) {
          el.classList.remove(str);
      } else {
          re = new RegExp("\\b" + str + "\\b");
  
          if (re.test(el.className)) {
              el.className = el.className.replace(re, "");
          }
      }
  };
  
  
  module.exports.inject = function inject(el, str) {
      var style;
  
      if (!el) { return false; }
  
      if (str) {
          style = document.createElement("style");
          style.type = "text/css";
  
          if (style.styleSheet) {
              style.styleSheet.cssText = str;
          } else {
              style.appendChild(document.createTextNode(str));
          }
  
          el.appendChild(style);
      }
  };
  
  },{}],15:[function(require,module,exports){
  'use strict';
  
  
  var currencies = {
      AED: { before: '\u062c' },
      ANG: { before: '\u0192' },
      ARS: { before: '$', code: true },
      AUD: { before: '$', code: true },
      AWG: { before: '\u0192' },
      BBD: { before: '$', code: true },
      BGN: { before: '\u043b\u0432' },
      BMD: { before: '$', code: true },
      BND: { before: '$', code: true },
      BRL: { before: 'R$' },
      BSD: { before: '$', code: true },
      CAD: { before: '$', code: true },
      CHF: { before: '', code: true },
      CLP: { before: '$', code: true },
      CNY: { before: '\u00A5' },
      COP: { before: '$', code: true },
      CRC: { before: '\u20A1' },
      CZK: { before: 'Kc' },
      DKK: { before: 'kr' },
      DOP: { before: '$', code: true },
      EEK: { before: 'kr' },
      EUR: { before: '\u20AC' },
      GBP: { before: '\u00A3' },
      GTQ: { before: 'Q' },
      HKD: { before: '$', code: true },
      HRK: { before: 'kn' },
      HUF: { before: 'Ft' },
      IDR: { before: 'Rp' },
      ILS: { before: '\u20AA' },
      INR: { before: 'Rs.' },
      ISK: { before: 'kr' },
      JMD: { before: 'J$' },
      JPY: { before: '\u00A5' },
      KRW: { before: '\u20A9' },
      KYD: { before: '$', code: true },
      LTL: { before: 'Lt' },
      LVL: { before: 'Ls' },
      MXN: { before: '$', code: true },
      MYR: { before: 'RM' },
      NOK: { before: 'kr' },
      NZD: { before: '$', code: true },
      PEN: { before: 'S/' },
      PHP: { before: 'Php' },
      PLN: { before: 'z' },
      QAR: { before: '\ufdfc' },
      RON: { before: 'lei' },
      RUB: { before: '\u0440\u0443\u0431' },
      SAR: { before: '\ufdfc' },
      SEK: { before: 'kr' },
      SGD: { before: '$', code: true },
      THB: { before: '\u0E3F' },
      TRY: { before: 'TL' },
      TTD: { before: 'TT$' },
      TWD: { before: 'NT$' },
      UAH: { before: '\u20b4' },
      USD: { before: '$', code: true },
      UYU: { before: '$U' },
      VEF: { before: 'Bs' },
      VND: { before: '\u20ab' },
      XCD: { before: '$', code: true },
      ZAR: { before: 'R' }
  };
  
  
  module.exports = function currency(amount, config) {
      var code = config && config.currency || 'USD',
          value = currencies[code],
          before = value.before || '',
          after = value.after || '',
          length = value.length || 2,
          showCode = value.code && config && config.showCode,
          result = amount;
  
      if (config && config.format) {
          result = before + result.toFixed(length) + after;
      }
  
      if (showCode) {
          result += ' ' + code;
      }
  
      return result;
  };
  
  },{}],16:[function(require,module,exports){
  'use strict';
  
  
  module.exports = (function (window, document) {
  
      /**
       * Events are added here for easy reference
       */
      var cache = [];
  
      // NOOP for Node
      if (!document) {
          return {
              add: function () {},
              remove: function () {}
          };
      // Non-IE events
      } else if (document.addEventListener) {
          return {
              /**
               * Add an event to an object and optionally adjust it's scope
               *
               * @param obj {HTMLElement} The object to attach the event to
               * @param type {string} The type of event excluding "on"
               * @param fn {function} The function
               * @param scope {object} Object to adjust the scope to (optional)
               */
              add: function (obj, type, fn, scope) {
                  scope = scope || obj;
  
                  var wrappedFn = function (e) { fn.call(scope, e); };
  
                  obj.addEventListener(type, wrappedFn, false);
                  cache.push([obj, type, fn, wrappedFn]);
              },
  
  
              /**
               * Remove an event from an object
               *
               * @param obj {HTMLElement} The object to remove the event from
               * @param type {string} The type of event excluding "on"
               * @param fn {function} The function
               */
              remove: function (obj, type, fn) {
                  var wrappedFn, item, len = cache.length, i;
  
                  for (i = 0; i < len; i++) {
                      item = cache[i];
  
                      if (item[0] === obj && item[1] === type && item[2] === fn) {
                          wrappedFn = item[3];
  
                          if (wrappedFn) {
                              obj.removeEventListener(type, wrappedFn, false);
                              cache = cache.slice(i);
                              return true;
                          }
                      }
                  }
              }
          };
  
      // IE events
      } else if (document.attachEvent) {
          return {
              /**
               * Add an event to an object and optionally adjust it's scope (IE)
               *
               * @param obj {HTMLElement} The object to attach the event to
               * @param type {string} The type of event excluding "on"
               * @param fn {function} The function
               * @param scope {object} Object to adjust the scope to (optional)
               */
              add: function (obj, type, fn, scope) {
                  scope = scope || obj;
  
                  var wrappedFn = function () {
                      var e = window.event;
                      e.target = e.target || e.srcElement;
  
                      e.preventDefault = function () {
                          e.returnValue = false;
                      };
  
                      fn.call(scope, e);
                  };
  
                  obj.attachEvent('on' + type, wrappedFn);
                  cache.push([obj, type, fn, wrappedFn]);
              },
  
  
              /**
               * Remove an event from an object (IE)
               *
               * @param obj {HTMLElement} The object to remove the event from
               * @param type {string} The type of event excluding "on"
               * @param fn {function} The function
               */
              remove: function (obj, type, fn) {
                  var wrappedFn, item, len = cache.length, i;
  
                  for (i = 0; i < len; i++) {
                      item = cache[i];
  
                      if (item[0] === obj && item[1] === type && item[2] === fn) {
                          wrappedFn = item[3];
  
                          if (wrappedFn) {
                              obj.detachEvent('on' + type, wrappedFn);
                              cache = cache.slice(i);
                              return true;
                          }
                      }
                  }
              }
          };
      }
  
  })(typeof window === 'undefined' ? null : window, typeof document === 'undefined' ? null : document);
  
  },{}],17:[function(require,module,exports){
  'use strict';
  
  
  var forms = module.exports = {
  
      parse: function parse(form) {
          var raw = form.elements,
              data = {},
              pair, value, i, len;
  
          for (i = 0, len = raw.length; i < len; i++) {
              pair = raw[i];
  
              if ((value = forms.getInputValue(pair))) {
                  data[pair.name] = value;
              }
          }
  
          return data;
      },
  
  
      getInputValue: function getInputValue(input) {
          var tag = input.tagName.toLowerCase();
  
          if (tag === 'select') {
              return input.options[input.selectedIndex].value;
          } else if (tag === 'textarea') {
              return input.innerText;
          } else {
              if (input.type === 'radio') {
                  return (input.checked) ? input.value : null;
              } else if (input.type === 'checkbox') {
                  return (input.checked) ? input.value : null;
              } else {
                  return input.value;
              }
          }
      }
  
  };
  },{}],18:[function(require,module,exports){
  'use strict';
  
  
  var mixin = module.exports = function mixin(dest, source) {
      var value;
  
      for (var key in source) {
          value = source[key];
  
          if (value && value.constructor === Object) {
              if (!dest[key]) {
                  dest[key] = value;
              } else {
                  mixin(dest[key] || {}, value);
              }
          } else {
              dest[key] = value;
          }
      }
  
      return dest;
  };
  
  },{}],19:[function(require,module,exports){
  'use strict';
  
  
  function Pubsub() {
      this._eventCache = {};
  }
  
  
  Pubsub.prototype.on = function on(name, fn, scope) {
      var cache = this._eventCache[name];
  
      if (!cache) {
          cache = this._eventCache[name] = [];
      }
  
      cache.push([fn, scope]);
  };
  
  
  Pubsub.prototype.off = function off(name, fn) {
      var cache = this._eventCache[name],
          i, len;
  
      if (cache) {
          for (i = 0, len = cache.length; i < len; i++) {
              if (cache[i] === fn) {
                  cache = cache.splice(i, 1);
              }
          }
      }
  };
  
  
  Pubsub.prototype.fire = function on(name) {
      var cache = this._eventCache[name], i, len, fn, scope;
  
      if (cache) {
          for (i = 0, len = cache.length; i < len; i++) {
              fn = cache[i][0];
              scope = cache[i][1] || this;
  
              if (typeof fn === 'function') {
                  fn.apply(scope, Array.prototype.slice.call(arguments, 1));
              }
          }
      }
  };
  
  
  module.exports = Pubsub;
  
  },{}],20:[function(require,module,exports){
  'use strict';
  
  
  var Storage = module.exports = function Storage(name, duration) {
      this._name = name;
      this._duration = duration || 30;
  };
  
  
  var proto = Storage.prototype;
  
  
  proto.load = function () {
      if (typeof window === 'object' && window.localStorage) {
          var data = window.localStorage.getItem(this._name), today, expires;
  
          if (data) {
              data = JSON.parse(decodeURIComponent(data));
          }
  
          if (data && data.expires) {
              today = new Date();
              expires = new Date(data.expires);
  
              if (today > expires) {
                  this.destroy();
                  return;
              }
          }
  
          return data && data.value;
      }
  };
  
  
  proto.save = function (data) {
      if (typeof window === 'object' && window.localStorage) {
          var expires = new Date(), wrapped;
  
          expires.setTime(expires.getTime() + this._duration * 24 * 60 * 60 * 1000);
  
          wrapped = {
              value: data,
              expires: expires.toGMTString()
          };
  
          window.localStorage.setItem(this._name, encodeURIComponent(JSON.stringify(wrapped)));
      }
  };
  
  
  proto.destroy = function () {
      if (typeof window === 'object' && window.localStorage) {
          window.localStorage.removeItem(this._name);
      }
  };
  
  },{}],21:[function(require,module,exports){
  'use strict';
  
  
  var ejs = require('ejs');
  
  
  module.exports = function template(str, data) {
      return ejs.render(str, data);
  };
  
  
  // Workaround for IE 8's lack of support
  if (!String.prototype.trim) {
      String.prototype.trim = function () {
          return this.replace(/^\s+|\s+$/g, '');
      };
  }
  
  },{"ejs":6}],22:[function(require,module,exports){
  'use strict';
  
  
  var config = require('./config'),
      events = require('./util/events'),
      template = require('./util/template'),
      forms = require('./util/forms'),
      css = require('./util/css'),
      viewevents = require('./viewevents'),
      constants = require('./constants');
  
  
  
  /**
   * Creates a view model.
   *
   * @constructor
   * @param {object} model
   */
  function View(model) {
      var wrapper;
  
      this.el = wrapper = document.createElement('div');
      this.model = model;
      this.isShowing = false;
  
      // HTML
      wrapper.id = config.name;
      config.parent.appendChild(wrapper);
  
      // CSS
      css.inject(document.getElementsByTagName('head')[0], config.styles);
  
      // JavaScript
      events.add(document, ('ontouchstart' in window) ? 'touchstart' : 'click', viewevents.click, this);
      events.add(document, 'keyup', viewevents.keyup, this);
      events.add(document, 'readystatechange', viewevents.readystatechange, this);
      events.add(window, 'pageshow', viewevents.pageshow, this);
  }
  
  
  /**
   * Tells the view to redraw
   */
  View.prototype.redraw = function redraw() {
      events.remove(this.el.querySelector('form'), 'submit', this.model.cart.toys_checkout, this.model.cart);
      this.el.innerHTML = template(config.template, this.model);
      events.add(this.el.querySelector('form'), 'submit', this.model.cart.toys_checkout, this.model.cart);
  };
  
  
  /**
   * Tells the view to show
   */
  View.prototype.show = function show() {
      if (!this.isShowing) {
          css.add(document.body, constants.SHOWING_CLASS);
          this.isShowing = true;
      }
  };
  
  
  /**
   * Tells the view to hide
   */
  View.prototype.hide = function hide() {
      if (this.isShowing) {
          css.remove(document.body, constants.SHOWING_CLASS);
          this.isShowing = false;
      }
  };
  
  
  /**
   * Toggles the visibility of the view
   */
  View.prototype.toggle = function toggle() {
      this[this.isShowing ? 'hide' : 'show']();
  };
  
  
  /**
   * Binds cart submit events to a form.
   *
   * @param {HTMLElement} form
   * @return {boolean}
   */
  View.prototype.bind = function bind(form) {
      var that = this;
  
      // Don't bind forms without a cmd value
      if (!constants.COMMANDS[form.cmd.value]) {
          return false;
      }
  
      // Prevent re-binding forms
      if (form.hassbmincart) {
          return false;
      } else {
          form.hassbmincart = true;
      }
  
      if (form.display) {
          events.add(form, 'submit', function (e) {
              e.preventDefault();
              that.show();
          });
      } else {
          events.add(form, 'submit', function (e) {
              e.preventDefault(e);
              that.model.cart.add(forms.parse(form));
          });
      }
  
      return true;
  };
  
  
  /**
   * Adds an item to the view.
   *
   * @param {number} idx
   * @param {object} data
   */
  View.prototype.addItem = function addItem(idx, data) {
      this.redraw();
      this.show();
  
      var els = this.el.querySelectorAll('.' + constants.ITEM_CLASS);
      css.add(els[idx], constants.ITEM_CHANGED_CLASS);
  };
  
  
  /**
   * Changes an item in the view.
   *
   * @param {number} idx
   * @param {object} data
   */
  View.prototype.changeItem = function changeItem(idx, data) {
      this.redraw();
      this.show();
  
      var els = this.el.querySelectorAll('.' + constants.ITEM_CLASS);
      css.add(els[idx], constants.ITEM_CHANGED_CLASS);
  };
  
  
  /**
   * Removes an item from the view.
   *
   * @param {number} idx
   */
  View.prototype.removeItem = function removeItem(idx) {
      this.redraw();
  };
  
  
  
  
  module.exports = View;
  
  },{"./config":10,"./constants":11,"./util/css":14,"./util/events":16,"./util/forms":17,"./util/template":21,"./viewevents":23}],23:[function(require,module,exports){
  'use strict';
  
  
  var constants = require('./constants'),
      events = require('./util/events'),
      viewevents;
  
  
  module.exports = viewevents = {
  
      click: function (evt) {
          var target = evt.target,
              className = target.className;
  
          if (this.isShowing) {
              // Cart close button
              if (className === constants.CLOSER_CLASS) {
                  this.hide();
              // Product remove button
              } else if (className === constants.REMOVE_CLASS) {
                  this.model.cart.remove(target.getAttribute(constants.DATA_IDX));
              // Product quantity input
              } else if (className === constants.QUANTITY_CLASS) {
                  target[target.setSelectionRange ? 'setSelectionRange' : 'select'](0, 999);
              // Outside the cart
              } else if (!(/input|button|select|option/i.test(target.tagName))) {
                  while (target.nodeType === 1) {
                      if (target === this.el) {
                          return;
                      }
  
                      target = target.parentNode;
                  }
  
                  this.hide();
              }
          }
      },
  
  
      keyup: function (evt) {
          var that = this,
              target = evt.target,
              timer;
  
          if (target.className === constants.QUANTITY_CLASS) {
              timer = setTimeout(function () {
                  var idx = parseInt(target.getAttribute(constants.DATA_IDX), 10),
                      cart = that.model.cart,
                      product = cart.items(idx),
                      quantity = parseInt(target.value, 10);
  
                  if (product) {
                      if (quantity > 0) {
                          product.set('quantity', quantity);
                      } else if (quantity === 0) {
                          cart.remove(idx);
                      }
                  }
              }, constants.KEYUP_TIMEOUT);
          }
      },
  
  
      readystatechange: function () {
          if (/interactive|complete/.test(document.readyState)) {
              var forms, form, i, len;
  
              // Bind to page's forms
              forms = document.getElementsByTagName('form');
  
              for (i = 0, len = forms.length; i < len; i++) {
                  form = forms[i];
  
                  if (form.cmd && constants.COMMANDS[form.cmd.value]) {
                      this.bind(form);
                  }
              }
  
              // Do the initial render when the buttons are ready
              this.redraw();
  
              // Only run this once
              events.remove(document, 'readystatechange', viewevents.readystatechange);
          }
      },
  
  
      pageshow: function (evt) {
          if (evt.persisted) {
              this.redraw();
              this.hide();
          }
      }
  
  };
  
  },{"./constants":11,"./util/events":16}]},{},[9,10,11,12,13,14,15,16,17,18,19,20,21,22,23])
  ;