/* Minification failed. Returning unminified contents.
(71718,47-54): run-time error JS1019: Can't have 'break' outside of loop: break a
(71665,460-467): run-time error JS1019: Can't have 'break' outside of loop: break a
 */
/*! tether 1.4.0 */

(function(root, factory) {
  if (typeof define === 'function' && define.amd) {
    define(factory);
  } else if (typeof exports === 'object') {
    module.exports = factory(require, exports, module);
  } else {
    root.Tether = factory();
  }
}(this, function(require, exports, module) {

'use strict';

var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }

var TetherBase = undefined;
if (typeof TetherBase === 'undefined') {
  TetherBase = { modules: [] };
}

var zeroElement = null;

// Same as native getBoundingClientRect, except it takes into account parent <frame> offsets
// if the element lies within a nested document (<frame> or <iframe>-like).
function getActualBoundingClientRect(node) {
  var boundingRect = node.getBoundingClientRect();

  // The original object returned by getBoundingClientRect is immutable, so we clone it
  // We can't use extend because the properties are not considered part of the object by hasOwnProperty in IE9
  var rect = {};
  for (var k in boundingRect) {
    rect[k] = boundingRect[k];
  }

  if (node.ownerDocument !== document) {
    var _frameElement = node.ownerDocument.defaultView.frameElement;
    if (_frameElement) {
      var frameRect = getActualBoundingClientRect(_frameElement);
      rect.top += frameRect.top;
      rect.bottom += frameRect.top;
      rect.left += frameRect.left;
      rect.right += frameRect.left;
    }
  }

  return rect;
}

function getScrollParents(el) {
  // In firefox if the el is inside an iframe with display: none; window.getComputedStyle() will return null;
  // https://bugzilla.mozilla.org/show_bug.cgi?id=548397
  var computedStyle = getComputedStyle(el) || {};
  var position = computedStyle.position;
  var parents = [];

  if (position === 'fixed') {
    return [el];
  }

  var parent = el;
  while ((parent = parent.parentNode) && parent && parent.nodeType === 1) {
    var style = undefined;
    try {
      style = getComputedStyle(parent);
    } catch (err) {}

    if (typeof style === 'undefined' || style === null) {
      parents.push(parent);
      return parents;
    }

    var _style = style;
    var overflow = _style.overflow;
    var overflowX = _style.overflowX;
    var overflowY = _style.overflowY;

    if (/(auto|scroll)/.test(overflow + overflowY + overflowX)) {
      if (position !== 'absolute' || ['relative', 'absolute', 'fixed'].indexOf(style.position) >= 0) {
        parents.push(parent);
      }
    }
  }

  parents.push(el.ownerDocument.body);

  // If the node is within a frame, account for the parent window scroll
  if (el.ownerDocument !== document) {
    parents.push(el.ownerDocument.defaultView);
  }

  return parents;
}

var uniqueId = (function () {
  var id = 0;
  return function () {
    return ++id;
  };
})();

var zeroPosCache = {};
var getOrigin = function getOrigin() {
  // getBoundingClientRect is unfortunately too accurate.  It introduces a pixel or two of
  // jitter as the user scrolls that messes with our ability to detect if two positions
  // are equivilant or not.  We place an element at the top left of the page that will
  // get the same jitter, so we can cancel the two out.
  var node = zeroElement;
  if (!node || !document.body.contains(node)) {
    node = document.createElement('div');
    node.setAttribute('data-tether-id', uniqueId());
    extend(node.style, {
      top: 0,
      left: 0,
      position: 'absolute'
    });

    document.body.appendChild(node);

    zeroElement = node;
  }

  var id = node.getAttribute('data-tether-id');
  if (typeof zeroPosCache[id] === 'undefined') {
    zeroPosCache[id] = getActualBoundingClientRect(node);

    // Clear the cache when this position call is done
    defer(function () {
      delete zeroPosCache[id];
    });
  }

  return zeroPosCache[id];
};

function removeUtilElements() {
  if (zeroElement) {
    document.body.removeChild(zeroElement);
  }
  zeroElement = null;
};

function getBounds(el) {
  var doc = undefined;
  if (el === document) {
    doc = document;
    el = document.documentElement;
  } else {
    doc = el.ownerDocument;
  }

  var docEl = doc.documentElement;

  var box = getActualBoundingClientRect(el);

  var origin = getOrigin();

  box.top -= origin.top;
  box.left -= origin.left;

  if (typeof box.width === 'undefined') {
    box.width = document.body.scrollWidth - box.left - box.right;
  }
  if (typeof box.height === 'undefined') {
    box.height = document.body.scrollHeight - box.top - box.bottom;
  }

  box.top = box.top - docEl.clientTop;
  box.left = box.left - docEl.clientLeft;
  box.right = doc.body.clientWidth - box.width - box.left;
  box.bottom = doc.body.clientHeight - box.height - box.top;

  return box;
}

function getOffsetParent(el) {
  return el.offsetParent || document.documentElement;
}

var _scrollBarSize = null;
function getScrollBarSize() {
  if (_scrollBarSize) {
    return _scrollBarSize;
  }
  var inner = document.createElement('div');
  inner.style.width = '100%';
  inner.style.height = '200px';

  var outer = document.createElement('div');
  extend(outer.style, {
    position: 'absolute',
    top: 0,
    left: 0,
    pointerEvents: 'none',
    visibility: 'hidden',
    width: '200px',
    height: '150px',
    overflow: 'hidden'
  });

  outer.appendChild(inner);

  document.body.appendChild(outer);

  var widthContained = inner.offsetWidth;
  outer.style.overflow = 'scroll';
  var widthScroll = inner.offsetWidth;

  if (widthContained === widthScroll) {
    widthScroll = outer.clientWidth;
  }

  document.body.removeChild(outer);

  var width = widthContained - widthScroll;

  _scrollBarSize = { width: width, height: width };
  return _scrollBarSize;
}

function extend() {
  var out = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];

  var args = [];

  Array.prototype.push.apply(args, arguments);

  args.slice(1).forEach(function (obj) {
    if (obj) {
      for (var key in obj) {
        if (({}).hasOwnProperty.call(obj, key)) {
          out[key] = obj[key];
        }
      }
    }
  });

  return out;
}

function removeClass(el, name) {
  if (typeof el.classList !== 'undefined') {
    name.split(' ').forEach(function (cls) {
      if (cls.trim()) {
        el.classList.remove(cls);
      }
    });
  } else {
    var regex = new RegExp('(^| )' + name.split(' ').join('|') + '( |$)', 'gi');
    var className = getClassName(el).replace(regex, ' ');
    setClassName(el, className);
  }
}

function addClass(el, name) {
  if (typeof el.classList !== 'undefined') {
    name.split(' ').forEach(function (cls) {
      if (cls.trim()) {
        el.classList.add(cls);
      }
    });
  } else {
    removeClass(el, name);
    var cls = getClassName(el) + (' ' + name);
    setClassName(el, cls);
  }
}

function hasClass(el, name) {
  if (typeof el.classList !== 'undefined') {
    return el.classList.contains(name);
  }
  var className = getClassName(el);
  return new RegExp('(^| )' + name + '( |$)', 'gi').test(className);
}

function getClassName(el) {
  // Can't use just SVGAnimatedString here since nodes within a Frame in IE have
  // completely separately SVGAnimatedString base classes
  if (el.className instanceof el.ownerDocument.defaultView.SVGAnimatedString) {
    return el.className.baseVal;
  }
  return el.className;
}

function setClassName(el, className) {
  el.setAttribute('class', className);
}

function updateClasses(el, add, all) {
  // Of the set of 'all' classes, we need the 'add' classes, and only the
  // 'add' classes to be set.
  all.forEach(function (cls) {
    if (add.indexOf(cls) === -1 && hasClass(el, cls)) {
      removeClass(el, cls);
    }
  });

  add.forEach(function (cls) {
    if (!hasClass(el, cls)) {
      addClass(el, cls);
    }
  });
}

var deferred = [];

var defer = function defer(fn) {
  deferred.push(fn);
};

var flush = function flush() {
  var fn = undefined;
  while (fn = deferred.pop()) {
    fn();
  }
};

var Evented = (function () {
  function Evented() {
    _classCallCheck(this, Evented);
  }

  _createClass(Evented, [{
    key: 'on',
    value: function on(event, handler, ctx) {
      var once = arguments.length <= 3 || arguments[3] === undefined ? false : arguments[3];

      if (typeof this.bindings === 'undefined') {
        this.bindings = {};
      }
      if (typeof this.bindings[event] === 'undefined') {
        this.bindings[event] = [];
      }
      this.bindings[event].push({ handler: handler, ctx: ctx, once: once });
    }
  }, {
    key: 'once',
    value: function once(event, handler, ctx) {
      this.on(event, handler, ctx, true);
    }
  }, {
    key: 'off',
    value: function off(event, handler) {
      if (typeof this.bindings === 'undefined' || typeof this.bindings[event] === 'undefined') {
        return;
      }

      if (typeof handler === 'undefined') {
        delete this.bindings[event];
      } else {
        var i = 0;
        while (i < this.bindings[event].length) {
          if (this.bindings[event][i].handler === handler) {
            this.bindings[event].splice(i, 1);
          } else {
            ++i;
          }
        }
      }
    }
  }, {
    key: 'trigger',
    value: function trigger(event) {
      if (typeof this.bindings !== 'undefined' && this.bindings[event]) {
        var i = 0;

        for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
          args[_key - 1] = arguments[_key];
        }

        while (i < this.bindings[event].length) {
          var _bindings$event$i = this.bindings[event][i];
          var handler = _bindings$event$i.handler;
          var ctx = _bindings$event$i.ctx;
          var once = _bindings$event$i.once;

          var context = ctx;
          if (typeof context === 'undefined') {
            context = this;
          }

          handler.apply(context, args);

          if (once) {
            this.bindings[event].splice(i, 1);
          } else {
            ++i;
          }
        }
      }
    }
  }]);

  return Evented;
})();

TetherBase.Utils = {
  getActualBoundingClientRect: getActualBoundingClientRect,
  getScrollParents: getScrollParents,
  getBounds: getBounds,
  getOffsetParent: getOffsetParent,
  extend: extend,
  addClass: addClass,
  removeClass: removeClass,
  hasClass: hasClass,
  updateClasses: updateClasses,
  defer: defer,
  flush: flush,
  uniqueId: uniqueId,
  Evented: Evented,
  getScrollBarSize: getScrollBarSize,
  removeUtilElements: removeUtilElements
};
/* globals TetherBase, performance */

'use strict';

var _slicedToArray = (function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i['return']) _i['return'](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError('Invalid attempt to destructure non-iterable instance'); } }; })();

var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();

var _get = function get(_x6, _x7, _x8) { var _again = true; _function: while (_again) { var object = _x6, property = _x7, receiver = _x8; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x6 = parent; _x7 = property; _x8 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }

function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }

if (typeof TetherBase === 'undefined') {
  throw new Error('You must include the utils.js file before tether.js');
}

var _TetherBase$Utils = TetherBase.Utils;
var getScrollParents = _TetherBase$Utils.getScrollParents;
var getBounds = _TetherBase$Utils.getBounds;
var getOffsetParent = _TetherBase$Utils.getOffsetParent;
var extend = _TetherBase$Utils.extend;
var addClass = _TetherBase$Utils.addClass;
var removeClass = _TetherBase$Utils.removeClass;
var updateClasses = _TetherBase$Utils.updateClasses;
var defer = _TetherBase$Utils.defer;
var flush = _TetherBase$Utils.flush;
var getScrollBarSize = _TetherBase$Utils.getScrollBarSize;
var removeUtilElements = _TetherBase$Utils.removeUtilElements;

function within(a, b) {
  var diff = arguments.length <= 2 || arguments[2] === undefined ? 1 : arguments[2];

  return a + diff >= b && b >= a - diff;
}

var transformKey = (function () {
  if (typeof document === 'undefined') {
    return '';
  }
  var el = document.createElement('div');

  var transforms = ['transform', 'WebkitTransform', 'OTransform', 'MozTransform', 'msTransform'];
  for (var i = 0; i < transforms.length; ++i) {
    var key = transforms[i];
    if (el.style[key] !== undefined) {
      return key;
    }
  }
})();

var tethers = [];

var position = function position() {
  tethers.forEach(function (tether) {
    tether.position(false);
  });
  flush();
};

function now() {
  if (typeof performance !== 'undefined' && typeof performance.now !== 'undefined') {
    return performance.now();
  }
  return +new Date();
}

(function () {
  var lastCall = null;
  var lastDuration = null;
  var pendingTimeout = null;

  var tick = function tick() {
    if (typeof lastDuration !== 'undefined' && lastDuration > 16) {
      // We voluntarily throttle ourselves if we can't manage 60fps
      lastDuration = Math.min(lastDuration - 16, 250);

      // Just in case this is the last event, remember to position just once more
      pendingTimeout = setTimeout(tick, 250);
      return;
    }

    if (typeof lastCall !== 'undefined' && now() - lastCall < 10) {
      // Some browsers call events a little too frequently, refuse to run more than is reasonable
      return;
    }

    if (pendingTimeout != null) {
      clearTimeout(pendingTimeout);
      pendingTimeout = null;
    }

    lastCall = now();
    position();
    lastDuration = now() - lastCall;
  };

  if (typeof window !== 'undefined' && typeof window.addEventListener !== 'undefined') {
    ['resize', 'scroll', 'touchmove'].forEach(function (event) {
      window.addEventListener(event, tick);
    });
  }
})();

var MIRROR_LR = {
  center: 'center',
  left: 'right',
  right: 'left'
};

var MIRROR_TB = {
  middle: 'middle',
  top: 'bottom',
  bottom: 'top'
};

var OFFSET_MAP = {
  top: 0,
  left: 0,
  middle: '50%',
  center: '50%',
  bottom: '100%',
  right: '100%'
};

var autoToFixedAttachment = function autoToFixedAttachment(attachment, relativeToAttachment) {
  var left = attachment.left;
  var top = attachment.top;

  if (left === 'auto') {
    left = MIRROR_LR[relativeToAttachment.left];
  }

  if (top === 'auto') {
    top = MIRROR_TB[relativeToAttachment.top];
  }

  return { left: left, top: top };
};

var attachmentToOffset = function attachmentToOffset(attachment) {
  var left = attachment.left;
  var top = attachment.top;

  if (typeof OFFSET_MAP[attachment.left] !== 'undefined') {
    left = OFFSET_MAP[attachment.left];
  }

  if (typeof OFFSET_MAP[attachment.top] !== 'undefined') {
    top = OFFSET_MAP[attachment.top];
  }

  return { left: left, top: top };
};

function addOffset() {
  var out = { top: 0, left: 0 };

  for (var _len = arguments.length, offsets = Array(_len), _key = 0; _key < _len; _key++) {
    offsets[_key] = arguments[_key];
  }

  offsets.forEach(function (_ref) {
    var top = _ref.top;
    var left = _ref.left;

    if (typeof top === 'string') {
      top = parseFloat(top, 10);
    }
    if (typeof left === 'string') {
      left = parseFloat(left, 10);
    }

    out.top += top;
    out.left += left;
  });

  return out;
}

function offsetToPx(offset, size) {
  if (typeof offset.left === 'string' && offset.left.indexOf('%') !== -1) {
    offset.left = parseFloat(offset.left, 10) / 100 * size.width;
  }
  if (typeof offset.top === 'string' && offset.top.indexOf('%') !== -1) {
    offset.top = parseFloat(offset.top, 10) / 100 * size.height;
  }

  return offset;
}

var parseOffset = function parseOffset(value) {
  var _value$split = value.split(' ');

  var _value$split2 = _slicedToArray(_value$split, 2);

  var top = _value$split2[0];
  var left = _value$split2[1];

  return { top: top, left: left };
};
var parseAttachment = parseOffset;

var TetherClass = (function (_Evented) {
  _inherits(TetherClass, _Evented);

  function TetherClass(options) {
    var _this = this;

    _classCallCheck(this, TetherClass);

    _get(Object.getPrototypeOf(TetherClass.prototype), 'constructor', this).call(this);
    this.position = this.position.bind(this);

    tethers.push(this);

    this.history = [];

    this.setOptions(options, false);

    TetherBase.modules.forEach(function (module) {
      if (typeof module.initialize !== 'undefined') {
        module.initialize.call(_this);
      }
    });

    this.position();
  }

  _createClass(TetherClass, [{
    key: 'getClass',
    value: function getClass() {
      var key = arguments.length <= 0 || arguments[0] === undefined ? '' : arguments[0];
      var classes = this.options.classes;

      if (typeof classes !== 'undefined' && classes[key]) {
        return this.options.classes[key];
      } else if (this.options.classPrefix) {
        return this.options.classPrefix + '-' + key;
      } else {
        return key;
      }
    }
  }, {
    key: 'setOptions',
    value: function setOptions(options) {
      var _this2 = this;

      var pos = arguments.length <= 1 || arguments[1] === undefined ? true : arguments[1];

      var defaults = {
        offset: '0 0',
        targetOffset: '0 0',
        targetAttachment: 'auto auto',
        classPrefix: 'tether'
      };

      this.options = extend(defaults, options);

      var _options = this.options;
      var element = _options.element;
      var target = _options.target;
      var targetModifier = _options.targetModifier;

      this.element = element;
      this.target = target;
      this.targetModifier = targetModifier;

      if (this.target === 'viewport') {
        this.target = document.body;
        this.targetModifier = 'visible';
      } else if (this.target === 'scroll-handle') {
        this.target = document.body;
        this.targetModifier = 'scroll-handle';
      }

      ['element', 'target'].forEach(function (key) {
        if (typeof _this2[key] === 'undefined') {
          throw new Error('Tether Error: Both element and target must be defined');
        }

        if (typeof _this2[key].jquery !== 'undefined') {
          _this2[key] = _this2[key][0];
        } else if (typeof _this2[key] === 'string') {
          _this2[key] = document.querySelector(_this2[key]);
        }
      });

      addClass(this.element, this.getClass('element'));
      if (!(this.options.addTargetClasses === false)) {
        addClass(this.target, this.getClass('target'));
      }

      if (!this.options.attachment) {
        throw new Error('Tether Error: You must provide an attachment');
      }

      this.targetAttachment = parseAttachment(this.options.targetAttachment);
      this.attachment = parseAttachment(this.options.attachment);
      this.offset = parseOffset(this.options.offset);
      this.targetOffset = parseOffset(this.options.targetOffset);

      if (typeof this.scrollParents !== 'undefined') {
        this.disable();
      }

      if (this.targetModifier === 'scroll-handle') {
        this.scrollParents = [this.target];
      } else {
        this.scrollParents = getScrollParents(this.target);
      }

      if (!(this.options.enabled === false)) {
        this.enable(pos);
      }
    }
  }, {
    key: 'getTargetBounds',
    value: function getTargetBounds() {
      if (typeof this.targetModifier !== 'undefined') {
        if (this.targetModifier === 'visible') {
          if (this.target === document.body) {
            return { top: pageYOffset, left: pageXOffset, height: innerHeight, width: innerWidth };
          } else {
            var bounds = getBounds(this.target);

            var out = {
              height: bounds.height,
              width: bounds.width,
              top: bounds.top,
              left: bounds.left
            };

            out.height = Math.min(out.height, bounds.height - (pageYOffset - bounds.top));
            out.height = Math.min(out.height, bounds.height - (bounds.top + bounds.height - (pageYOffset + innerHeight)));
            out.height = Math.min(innerHeight, out.height);
            out.height -= 2;

            out.width = Math.min(out.width, bounds.width - (pageXOffset - bounds.left));
            out.width = Math.min(out.width, bounds.width - (bounds.left + bounds.width - (pageXOffset + innerWidth)));
            out.width = Math.min(innerWidth, out.width);
            out.width -= 2;

            if (out.top < pageYOffset) {
              out.top = pageYOffset;
            }
            if (out.left < pageXOffset) {
              out.left = pageXOffset;
            }

            return out;
          }
        } else if (this.targetModifier === 'scroll-handle') {
          var bounds = undefined;
          var target = this.target;
          if (target === document.body) {
            target = document.documentElement;

            bounds = {
              left: pageXOffset,
              top: pageYOffset,
              height: innerHeight,
              width: innerWidth
            };
          } else {
            bounds = getBounds(target);
          }

          var style = getComputedStyle(target);

          var hasBottomScroll = target.scrollWidth > target.clientWidth || [style.overflow, style.overflowX].indexOf('scroll') >= 0 || this.target !== document.body;

          var scrollBottom = 0;
          if (hasBottomScroll) {
            scrollBottom = 15;
          }

          var height = bounds.height - parseFloat(style.borderTopWidth) - parseFloat(style.borderBottomWidth) - scrollBottom;

          var out = {
            width: 15,
            height: height * 0.975 * (height / target.scrollHeight),
            left: bounds.left + bounds.width - parseFloat(style.borderLeftWidth) - 15
          };

          var fitAdj = 0;
          if (height < 408 && this.target === document.body) {
            fitAdj = -0.00011 * Math.pow(height, 2) - 0.00727 * height + 22.58;
          }

          if (this.target !== document.body) {
            out.height = Math.max(out.height, 24);
          }

          var scrollPercentage = this.target.scrollTop / (target.scrollHeight - height);
          out.top = scrollPercentage * (height - out.height - fitAdj) + bounds.top + parseFloat(style.borderTopWidth);

          if (this.target === document.body) {
            out.height = Math.max(out.height, 24);
          }

          return out;
        }
      } else {
        return getBounds(this.target);
      }
    }
  }, {
    key: 'clearCache',
    value: function clearCache() {
      this._cache = {};
    }
  }, {
    key: 'cache',
    value: function cache(k, getter) {
      // More than one module will often need the same DOM info, so
      // we keep a cache which is cleared on each position call
      if (typeof this._cache === 'undefined') {
        this._cache = {};
      }

      if (typeof this._cache[k] === 'undefined') {
        this._cache[k] = getter.call(this);
      }

      return this._cache[k];
    }
  }, {
    key: 'enable',
    value: function enable() {
      var _this3 = this;

      var pos = arguments.length <= 0 || arguments[0] === undefined ? true : arguments[0];

      if (!(this.options.addTargetClasses === false)) {
        addClass(this.target, this.getClass('enabled'));
      }
      addClass(this.element, this.getClass('enabled'));
      this.enabled = true;

      this.scrollParents.forEach(function (parent) {
        if (parent !== _this3.target.ownerDocument) {
          parent.addEventListener('scroll', _this3.position);
        }
      });

      if (pos) {
        this.position();
      }
    }
  }, {
    key: 'disable',
    value: function disable() {
      var _this4 = this;

      removeClass(this.target, this.getClass('enabled'));
      removeClass(this.element, this.getClass('enabled'));
      this.enabled = false;

      if (typeof this.scrollParents !== 'undefined') {
        this.scrollParents.forEach(function (parent) {
          parent.removeEventListener('scroll', _this4.position);
        });
      }
    }
  }, {
    key: 'destroy',
    value: function destroy() {
      var _this5 = this;

      this.disable();

      tethers.forEach(function (tether, i) {
        if (tether === _this5) {
          tethers.splice(i, 1);
        }
      });

      // Remove any elements we were using for convenience from the DOM
      if (tethers.length === 0) {
        removeUtilElements();
      }
    }
  }, {
    key: 'updateAttachClasses',
    value: function updateAttachClasses(elementAttach, targetAttach) {
      var _this6 = this;

      elementAttach = elementAttach || this.attachment;
      targetAttach = targetAttach || this.targetAttachment;
      var sides = ['left', 'top', 'bottom', 'right', 'middle', 'center'];

      if (typeof this._addAttachClasses !== 'undefined' && this._addAttachClasses.length) {
        // updateAttachClasses can be called more than once in a position call, so
        // we need to clean up after ourselves such that when the last defer gets
        // ran it doesn't add any extra classes from previous calls.
        this._addAttachClasses.splice(0, this._addAttachClasses.length);
      }

      if (typeof this._addAttachClasses === 'undefined') {
        this._addAttachClasses = [];
      }
      var add = this._addAttachClasses;

      if (elementAttach.top) {
        add.push(this.getClass('element-attached') + '-' + elementAttach.top);
      }
      if (elementAttach.left) {
        add.push(this.getClass('element-attached') + '-' + elementAttach.left);
      }
      if (targetAttach.top) {
        add.push(this.getClass('target-attached') + '-' + targetAttach.top);
      }
      if (targetAttach.left) {
        add.push(this.getClass('target-attached') + '-' + targetAttach.left);
      }

      var all = [];
      sides.forEach(function (side) {
        all.push(_this6.getClass('element-attached') + '-' + side);
        all.push(_this6.getClass('target-attached') + '-' + side);
      });

      defer(function () {
        if (!(typeof _this6._addAttachClasses !== 'undefined')) {
          return;
        }

        updateClasses(_this6.element, _this6._addAttachClasses, all);
        if (!(_this6.options.addTargetClasses === false)) {
          updateClasses(_this6.target, _this6._addAttachClasses, all);
        }

        delete _this6._addAttachClasses;
      });
    }
  }, {
    key: 'position',
    value: function position() {
      var _this7 = this;

      var flushChanges = arguments.length <= 0 || arguments[0] === undefined ? true : arguments[0];

      // flushChanges commits the changes immediately, leave true unless you are positioning multiple
      // tethers (in which case call Tether.Utils.flush yourself when you're done)

      if (!this.enabled) {
        return;
      }

      this.clearCache();

      // Turn 'auto' attachments into the appropriate corner or edge
      var targetAttachment = autoToFixedAttachment(this.targetAttachment, this.attachment);

      this.updateAttachClasses(this.attachment, targetAttachment);

      var elementPos = this.cache('element-bounds', function () {
        return getBounds(_this7.element);
      });

      var width = elementPos.width;
      var height = elementPos.height;

      if (width === 0 && height === 0 && typeof this.lastSize !== 'undefined') {
        var _lastSize = this.lastSize;

        // We cache the height and width to make it possible to position elements that are
        // getting hidden.
        width = _lastSize.width;
        height = _lastSize.height;
      } else {
        this.lastSize = { width: width, height: height };
      }

      var targetPos = this.cache('target-bounds', function () {
        return _this7.getTargetBounds();
      });
      var targetSize = targetPos;

      // Get an actual px offset from the attachment
      var offset = offsetToPx(attachmentToOffset(this.attachment), { width: width, height: height });
      var targetOffset = offsetToPx(attachmentToOffset(targetAttachment), targetSize);

      var manualOffset = offsetToPx(this.offset, { width: width, height: height });
      var manualTargetOffset = offsetToPx(this.targetOffset, targetSize);

      // Add the manually provided offset
      offset = addOffset(offset, manualOffset);
      targetOffset = addOffset(targetOffset, manualTargetOffset);

      // It's now our goal to make (element position + offset) == (target position + target offset)
      var left = targetPos.left + targetOffset.left - offset.left;
      var top = targetPos.top + targetOffset.top - offset.top;

      for (var i = 0; i < TetherBase.modules.length; ++i) {
        var _module2 = TetherBase.modules[i];
        var ret = _module2.position.call(this, {
          left: left,
          top: top,
          targetAttachment: targetAttachment,
          targetPos: targetPos,
          elementPos: elementPos,
          offset: offset,
          targetOffset: targetOffset,
          manualOffset: manualOffset,
          manualTargetOffset: manualTargetOffset,
          scrollbarSize: scrollbarSize,
          attachment: this.attachment
        });

        if (ret === false) {
          return false;
        } else if (typeof ret === 'undefined' || typeof ret !== 'object') {
          continue;
        } else {
          top = ret.top;
          left = ret.left;
        }
      }

      // We describe the position three different ways to give the optimizer
      // a chance to decide the best possible way to position the element
      // with the fewest repaints.
      var next = {
        // It's position relative to the page (absolute positioning when
        // the element is a child of the body)
        page: {
          top: top,
          left: left
        },

        // It's position relative to the viewport (fixed positioning)
        viewport: {
          top: top - pageYOffset,
          bottom: pageYOffset - top - height + innerHeight,
          left: left - pageXOffset,
          right: pageXOffset - left - width + innerWidth
        }
      };

      var doc = this.target.ownerDocument;
      var win = doc.defaultView;

      var scrollbarSize = undefined;
      if (win.innerHeight > doc.documentElement.clientHeight) {
        scrollbarSize = this.cache('scrollbar-size', getScrollBarSize);
        next.viewport.bottom -= scrollbarSize.height;
      }

      if (win.innerWidth > doc.documentElement.clientWidth) {
        scrollbarSize = this.cache('scrollbar-size', getScrollBarSize);
        next.viewport.right -= scrollbarSize.width;
      }

      if (['', 'static'].indexOf(doc.body.style.position) === -1 || ['', 'static'].indexOf(doc.body.parentElement.style.position) === -1) {
        // Absolute positioning in the body will be relative to the page, not the 'initial containing block'
        next.page.bottom = doc.body.scrollHeight - top - height;
        next.page.right = doc.body.scrollWidth - left - width;
      }

      if (typeof this.options.optimizations !== 'undefined' && this.options.optimizations.moveElement !== false && !(typeof this.targetModifier !== 'undefined')) {
        (function () {
          var offsetParent = _this7.cache('target-offsetparent', function () {
            return getOffsetParent(_this7.target);
          });
          var offsetPosition = _this7.cache('target-offsetparent-bounds', function () {
            return getBounds(offsetParent);
          });
          var offsetParentStyle = getComputedStyle(offsetParent);
          var offsetParentSize = offsetPosition;

          var offsetBorder = {};
          ['Top', 'Left', 'Bottom', 'Right'].forEach(function (side) {
            offsetBorder[side.toLowerCase()] = parseFloat(offsetParentStyle['border' + side + 'Width']);
          });

          offsetPosition.right = doc.body.scrollWidth - offsetPosition.left - offsetParentSize.width + offsetBorder.right;
          offsetPosition.bottom = doc.body.scrollHeight - offsetPosition.top - offsetParentSize.height + offsetBorder.bottom;

          if (next.page.top >= offsetPosition.top + offsetBorder.top && next.page.bottom >= offsetPosition.bottom) {
            if (next.page.left >= offsetPosition.left + offsetBorder.left && next.page.right >= offsetPosition.right) {
              // We're within the visible part of the target's scroll parent
              var scrollTop = offsetParent.scrollTop;
              var scrollLeft = offsetParent.scrollLeft;

              // It's position relative to the target's offset parent (absolute positioning when
              // the element is moved to be a child of the target's offset parent).
              next.offset = {
                top: next.page.top - offsetPosition.top + scrollTop - offsetBorder.top,
                left: next.page.left - offsetPosition.left + scrollLeft - offsetBorder.left
              };
            }
          }
        })();
      }

      // We could also travel up the DOM and try each containing context, rather than only
      // looking at the body, but we're gonna get diminishing returns.

      this.move(next);

      this.history.unshift(next);

      if (this.history.length > 3) {
        this.history.pop();
      }

      if (flushChanges) {
        flush();
      }

      return true;
    }

    // THE ISSUE
  }, {
    key: 'move',
    value: function move(pos) {
      var _this8 = this;

      if (!(typeof this.element.parentNode !== 'undefined')) {
        return;
      }

      var same = {};

      for (var type in pos) {
        same[type] = {};

        for (var key in pos[type]) {
          var found = false;

          for (var i = 0; i < this.history.length; ++i) {
            var point = this.history[i];
            if (typeof point[type] !== 'undefined' && !within(point[type][key], pos[type][key])) {
              found = true;
              break;
            }
          }

          if (!found) {
            same[type][key] = true;
          }
        }
      }

      var css = { top: '', left: '', right: '', bottom: '' };

      var transcribe = function transcribe(_same, _pos) {
        var hasOptimizations = typeof _this8.options.optimizations !== 'undefined';
        var gpu = hasOptimizations ? _this8.options.optimizations.gpu : null;
        if (gpu !== false) {
          var yPos = undefined,
              xPos = undefined;
          if (_same.top) {
            css.top = 0;
            yPos = _pos.top;
          } else {
            css.bottom = 0;
            yPos = -_pos.bottom;
          }

          if (_same.left) {
            css.left = 0;
            xPos = _pos.left;
          } else {
            css.right = 0;
            xPos = -_pos.right;
          }

          if (window.matchMedia) {
            // HubSpot/tether#207
            var retina = window.matchMedia('only screen and (min-resolution: 1.3dppx)').matches || window.matchMedia('only screen and (-webkit-min-device-pixel-ratio: 1.3)').matches;
            if (!retina) {
              xPos = Math.round(xPos);
              yPos = Math.round(yPos);
            }
          }

          css[transformKey] = 'translateX(' + xPos + 'px) translateY(' + yPos + 'px)';

          if (transformKey !== 'msTransform') {
            // The Z transform will keep this in the GPU (faster, and prevents artifacts),
            // but IE9 doesn't support 3d transforms and will choke.
            css[transformKey] += " translateZ(0)";
          }
        } else {
          if (_same.top) {
            css.top = _pos.top + 'px';
          } else {
            css.bottom = _pos.bottom + 'px';
          }

          if (_same.left) {
            css.left = _pos.left + 'px';
          } else {
            css.right = _pos.right + 'px';
          }
        }
      };

      var moved = false;
      if ((same.page.top || same.page.bottom) && (same.page.left || same.page.right)) {
        css.position = 'absolute';
        transcribe(same.page, pos.page);
      } else if ((same.viewport.top || same.viewport.bottom) && (same.viewport.left || same.viewport.right)) {
        css.position = 'fixed';
        transcribe(same.viewport, pos.viewport);
      } else if (typeof same.offset !== 'undefined' && same.offset.top && same.offset.left) {
        (function () {
          css.position = 'absolute';
          var offsetParent = _this8.cache('target-offsetparent', function () {
            return getOffsetParent(_this8.target);
          });

          if (getOffsetParent(_this8.element) !== offsetParent) {
            defer(function () {
              _this8.element.parentNode.removeChild(_this8.element);
              offsetParent.appendChild(_this8.element);
            });
          }

          transcribe(same.offset, pos.offset);
          moved = true;
        })();
      } else {
        css.position = 'absolute';
        transcribe({ top: true, left: true }, pos.page);
      }

      if (!moved) {
        if (this.options.bodyElement) {
          this.options.bodyElement.appendChild(this.element);
        } else {
          var offsetParentIsBody = true;
          var currentNode = this.element.parentNode;
          while (currentNode && currentNode.nodeType === 1 && currentNode.tagName !== 'BODY') {
            if (getComputedStyle(currentNode).position !== 'static') {
              offsetParentIsBody = false;
              break;
            }

            currentNode = currentNode.parentNode;
          }

          if (!offsetParentIsBody) {
            this.element.parentNode.removeChild(this.element);
            this.element.ownerDocument.body.appendChild(this.element);
          }
        }
      }

      // Any css change will trigger a repaint, so let's avoid one if nothing changed
      var writeCSS = {};
      var write = false;
      for (var key in css) {
        var val = css[key];
        var elVal = this.element.style[key];

        if (elVal !== val) {
          write = true;
          writeCSS[key] = val;
        }
      }

      if (write) {
        defer(function () {
          extend(_this8.element.style, writeCSS);
          _this8.trigger('repositioned');
        });
      }
    }
  }]);

  return TetherClass;
})(Evented);

TetherClass.modules = [];

TetherBase.position = position;

var Tether = extend(TetherClass, TetherBase);
/* globals TetherBase */

'use strict';

var _slicedToArray = (function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i['return']) _i['return'](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError('Invalid attempt to destructure non-iterable instance'); } }; })();

var _TetherBase$Utils = TetherBase.Utils;
var getBounds = _TetherBase$Utils.getBounds;
var extend = _TetherBase$Utils.extend;
var updateClasses = _TetherBase$Utils.updateClasses;
var defer = _TetherBase$Utils.defer;

var BOUNDS_FORMAT = ['left', 'top', 'right', 'bottom'];

function getBoundingRect(tether, to) {
  if (to === 'scrollParent') {
    to = tether.scrollParents[0];
  } else if (to === 'window') {
    to = [pageXOffset, pageYOffset, innerWidth + pageXOffset, innerHeight + pageYOffset];
  }

  if (to === document) {
    to = to.documentElement;
  }

  if (typeof to.nodeType !== 'undefined') {
    (function () {
      var node = to;
      var size = getBounds(to);
      var pos = size;
      var style = getComputedStyle(to);

      to = [pos.left, pos.top, size.width + pos.left, size.height + pos.top];

      // Account any parent Frames scroll offset
      if (node.ownerDocument !== document) {
        var win = node.ownerDocument.defaultView;
        to[0] += win.pageXOffset;
        to[1] += win.pageYOffset;
        to[2] += win.pageXOffset;
        to[3] += win.pageYOffset;
      }

      BOUNDS_FORMAT.forEach(function (side, i) {
        side = side[0].toUpperCase() + side.substr(1);
        if (side === 'Top' || side === 'Left') {
          to[i] += parseFloat(style['border' + side + 'Width']);
        } else {
          to[i] -= parseFloat(style['border' + side + 'Width']);
        }
      });
    })();
  }

  return to;
}

TetherBase.modules.push({
  position: function position(_ref) {
    var _this = this;

    var top = _ref.top;
    var left = _ref.left;
    var targetAttachment = _ref.targetAttachment;

    if (!this.options.constraints) {
      return true;
    }

    var _cache = this.cache('element-bounds', function () {
      return getBounds(_this.element);
    });

    var height = _cache.height;
    var width = _cache.width;

    if (width === 0 && height === 0 && typeof this.lastSize !== 'undefined') {
      var _lastSize = this.lastSize;

      // Handle the item getting hidden as a result of our positioning without glitching
      // the classes in and out
      width = _lastSize.width;
      height = _lastSize.height;
    }

    var targetSize = this.cache('target-bounds', function () {
      return _this.getTargetBounds();
    });

    var targetHeight = targetSize.height;
    var targetWidth = targetSize.width;

    var allClasses = [this.getClass('pinned'), this.getClass('out-of-bounds')];

    this.options.constraints.forEach(function (constraint) {
      var outOfBoundsClass = constraint.outOfBoundsClass;
      var pinnedClass = constraint.pinnedClass;

      if (outOfBoundsClass) {
        allClasses.push(outOfBoundsClass);
      }
      if (pinnedClass) {
        allClasses.push(pinnedClass);
      }
    });

    allClasses.forEach(function (cls) {
      ['left', 'top', 'right', 'bottom'].forEach(function (side) {
        allClasses.push(cls + '-' + side);
      });
    });

    var addClasses = [];

    var tAttachment = extend({}, targetAttachment);
    var eAttachment = extend({}, this.attachment);

    this.options.constraints.forEach(function (constraint) {
      var to = constraint.to;
      var attachment = constraint.attachment;
      var pin = constraint.pin;

      if (typeof attachment === 'undefined') {
        attachment = '';
      }

      var changeAttachX = undefined,
          changeAttachY = undefined;
      if (attachment.indexOf(' ') >= 0) {
        var _attachment$split = attachment.split(' ');

        var _attachment$split2 = _slicedToArray(_attachment$split, 2);

        changeAttachY = _attachment$split2[0];
        changeAttachX = _attachment$split2[1];
      } else {
        changeAttachX = changeAttachY = attachment;
      }

      var bounds = getBoundingRect(_this, to);

      if (changeAttachY === 'target' || changeAttachY === 'both') {
        if (top < bounds[1] && tAttachment.top === 'top') {
          top += targetHeight;
          tAttachment.top = 'bottom';
        }

        if (top + height > bounds[3] && tAttachment.top === 'bottom') {
          top -= targetHeight;
          tAttachment.top = 'top';
        }
      }

      if (changeAttachY === 'together') {
        if (tAttachment.top === 'top') {
          if (eAttachment.top === 'bottom' && top < bounds[1]) {
            top += targetHeight;
            tAttachment.top = 'bottom';

            top += height;
            eAttachment.top = 'top';
          } else if (eAttachment.top === 'top' && top + height > bounds[3] && top - (height - targetHeight) >= bounds[1]) {
            top -= height - targetHeight;
            tAttachment.top = 'bottom';

            eAttachment.top = 'bottom';
          }
        }

        if (tAttachment.top === 'bottom') {
          if (eAttachment.top === 'top' && top + height > bounds[3]) {
            top -= targetHeight;
            tAttachment.top = 'top';

            top -= height;
            eAttachment.top = 'bottom';
          } else if (eAttachment.top === 'bottom' && top < bounds[1] && top + (height * 2 - targetHeight) <= bounds[3]) {
            top += height - targetHeight;
            tAttachment.top = 'top';

            eAttachment.top = 'top';
          }
        }

        if (tAttachment.top === 'middle') {
          if (top + height > bounds[3] && eAttachment.top === 'top') {
            top -= height;
            eAttachment.top = 'bottom';
          } else if (top < bounds[1] && eAttachment.top === 'bottom') {
            top += height;
            eAttachment.top = 'top';
          }
        }
      }

      if (changeAttachX === 'target' || changeAttachX === 'both') {
        if (left < bounds[0] && tAttachment.left === 'left') {
          left += targetWidth;
          tAttachment.left = 'right';
        }

        if (left + width > bounds[2] && tAttachment.left === 'right') {
          left -= targetWidth;
          tAttachment.left = 'left';
        }
      }

      if (changeAttachX === 'together') {
        if (left < bounds[0] && tAttachment.left === 'left') {
          if (eAttachment.left === 'right') {
            left += targetWidth;
            tAttachment.left = 'right';

            left += width;
            eAttachment.left = 'left';
          } else if (eAttachment.left === 'left') {
            left += targetWidth;
            tAttachment.left = 'right';

            left -= width;
            eAttachment.left = 'right';
          }
        } else if (left + width > bounds[2] && tAttachment.left === 'right') {
          if (eAttachment.left === 'left') {
            left -= targetWidth;
            tAttachment.left = 'left';

            left -= width;
            eAttachment.left = 'right';
          } else if (eAttachment.left === 'right') {
            left -= targetWidth;
            tAttachment.left = 'left';

            left += width;
            eAttachment.left = 'left';
          }
        } else if (tAttachment.left === 'center') {
          if (left + width > bounds[2] && eAttachment.left === 'left') {
            left -= width;
            eAttachment.left = 'right';
          } else if (left < bounds[0] && eAttachment.left === 'right') {
            left += width;
            eAttachment.left = 'left';
          }
        }
      }

      if (changeAttachY === 'element' || changeAttachY === 'both') {
        if (top < bounds[1] && eAttachment.top === 'bottom') {
          top += height;
          eAttachment.top = 'top';
        }

        if (top + height > bounds[3] && eAttachment.top === 'top') {
          top -= height;
          eAttachment.top = 'bottom';
        }
      }

      if (changeAttachX === 'element' || changeAttachX === 'both') {
        if (left < bounds[0]) {
          if (eAttachment.left === 'right') {
            left += width;
            eAttachment.left = 'left';
          } else if (eAttachment.left === 'center') {
            left += width / 2;
            eAttachment.left = 'left';
          }
        }

        if (left + width > bounds[2]) {
          if (eAttachment.left === 'left') {
            left -= width;
            eAttachment.left = 'right';
          } else if (eAttachment.left === 'center') {
            left -= width / 2;
            eAttachment.left = 'right';
          }
        }
      }

      if (typeof pin === 'string') {
        pin = pin.split(',').map(function (p) {
          return p.trim();
        });
      } else if (pin === true) {
        pin = ['top', 'left', 'right', 'bottom'];
      }

      pin = pin || [];

      var pinned = [];
      var oob = [];

      if (top < bounds[1]) {
        if (pin.indexOf('top') >= 0) {
          top = bounds[1];
          pinned.push('top');
        } else {
          oob.push('top');
        }
      }

      if (top + height > bounds[3]) {
        if (pin.indexOf('bottom') >= 0) {
          top = bounds[3] - height;
          pinned.push('bottom');
        } else {
          oob.push('bottom');
        }
      }

      if (left < bounds[0]) {
        if (pin.indexOf('left') >= 0) {
          left = bounds[0];
          pinned.push('left');
        } else {
          oob.push('left');
        }
      }

      if (left + width > bounds[2]) {
        if (pin.indexOf('right') >= 0) {
          left = bounds[2] - width;
          pinned.push('right');
        } else {
          oob.push('right');
        }
      }

      if (pinned.length) {
        (function () {
          var pinnedClass = undefined;
          if (typeof _this.options.pinnedClass !== 'undefined') {
            pinnedClass = _this.options.pinnedClass;
          } else {
            pinnedClass = _this.getClass('pinned');
          }

          addClasses.push(pinnedClass);
          pinned.forEach(function (side) {
            addClasses.push(pinnedClass + '-' + side);
          });
        })();
      }

      if (oob.length) {
        (function () {
          var oobClass = undefined;
          if (typeof _this.options.outOfBoundsClass !== 'undefined') {
            oobClass = _this.options.outOfBoundsClass;
          } else {
            oobClass = _this.getClass('out-of-bounds');
          }

          addClasses.push(oobClass);
          oob.forEach(function (side) {
            addClasses.push(oobClass + '-' + side);
          });
        })();
      }

      if (pinned.indexOf('left') >= 0 || pinned.indexOf('right') >= 0) {
        eAttachment.left = tAttachment.left = false;
      }
      if (pinned.indexOf('top') >= 0 || pinned.indexOf('bottom') >= 0) {
        eAttachment.top = tAttachment.top = false;
      }

      if (tAttachment.top !== targetAttachment.top || tAttachment.left !== targetAttachment.left || eAttachment.top !== _this.attachment.top || eAttachment.left !== _this.attachment.left) {
        _this.updateAttachClasses(eAttachment, tAttachment);
        _this.trigger('update', {
          attachment: eAttachment,
          targetAttachment: tAttachment
        });
      }
    });

    defer(function () {
      if (!(_this.options.addTargetClasses === false)) {
        updateClasses(_this.target, addClasses, allClasses);
      }
      updateClasses(_this.element, addClasses, allClasses);
    });

    return { top: top, left: left };
  }
});
/* globals TetherBase */

'use strict';

var _TetherBase$Utils = TetherBase.Utils;
var getBounds = _TetherBase$Utils.getBounds;
var updateClasses = _TetherBase$Utils.updateClasses;
var defer = _TetherBase$Utils.defer;

TetherBase.modules.push({
  position: function position(_ref) {
    var _this = this;

    var top = _ref.top;
    var left = _ref.left;

    var _cache = this.cache('element-bounds', function () {
      return getBounds(_this.element);
    });

    var height = _cache.height;
    var width = _cache.width;

    var targetPos = this.getTargetBounds();

    var bottom = top + height;
    var right = left + width;

    var abutted = [];
    if (top <= targetPos.bottom && bottom >= targetPos.top) {
      ['left', 'right'].forEach(function (side) {
        var targetPosSide = targetPos[side];
        if (targetPosSide === left || targetPosSide === right) {
          abutted.push(side);
        }
      });
    }

    if (left <= targetPos.right && right >= targetPos.left) {
      ['top', 'bottom'].forEach(function (side) {
        var targetPosSide = targetPos[side];
        if (targetPosSide === top || targetPosSide === bottom) {
          abutted.push(side);
        }
      });
    }

    var allClasses = [];
    var addClasses = [];

    var sides = ['left', 'top', 'right', 'bottom'];
    allClasses.push(this.getClass('abutted'));
    sides.forEach(function (side) {
      allClasses.push(_this.getClass('abutted') + '-' + side);
    });

    if (abutted.length) {
      addClasses.push(this.getClass('abutted'));
    }

    abutted.forEach(function (side) {
      addClasses.push(_this.getClass('abutted') + '-' + side);
    });

    defer(function () {
      if (!(_this.options.addTargetClasses === false)) {
        updateClasses(_this.target, addClasses, allClasses);
      }
      updateClasses(_this.element, addClasses, allClasses);
    });

    return true;
  }
});
/* globals TetherBase */

'use strict';

var _slicedToArray = (function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i['return']) _i['return'](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError('Invalid attempt to destructure non-iterable instance'); } }; })();

TetherBase.modules.push({
  position: function position(_ref) {
    var top = _ref.top;
    var left = _ref.left;

    if (!this.options.shift) {
      return;
    }

    var shift = this.options.shift;
    if (typeof this.options.shift === 'function') {
      shift = this.options.shift.call(this, { top: top, left: left });
    }

    var shiftTop = undefined,
        shiftLeft = undefined;
    if (typeof shift === 'string') {
      shift = shift.split(' ');
      shift[1] = shift[1] || shift[0];

      var _shift = shift;

      var _shift2 = _slicedToArray(_shift, 2);

      shiftTop = _shift2[0];
      shiftLeft = _shift2[1];

      shiftTop = parseFloat(shiftTop, 10);
      shiftLeft = parseFloat(shiftLeft, 10);
    } else {
      shiftTop = shift.top;
      shiftLeft = shift.left;
    }

    top += shiftTop;
    left += shiftLeft;

    return { top: top, left: left };
  }
});
return Tether;

}));
;
/*!
 * jQuery JavaScript Library v3.1.1
 * https://jquery.com/
 *
 * Includes Sizzle.js
 * https://sizzlejs.com/
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license
 * https://jquery.org/license
 *
 * Date: 2016-09-22T22:30Z
 */
(function (global, factory) {
    "use strict";
    if (typeof module === "object" && typeof module.exports === "object") {
        // For CommonJS and CommonJS-like environments where a proper `window`
        // is present, execute the factory and get jQuery.
        // For environments that do not have a `window` with a `document`
        // (such as Node.js), expose a factory as module.exports.
        // This accentuates the need for the creation of a real `window`.
        // e.g. var jQuery = require("jquery")(window);
        // See ticket #14549 for more info.
        module.exports = global.document ?
            factory(global, true) :
            function (w) {
                if (!w.document) {
                    throw new Error("jQuery requires a window with a document");
                }
                return factory(w);
            };
    }
    else {
        factory(global);
    }
    // Pass this if window is not defined yet
})(typeof window !== "undefined" ? window : this, function (window, noGlobal) {
    // Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1
    // throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode
    // arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common
    // enough that all such attempts are guarded in a try block.
    "use strict";
    var arr = [];
    var document = window.document;
    var getProto = Object.getPrototypeOf;
    var slice = arr.slice;
    var concat = arr.concat;
    var push = arr.push;
    var indexOf = arr.indexOf;
    var class2type = {};
    var toString = class2type.toString;
    var hasOwn = class2type.hasOwnProperty;
    var fnToString = hasOwn.toString;
    var ObjectFunctionString = fnToString.call(Object);
    var support = {};
    function DOMEval(code, doc) {
        doc = doc || document;
        var script = doc.createElement("script");
        script.text = code;
        doc.head.appendChild(script).parentNode.removeChild(script);
    }
    /* global Symbol */
    // Defining this global in .eslintrc.json would create a danger of using the global
    // unguarded in another place, it seems safer to define global only for this module
    var version = "3.1.1", 
    // Define a local copy of jQuery
    jQuery = function (selector, context) {
        // The jQuery object is actually just the init constructor 'enhanced'
        // Need init if jQuery is called (just allow error to be thrown if not included)
        return new jQuery.fn.init(selector, context);
    }, 
    // Support: Android <=4.0 only
    // Make sure we trim BOM and NBSP
    rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, 
    // Matches dashed string for camelizing
    rmsPrefix = /^-ms-/, rdashAlpha = /-([a-z])/g, 
    // Used by jQuery.camelCase as callback to replace()
    fcamelCase = function (all, letter) {
        return letter.toUpperCase();
    };
    jQuery.fn = jQuery.prototype = {
        // The current version of jQuery being used
        jquery: version,
        constructor: jQuery,
        // The default length of a jQuery object is 0
        length: 0,
        toArray: function () {
            return slice.call(this);
        },
        // Get the Nth element in the matched element set OR
        // Get the whole matched element set as a clean array
        get: function (num) {
            // Return all the elements in a clean array
            if (num == null) {
                return slice.call(this);
            }
            // Return just the one element from the set
            return num < 0 ? this[num + this.length] : this[num];
        },
        // Take an array of elements and push it onto the stack
        // (returning the new matched element set)
        pushStack: function (elems) {
            // Build a new jQuery matched element set
            var ret = jQuery.merge(this.constructor(), elems);
            // Add the old object onto the stack (as a reference)
            ret.prevObject = this;
            // Return the newly-formed element set
            return ret;
        },
        // Execute a callback for every element in the matched set.
        each: function (callback) {
            return jQuery.each(this, callback);
        },
        map: function (callback) {
            return this.pushStack(jQuery.map(this, function (elem, i) {
                return callback.call(elem, i, elem);
            }));
        },
        slice: function () {
            return this.pushStack(slice.apply(this, arguments));
        },
        first: function () {
            return this.eq(0);
        },
        last: function () {
            return this.eq(-1);
        },
        eq: function (i) {
            var len = this.length, j = +i + (i < 0 ? len : 0);
            return this.pushStack(j >= 0 && j < len ? [this[j]] : []);
        },
        end: function () {
            return this.prevObject || this.constructor();
        },
        // For internal use only.
        // Behaves like an Array's method, not like a jQuery method.
        push: push,
        sort: arr.sort,
        splice: arr.splice
    };
    jQuery.extend = jQuery.fn.extend = function () {
        var options, name, src, copy, copyIsArray, clone, target = arguments[0] || {}, i = 1, length = arguments.length, deep = false;
        // Handle a deep copy situation
        if (typeof target === "boolean") {
            deep = target;
            // Skip the boolean and the target
            target = arguments[i] || {};
            i++;
        }
        // Handle case when target is a string or something (possible in deep copy)
        if (typeof target !== "object" && !jQuery.isFunction(target)) {
            target = {};
        }
        // Extend jQuery itself if only one argument is passed
        if (i === length) {
            target = this;
            i--;
        }
        for (; i < length; i++) {
            // Only deal with non-null/undefined values
            if ((options = arguments[i]) != null) {
                // Extend the base object
                for (name in options) {
                    src = target[name];
                    copy = options[name];
                    // Prevent never-ending loop
                    if (target === copy) {
                        continue;
                    }
                    // Recurse if we're merging plain objects or arrays
                    if (deep && copy && (jQuery.isPlainObject(copy) ||
                        (copyIsArray = jQuery.isArray(copy)))) {
                        if (copyIsArray) {
                            copyIsArray = false;
                            clone = src && jQuery.isArray(src) ? src : [];
                        }
                        else {
                            clone = src && jQuery.isPlainObject(src) ? src : {};
                        }
                        // Never move original objects, clone them
                        target[name] = jQuery.extend(deep, clone, copy);
                    }
                    else if (copy !== undefined) {
                        target[name] = copy;
                    }
                }
            }
        }
        // Return the modified object
        return target;
    };
    jQuery.extend({
        // Unique for each copy of jQuery on the page
        expando: "jQuery" + (version + Math.random()).replace(/\D/g, ""),
        // Assume jQuery is ready without the ready module
        isReady: true,
        error: function (msg) {
            throw new Error(msg);
        },
        noop: function () { },
        isFunction: function (obj) {
            return jQuery.type(obj) === "function";
        },
        isArray: Array.isArray,
        isWindow: function (obj) {
            return obj != null && obj === obj.window;
        },
        isNumeric: function (obj) {
            // As of jQuery 3.0, isNumeric is limited to
            // strings and numbers (primitives or objects)
            // that can be coerced to finite numbers (gh-2662)
            var type = jQuery.type(obj);
            return (type === "number" || type === "string") &&
                // parseFloat NaNs numeric-cast false positives ("")
                // ...but misinterprets leading-number strings, particularly hex literals ("0x...")
                // subtraction forces infinities to NaN
                !isNaN(obj - parseFloat(obj));
        },
        isPlainObject: function (obj) {
            var proto, Ctor;
            // Detect obvious negatives
            // Use toString instead of jQuery.type to catch host objects
            if (!obj || toString.call(obj) !== "[object Object]") {
                return false;
            }
            proto = getProto(obj);
            // Objects with no prototype (e.g., `Object.create( null )`) are plain
            if (!proto) {
                return true;
            }
            // Objects with prototype are plain iff they were constructed by a global Object function
            Ctor = hasOwn.call(proto, "constructor") && proto.constructor;
            return typeof Ctor === "function" && fnToString.call(Ctor) === ObjectFunctionString;
        },
        isEmptyObject: function (obj) {
            /* eslint-disable no-unused-vars */
            // See https://github.com/eslint/eslint/issues/6125
            var name;
            for (name in obj) {
                return false;
            }
            return true;
        },
        type: function (obj) {
            if (obj == null) {
                return obj + "";
            }
            // Support: Android <=2.3 only (functionish RegExp)
            return typeof obj === "object" || typeof obj === "function" ?
                class2type[toString.call(obj)] || "object" :
                typeof obj;
        },
        // Evaluates a script in a global context
        globalEval: function (code) {
            DOMEval(code);
        },
        // Convert dashed to camelCase; used by the css and data modules
        // Support: IE <=9 - 11, Edge 12 - 13
        // Microsoft forgot to hump their vendor prefix (#9572)
        camelCase: function (string) {
            return string.replace(rmsPrefix, "ms-").replace(rdashAlpha, fcamelCase);
        },
        nodeName: function (elem, name) {
            return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
        },
        each: function (obj, callback) {
            var length, i = 0;
            if (isArrayLike(obj)) {
                length = obj.length;
                for (; i < length; i++) {
                    if (callback.call(obj[i], i, obj[i]) === false) {
                        break;
                    }
                }
            }
            else {
                for (i in obj) {
                    if (callback.call(obj[i], i, obj[i]) === false) {
                        break;
                    }
                }
            }
            return obj;
        },
        // Support: Android <=4.0 only
        trim: function (text) {
            return text == null ?
                "" :
                (text + "").replace(rtrim, "");
        },
        // results is for internal usage only
        makeArray: function (arr, results) {
            var ret = results || [];
            if (arr != null) {
                if (isArrayLike(Object(arr))) {
                    jQuery.merge(ret, typeof arr === "string" ?
                        [arr] : arr);
                }
                else {
                    push.call(ret, arr);
                }
            }
            return ret;
        },
        inArray: function (elem, arr, i) {
            return arr == null ? -1 : indexOf.call(arr, elem, i);
        },
        // Support: Android <=4.0 only, PhantomJS 1 only
        // push.apply(_, arraylike) throws on ancient WebKit
        merge: function (first, second) {
            var len = +second.length, j = 0, i = first.length;
            for (; j < len; j++) {
                first[i++] = second[j];
            }
            first.length = i;
            return first;
        },
        grep: function (elems, callback, invert) {
            var callbackInverse, matches = [], i = 0, length = elems.length, callbackExpect = !invert;
            // Go through the array, only saving the items
            // that pass the validator function
            for (; i < length; i++) {
                callbackInverse = !callback(elems[i], i);
                if (callbackInverse !== callbackExpect) {
                    matches.push(elems[i]);
                }
            }
            return matches;
        },
        // arg is for internal usage only
        map: function (elems, callback, arg) {
            var length, value, i = 0, ret = [];
            // Go through the array, translating each of the items to their new values
            if (isArrayLike(elems)) {
                length = elems.length;
                for (; i < length; i++) {
                    value = callback(elems[i], i, arg);
                    if (value != null) {
                        ret.push(value);
                    }
                }
            }
            else {
                for (i in elems) {
                    value = callback(elems[i], i, arg);
                    if (value != null) {
                        ret.push(value);
                    }
                }
            }
            // Flatten any nested arrays
            return concat.apply([], ret);
        },
        // A global GUID counter for objects
        guid: 1,
        // Bind a function to a context, optionally partially applying any
        // arguments.
        proxy: function (fn, context) {
            var tmp, args, proxy;
            if (typeof context === "string") {
                tmp = fn[context];
                context = fn;
                fn = tmp;
            }
            // Quick check to determine if target is callable, in the spec
            // this throws a TypeError, but we will just return undefined.
            if (!jQuery.isFunction(fn)) {
                return undefined;
            }
            // Simulated bind
            args = slice.call(arguments, 2);
            proxy = function () {
                return fn.apply(context || this, args.concat(slice.call(arguments)));
            };
            // Set the guid of unique handler to the same of original handler, so it can be removed
            proxy.guid = fn.guid = fn.guid || jQuery.guid++;
            return proxy;
        },
        now: Date.now,
        // jQuery.support is not used in Core but other projects attach their
        // properties to it so it needs to exist.
        support: support
    });
    if (typeof Symbol === "function") {
        jQuery.fn[Symbol.iterator] = arr[Symbol.iterator];
    }
    // Populate the class2type map
    jQuery.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "), function (i, name) {
        class2type["[object " + name + "]"] = name.toLowerCase();
    });
    function isArrayLike(obj) {
        // Support: real iOS 8.2 only (not reproducible in simulator)
        // `in` check used to prevent JIT error (gh-2145)
        // hasOwn isn't used here due to false negatives
        // regarding Nodelist length in IE
        var length = !!obj && "length" in obj && obj.length, type = jQuery.type(obj);
        if (type === "function" || jQuery.isWindow(obj)) {
            return false;
        }
        return type === "array" || length === 0 ||
            typeof length === "number" && length > 0 && (length - 1) in obj;
    }
    var Sizzle = 
    /*!
     * Sizzle CSS Selector Engine v2.3.3
     * https://sizzlejs.com/
     *
     * Copyright jQuery Foundation and other contributors
     * Released under the MIT license
     * http://jquery.org/license
     *
     * Date: 2016-08-08
     */
    (function (window) {
        var i, support, Expr, getText, isXML, tokenize, compile, select, outermostContext, sortInput, hasDuplicate, 
        // Local document vars
        setDocument, document, docElem, documentIsHTML, rbuggyQSA, rbuggyMatches, matches, contains, 
        // Instance-specific data
        expando = "sizzle" + 1 * new Date(), preferredDoc = window.document, dirruns = 0, done = 0, classCache = createCache(), tokenCache = createCache(), compilerCache = createCache(), sortOrder = function (a, b) {
            if (a === b) {
                hasDuplicate = true;
            }
            return 0;
        }, 
        // Instance methods
        hasOwn = ({}).hasOwnProperty, arr = [], pop = arr.pop, push_native = arr.push, push = arr.push, slice = arr.slice, 
        // Use a stripped-down indexOf as it's faster than native
        // https://jsperf.com/thor-indexof-vs-for/5
        indexOf = function (list, elem) {
            var i = 0, len = list.length;
            for (; i < len; i++) {
                if (list[i] === elem) {
                    return i;
                }
            }
            return -1;
        }, booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", 
        // Regular expressions
        // http://www.w3.org/TR/css3-selectors/#whitespace
        whitespace = "[\\x20\\t\\r\\n\\f]", 
        // http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
        identifier = "(?:\\\\.|[\\w-]|[^\0-\\xa0])+", 
        // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors
        attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace +
            // Operator (capture 2)
            "*([*^$|!~]?=)" + whitespace +
            // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]"
            "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace +
            "*\\]", pseudos = ":(" + identifier + ")(?:\\((" +
            // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:
            // 1. quoted (capture 3; capture 4 or capture 5)
            "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" +
            // 2. simple (capture 6)
            "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" +
            // 3. anything else (capture 2)
            ".*" +
            ")\\)|)", 
        // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
        rwhitespace = new RegExp(whitespace + "+", "g"), rtrim = new RegExp("^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g"), rcomma = new RegExp("^" + whitespace + "*," + whitespace + "*"), rcombinators = new RegExp("^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*"), rattributeQuotes = new RegExp("=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g"), rpseudo = new RegExp(pseudos), ridentifier = new RegExp("^" + identifier + "$"), matchExpr = {
            "ID": new RegExp("^#(" + identifier + ")"),
            "CLASS": new RegExp("^\\.(" + identifier + ")"),
            "TAG": new RegExp("^(" + identifier + "|[*])"),
            "ATTR": new RegExp("^" + attributes),
            "PSEUDO": new RegExp("^" + pseudos),
            "CHILD": new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
                "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
                "*(\\d+)|))" + whitespace + "*\\)|)", "i"),
            "bool": new RegExp("^(?:" + booleans + ")$", "i"),
            // For use in libraries implementing .is()
            // We use this for POS matching in `select`
            "needsContext": new RegExp("^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
                whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i")
        }, rinputs = /^(?:input|select|textarea|button)$/i, rheader = /^h\d$/i, rnative = /^[^{]+\{\s*\[native \w/, 
        // Easily-parseable/retrievable ID or TAG or CLASS selectors
        rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, rsibling = /[+~]/, 
        // CSS escapes
        // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
        runescape = new RegExp("\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig"), funescape = function (_, escaped, escapedWhitespace) {
            var high = "0x" + escaped - 0x10000;
            // NaN means non-codepoint
            // Support: Firefox<24
            // Workaround erroneous numeric interpretation of +"0x"
            return high !== high || escapedWhitespace ?
                escaped :
                high < 0 ?
                    // BMP codepoint
                    String.fromCharCode(high + 0x10000) :
                    // Supplemental Plane codepoint (surrogate pair)
                    String.fromCharCode(high >> 10 | 0xD800, high & 0x3FF | 0xDC00);
        }, 
        // CSS string/identifier serialization
        // https://drafts.csswg.org/cssom/#common-serializing-idioms
        rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, fcssescape = function (ch, asCodePoint) {
            if (asCodePoint) {
                // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER
                if (ch === "\0") {
                    return "\uFFFD";
                }
                // Control characters and (dependent upon position) numbers get escaped as code points
                return ch.slice(0, -1) + "\\" + ch.charCodeAt(ch.length - 1).toString(16) + " ";
            }
            // Other potentially-special ASCII characters get backslash-escaped
            return "\\" + ch;
        }, 
        // Used for iframes
        // See setDocument()
        // Removing the function wrapper causes a "Permission Denied"
        // error in IE
        unloadHandler = function () {
            setDocument();
        }, disabledAncestor = addCombinator(function (elem) {
            return elem.disabled === true && ("form" in elem || "label" in elem);
        }, { dir: "parentNode", next: "legend" });
        // Optimize for push.apply( _, NodeList )
        try {
            push.apply((arr = slice.call(preferredDoc.childNodes)), preferredDoc.childNodes);
            // Support: Android<4.0
            // Detect silently failing push.apply
            arr[preferredDoc.childNodes.length].nodeType;
        }
        catch (e) {
            push = { apply: arr.length ?
                    // Leverage slice if possible
                    function (target, els) {
                        push_native.apply(target, slice.call(els));
                    } :
                    // Support: IE<9
                    // Otherwise append directly
                    function (target, els) {
                        var j = target.length, i = 0;
                        // Can't trust NodeList.length
                        while ((target[j++] = els[i++])) { }
                        target.length = j - 1;
                    }
            };
        }
        function Sizzle(selector, context, results, seed) {
            var m, i, elem, nid, match, groups, newSelector, newContext = context && context.ownerDocument, 
            // nodeType defaults to 9, since context defaults to document
            nodeType = context ? context.nodeType : 9;
            results = results || [];
            // Return early from calls with invalid selector or context
            if (typeof selector !== "string" || !selector ||
                nodeType !== 1 && nodeType !== 9 && nodeType !== 11) {
                return results;
            }
            // Try to shortcut find operations (as opposed to filters) in HTML documents
            if (!seed) {
                if ((context ? context.ownerDocument || context : preferredDoc) !== document) {
                    setDocument(context);
                }
                context = context || document;
                if (documentIsHTML) {
                    // If the selector is sufficiently simple, try using a "get*By*" DOM method
                    // (excepting DocumentFragment context, where the methods don't exist)
                    if (nodeType !== 11 && (match = rquickExpr.exec(selector))) {
                        // ID selector
                        if ((m = match[1])) {
                            // Document context
                            if (nodeType === 9) {
                                if ((elem = context.getElementById(m))) {
                                    // Support: IE, Opera, Webkit
                                    // TODO: identify versions
                                    // getElementById can match elements by name instead of ID
                                    if (elem.id === m) {
                                        results.push(elem);
                                        return results;
                                    }
                                }
                                else {
                                    return results;
                                }
                            }
                            else {
                                // Support: IE, Opera, Webkit
                                // TODO: identify versions
                                // getElementById can match elements by name instead of ID
                                if (newContext && (elem = newContext.getElementById(m)) &&
                                    contains(context, elem) &&
                                    elem.id === m) {
                                    results.push(elem);
                                    return results;
                                }
                            }
                        }
                        else if (match[2]) {
                            push.apply(results, context.getElementsByTagName(selector));
                            return results;
                        }
                        else if ((m = match[3]) && support.getElementsByClassName &&
                            context.getElementsByClassName) {
                            push.apply(results, context.getElementsByClassName(m));
                            return results;
                        }
                    }
                    // Take advantage of querySelectorAll
                    if (support.qsa &&
                        !compilerCache[selector + " "] &&
                        (!rbuggyQSA || !rbuggyQSA.test(selector))) {
                        if (nodeType !== 1) {
                            newContext = context;
                            newSelector = selector;
                        }
                        else if (context.nodeName.toLowerCase() !== "object") {
                            // Capture the context ID, setting it first if necessary
                            if ((nid = context.getAttribute("id"))) {
                                nid = nid.replace(rcssescape, fcssescape);
                            }
                            else {
                                context.setAttribute("id", (nid = expando));
                            }
                            // Prefix every selector in the list
                            groups = tokenize(selector);
                            i = groups.length;
                            while (i--) {
                                groups[i] = "#" + nid + " " + toSelector(groups[i]);
                            }
                            newSelector = groups.join(",");
                            // Expand context for sibling selectors
                            newContext = rsibling.test(selector) && testContext(context.parentNode) ||
                                context;
                        }
                        if (newSelector) {
                            try {
                                push.apply(results, newContext.querySelectorAll(newSelector));
                                return results;
                            }
                            catch (qsaError) {
                            }
                            finally {
                                if (nid === expando) {
                                    context.removeAttribute("id");
                                }
                            }
                        }
                    }
                }
            }
            // All others
            return select(selector.replace(rtrim, "$1"), context, results, seed);
        }
        /**
         * Create key-value caches of limited size
         * @returns {function(string, object)} Returns the Object data after storing it on itself with
         *	property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
         *	deleting the oldest entry
         */
        function createCache() {
            var keys = [];
            function cache(key, value) {
                // Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
                if (keys.push(key + " ") > Expr.cacheLength) {
                    // Only keep the most recent entries
                    delete cache[keys.shift()];
                }
                return (cache[key + " "] = value);
            }
            return cache;
        }
        /**
         * Mark a function for special use by Sizzle
         * @param {Function} fn The function to mark
         */
        function markFunction(fn) {
            fn[expando] = true;
            return fn;
        }
        /**
         * Support testing using an element
         * @param {Function} fn Passed the created element and returns a boolean result
         */
        function assert(fn) {
            var el = document.createElement("fieldset");
            try {
                return !!fn(el);
            }
            catch (e) {
                return false;
            }
            finally {
                // Remove from its parent by default
                if (el.parentNode) {
                    el.parentNode.removeChild(el);
                }
                // release memory in IE
                el = null;
            }
        }
        /**
         * Adds the same handler for all of the specified attrs
         * @param {String} attrs Pipe-separated list of attributes
         * @param {Function} handler The method that will be applied
         */
        function addHandle(attrs, handler) {
            var arr = attrs.split("|"), i = arr.length;
            while (i--) {
                Expr.attrHandle[arr[i]] = handler;
            }
        }
        /**
         * Checks document order of two siblings
         * @param {Element} a
         * @param {Element} b
         * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b
         */
        function siblingCheck(a, b) {
            var cur = b && a, diff = cur && a.nodeType === 1 && b.nodeType === 1 &&
                a.sourceIndex - b.sourceIndex;
            // Use IE sourceIndex if available on both nodes
            if (diff) {
                return diff;
            }
            // Check if b follows a
            if (cur) {
                while ((cur = cur.nextSibling)) {
                    if (cur === b) {
                        return -1;
                    }
                }
            }
            return a ? 1 : -1;
        }
        /**
         * Returns a function to use in pseudos for input types
         * @param {String} type
         */
        function createInputPseudo(type) {
            return function (elem) {
                var name = elem.nodeName.toLowerCase();
                return name === "input" && elem.type === type;
            };
        }
        /**
         * Returns a function to use in pseudos for buttons
         * @param {String} type
         */
        function createButtonPseudo(type) {
            return function (elem) {
                var name = elem.nodeName.toLowerCase();
                return (name === "input" || name === "button") && elem.type === type;
            };
        }
        /**
         * Returns a function to use in pseudos for :enabled/:disabled
         * @param {Boolean} disabled true for :disabled; false for :enabled
         */
        function createDisabledPseudo(disabled) {
            // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable
            return function (elem) {
                // Only certain elements can match :enabled or :disabled
                // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled
                // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled
                if ("form" in elem) {
                    // Check for inherited disabledness on relevant non-disabled elements:
                    // * listed form-associated elements in a disabled fieldset
                    //   https://html.spec.whatwg.org/multipage/forms.html#category-listed
                    //   https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled
                    // * option elements in a disabled optgroup
                    //   https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled
                    // All such elements have a "form" property.
                    if (elem.parentNode && elem.disabled === false) {
                        // Option elements defer to a parent optgroup if present
                        if ("label" in elem) {
                            if ("label" in elem.parentNode) {
                                return elem.parentNode.disabled === disabled;
                            }
                            else {
                                return elem.disabled === disabled;
                            }
                        }
                        // Support: IE 6 - 11
                        // Use the isDisabled shortcut property to check for disabled fieldset ancestors
                        return elem.isDisabled === disabled ||
                            // Where there is no isDisabled, check manually
                            /* jshint -W018 */
                            elem.isDisabled !== !disabled &&
                                disabledAncestor(elem) === disabled;
                    }
                    return elem.disabled === disabled;
                }
                else if ("label" in elem) {
                    return elem.disabled === disabled;
                }
                // Remaining elements are neither :enabled nor :disabled
                return false;
            };
        }
        /**
         * Returns a function to use in pseudos for positionals
         * @param {Function} fn
         */
        function createPositionalPseudo(fn) {
            return markFunction(function (argument) {
                argument = +argument;
                return markFunction(function (seed, matches) {
                    var j, matchIndexes = fn([], seed.length, argument), i = matchIndexes.length;
                    // Match elements found at the specified indexes
                    while (i--) {
                        if (seed[(j = matchIndexes[i])]) {
                            seed[j] = !(matches[j] = seed[j]);
                        }
                    }
                });
            });
        }
        /**
         * Checks a node for validity as a Sizzle context
         * @param {Element|Object=} context
         * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value
         */
        function testContext(context) {
            return context && typeof context.getElementsByTagName !== "undefined" && context;
        }
        // Expose support vars for convenience
        support = Sizzle.support = {};
        /**
         * Detects XML nodes
         * @param {Element|Object} elem An element or a document
         * @returns {Boolean} True iff elem is a non-HTML XML node
         */
        isXML = Sizzle.isXML = function (elem) {
            // documentElement is verified for cases where it doesn't yet exist
            // (such as loading iframes in IE - #4833)
            var documentElement = elem && (elem.ownerDocument || elem).documentElement;
            return documentElement ? documentElement.nodeName !== "HTML" : false;
        };
        /**
         * Sets document-related variables once based on the current document
         * @param {Element|Object} [doc] An element or document object to use to set the document
         * @returns {Object} Returns the current document
         */
        setDocument = Sizzle.setDocument = function (node) {
            var hasCompare, subWindow, doc = node ? node.ownerDocument || node : preferredDoc;
            // Return early if doc is invalid or already selected
            if (doc === document || doc.nodeType !== 9 || !doc.documentElement) {
                return document;
            }
            // Update global variables
            document = doc;
            docElem = document.documentElement;
            documentIsHTML = !isXML(document);
            // Support: IE 9-11, Edge
            // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936)
            if (preferredDoc !== document &&
                (subWindow = document.defaultView) && subWindow.top !== subWindow) {
                // Support: IE 11, Edge
                if (subWindow.addEventListener) {
                    subWindow.addEventListener("unload", unloadHandler, false);
                }
                else if (subWindow.attachEvent) {
                    subWindow.attachEvent("onunload", unloadHandler);
                }
            }
            /* Attributes
            ---------------------------------------------------------------------- */
            // Support: IE<8
            // Verify that getAttribute really returns attributes and not properties
            // (excepting IE8 booleans)
            support.attributes = assert(function (el) {
                el.className = "i";
                return !el.getAttribute("className");
            });
            /* getElement(s)By*
            ---------------------------------------------------------------------- */
            // Check if getElementsByTagName("*") returns only elements
            support.getElementsByTagName = assert(function (el) {
                el.appendChild(document.createComment(""));
                return !el.getElementsByTagName("*").length;
            });
            // Support: IE<9
            support.getElementsByClassName = rnative.test(document.getElementsByClassName);
            // Support: IE<10
            // Check if getElementById returns elements by name
            // The broken getElementById methods don't pick up programmatically-set names,
            // so use a roundabout getElementsByName test
            support.getById = assert(function (el) {
                docElem.appendChild(el).id = expando;
                return !document.getElementsByName || !document.getElementsByName(expando).length;
            });
            // ID filter and find
            if (support.getById) {
                Expr.filter["ID"] = function (id) {
                    var attrId = id.replace(runescape, funescape);
                    return function (elem) {
                        return elem.getAttribute("id") === attrId;
                    };
                };
                Expr.find["ID"] = function (id, context) {
                    if (typeof context.getElementById !== "undefined" && documentIsHTML) {
                        var elem = context.getElementById(id);
                        return elem ? [elem] : [];
                    }
                };
            }
            else {
                Expr.filter["ID"] = function (id) {
                    var attrId = id.replace(runescape, funescape);
                    return function (elem) {
                        var node = typeof elem.getAttributeNode !== "undefined" &&
                            elem.getAttributeNode("id");
                        return node && node.value === attrId;
                    };
                };
                // Support: IE 6 - 7 only
                // getElementById is not reliable as a find shortcut
                Expr.find["ID"] = function (id, context) {
                    if (typeof context.getElementById !== "undefined" && documentIsHTML) {
                        var node, i, elems, elem = context.getElementById(id);
                        if (elem) {
                            // Verify the id attribute
                            node = elem.getAttributeNode("id");
                            if (node && node.value === id) {
                                return [elem];
                            }
                            // Fall back on getElementsByName
                            elems = context.getElementsByName(id);
                            i = 0;
                            while ((elem = elems[i++])) {
                                node = elem.getAttributeNode("id");
                                if (node && node.value === id) {
                                    return [elem];
                                }
                            }
                        }
                        return [];
                    }
                };
            }
            // Tag
            Expr.find["TAG"] = support.getElementsByTagName ?
                function (tag, context) {
                    if (typeof context.getElementsByTagName !== "undefined") {
                        return context.getElementsByTagName(tag);
                    }
                    else if (support.qsa) {
                        return context.querySelectorAll(tag);
                    }
                } :
                function (tag, context) {
                    var elem, tmp = [], i = 0, 
                    // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too
                    results = context.getElementsByTagName(tag);
                    // Filter out possible comments
                    if (tag === "*") {
                        while ((elem = results[i++])) {
                            if (elem.nodeType === 1) {
                                tmp.push(elem);
                            }
                        }
                        return tmp;
                    }
                    return results;
                };
            // Class
            Expr.find["CLASS"] = support.getElementsByClassName && function (className, context) {
                if (typeof context.getElementsByClassName !== "undefined" && documentIsHTML) {
                    return context.getElementsByClassName(className);
                }
            };
            /* QSA/matchesSelector
            ---------------------------------------------------------------------- */
            // QSA and matchesSelector support
            // matchesSelector(:active) reports false when true (IE9/Opera 11.5)
            rbuggyMatches = [];
            // qSa(:focus) reports false when true (Chrome 21)
            // We allow this because of a bug in IE8/9 that throws an error
            // whenever `document.activeElement` is accessed on an iframe
            // So, we allow :focus to pass through QSA all the time to avoid the IE error
            // See https://bugs.jquery.com/ticket/13378
            rbuggyQSA = [];
            if ((support.qsa = rnative.test(document.querySelectorAll))) {
                // Build QSA regex
                // Regex strategy adopted from Diego Perini
                assert(function (el) {
                    // Select is set to empty string on purpose
                    // This is to test IE's treatment of not explicitly
                    // setting a boolean content attribute,
                    // since its presence should be enough
                    // https://bugs.jquery.com/ticket/12359
                    docElem.appendChild(el).innerHTML = "<a id='" + expando + "'></a>" +
                        "<select id='" + expando + "-\r\\' msallowcapture=''>" +
                        "<option selected=''></option></select>";
                    // Support: IE8, Opera 11-12.16
                    // Nothing should be selected when empty strings follow ^= or $= or *=
                    // The test attribute must be unknown in Opera but "safe" for WinRT
                    // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section
                    if (el.querySelectorAll("[msallowcapture^='']").length) {
                        rbuggyQSA.push("[*^$]=" + whitespace + "*(?:''|\"\")");
                    }
                    // Support: IE8
                    // Boolean attributes and "value" are not treated correctly
                    if (!el.querySelectorAll("[selected]").length) {
                        rbuggyQSA.push("\\[" + whitespace + "*(?:value|" + booleans + ")");
                    }
                    // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+
                    if (!el.querySelectorAll("[id~=" + expando + "-]").length) {
                        rbuggyQSA.push("~=");
                    }
                    // Webkit/Opera - :checked should return selected option elements
                    // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
                    // IE8 throws error here and will not see later tests
                    if (!el.querySelectorAll(":checked").length) {
                        rbuggyQSA.push(":checked");
                    }
                    // Support: Safari 8+, iOS 8+
                    // https://bugs.webkit.org/show_bug.cgi?id=136851
                    // In-page `selector#id sibling-combinator selector` fails
                    if (!el.querySelectorAll("a#" + expando + "+*").length) {
                        rbuggyQSA.push(".#.+[+~]");
                    }
                });
                assert(function (el) {
                    el.innerHTML = "<a href='' disabled='disabled'></a>" +
                        "<select disabled='disabled'><option/></select>";
                    // Support: Windows 8 Native Apps
                    // The type and name attributes are restricted during .innerHTML assignment
                    var input = document.createElement("input");
                    input.setAttribute("type", "hidden");
                    el.appendChild(input).setAttribute("name", "D");
                    // Support: IE8
                    // Enforce case-sensitivity of name attribute
                    if (el.querySelectorAll("[name=d]").length) {
                        rbuggyQSA.push("name" + whitespace + "*[*^$|!~]?=");
                    }
                    // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
                    // IE8 throws error here and will not see later tests
                    if (el.querySelectorAll(":enabled").length !== 2) {
                        rbuggyQSA.push(":enabled", ":disabled");
                    }
                    // Support: IE9-11+
                    // IE's :disabled selector does not pick up the children of disabled fieldsets
                    docElem.appendChild(el).disabled = true;
                    if (el.querySelectorAll(":disabled").length !== 2) {
                        rbuggyQSA.push(":enabled", ":disabled");
                    }
                    // Opera 10-11 does not throw on post-comma invalid pseudos
                    el.querySelectorAll("*,:x");
                    rbuggyQSA.push(",.*:");
                });
            }
            if ((support.matchesSelector = rnative.test((matches = docElem.matches ||
                docElem.webkitMatchesSelector ||
                docElem.mozMatchesSelector ||
                docElem.oMatchesSelector ||
                docElem.msMatchesSelector)))) {
                assert(function (el) {
                    // Check to see if it's possible to do matchesSelector
                    // on a disconnected node (IE 9)
                    support.disconnectedMatch = matches.call(el, "*");
                    // This should fail with an exception
                    // Gecko does not error, returns false instead
                    matches.call(el, "[s!='']:x");
                    rbuggyMatches.push("!=", pseudos);
                });
            }
            rbuggyQSA = rbuggyQSA.length && new RegExp(rbuggyQSA.join("|"));
            rbuggyMatches = rbuggyMatches.length && new RegExp(rbuggyMatches.join("|"));
            /* Contains
            ---------------------------------------------------------------------- */
            hasCompare = rnative.test(docElem.compareDocumentPosition);
            // Element contains another
            // Purposefully self-exclusive
            // As in, an element does not contain itself
            contains = hasCompare || rnative.test(docElem.contains) ?
                function (a, b) {
                    var adown = a.nodeType === 9 ? a.documentElement : a, bup = b && b.parentNode;
                    return a === bup || !!(bup && bup.nodeType === 1 && (adown.contains ?
                        adown.contains(bup) :
                        a.compareDocumentPosition && a.compareDocumentPosition(bup) & 16));
                } :
                function (a, b) {
                    if (b) {
                        while ((b = b.parentNode)) {
                            if (b === a) {
                                return true;
                            }
                        }
                    }
                    return false;
                };
            /* Sorting
            ---------------------------------------------------------------------- */
            // Document order sorting
            sortOrder = hasCompare ?
                function (a, b) {
                    // Flag for duplicate removal
                    if (a === b) {
                        hasDuplicate = true;
                        return 0;
                    }
                    // Sort on method existence if only one input has compareDocumentPosition
                    var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
                    if (compare) {
                        return compare;
                    }
                    // Calculate position if both inputs belong to the same document
                    compare = (a.ownerDocument || a) === (b.ownerDocument || b) ?
                        a.compareDocumentPosition(b) :
                        // Otherwise we know they are disconnected
                        1;
                    // Disconnected nodes
                    if (compare & 1 ||
                        (!support.sortDetached && b.compareDocumentPosition(a) === compare)) {
                        // Choose the first element that is related to our preferred document
                        if (a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a)) {
                            return -1;
                        }
                        if (b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b)) {
                            return 1;
                        }
                        // Maintain original order
                        return sortInput ?
                            (indexOf(sortInput, a) - indexOf(sortInput, b)) :
                            0;
                    }
                    return compare & 4 ? -1 : 1;
                } :
                function (a, b) {
                    // Exit early if the nodes are identical
                    if (a === b) {
                        hasDuplicate = true;
                        return 0;
                    }
                    var cur, i = 0, aup = a.parentNode, bup = b.parentNode, ap = [a], bp = [b];
                    // Parentless nodes are either documents or disconnected
                    if (!aup || !bup) {
                        return a === document ? -1 :
                            b === document ? 1 :
                                aup ? -1 :
                                    bup ? 1 :
                                        sortInput ?
                                            (indexOf(sortInput, a) - indexOf(sortInput, b)) :
                                            0;
                    }
                    else if (aup === bup) {
                        return siblingCheck(a, b);
                    }
                    // Otherwise we need full lists of their ancestors for comparison
                    cur = a;
                    while ((cur = cur.parentNode)) {
                        ap.unshift(cur);
                    }
                    cur = b;
                    while ((cur = cur.parentNode)) {
                        bp.unshift(cur);
                    }
                    // Walk down the tree looking for a discrepancy
                    while (ap[i] === bp[i]) {
                        i++;
                    }
                    return i ?
                        // Do a sibling check if the nodes have a common ancestor
                        siblingCheck(ap[i], bp[i]) :
                        // Otherwise nodes in our document sort first
                        ap[i] === preferredDoc ? -1 :
                            bp[i] === preferredDoc ? 1 :
                                0;
                };
            return document;
        };
        Sizzle.matches = function (expr, elements) {
            return Sizzle(expr, null, null, elements);
        };
        Sizzle.matchesSelector = function (elem, expr) {
            // Set document vars if needed
            if ((elem.ownerDocument || elem) !== document) {
                setDocument(elem);
            }
            // Make sure that attribute selectors are quoted
            expr = expr.replace(rattributeQuotes, "='$1']");
            if (support.matchesSelector && documentIsHTML &&
                !compilerCache[expr + " "] &&
                (!rbuggyMatches || !rbuggyMatches.test(expr)) &&
                (!rbuggyQSA || !rbuggyQSA.test(expr))) {
                try {
                    var ret = matches.call(elem, expr);
                    // IE 9's matchesSelector returns false on disconnected nodes
                    if (ret || support.disconnectedMatch ||
                        // As well, disconnected nodes are said to be in a document
                        // fragment in IE 9
                        elem.document && elem.document.nodeType !== 11) {
                        return ret;
                    }
                }
                catch (e) { }
            }
            return Sizzle(expr, document, null, [elem]).length > 0;
        };
        Sizzle.contains = function (context, elem) {
            // Set document vars if needed
            if ((context.ownerDocument || context) !== document) {
                setDocument(context);
            }
            return contains(context, elem);
        };
        Sizzle.attr = function (elem, name) {
            // Set document vars if needed
            if ((elem.ownerDocument || elem) !== document) {
                setDocument(elem);
            }
            var fn = Expr.attrHandle[name.toLowerCase()], 
            // Don't get fooled by Object.prototype properties (jQuery #13807)
            val = fn && hasOwn.call(Expr.attrHandle, name.toLowerCase()) ?
                fn(elem, name, !documentIsHTML) :
                undefined;
            return val !== undefined ?
                val :
                support.attributes || !documentIsHTML ?
                    elem.getAttribute(name) :
                    (val = elem.getAttributeNode(name)) && val.specified ?
                        val.value :
                        null;
        };
        Sizzle.escape = function (sel) {
            return (sel + "").replace(rcssescape, fcssescape);
        };
        Sizzle.error = function (msg) {
            throw new Error("Syntax error, unrecognized expression: " + msg);
        };
        /**
         * Document sorting and removing duplicates
         * @param {ArrayLike} results
         */
        Sizzle.uniqueSort = function (results) {
            var elem, duplicates = [], j = 0, i = 0;
            // Unless we *know* we can detect duplicates, assume their presence
            hasDuplicate = !support.detectDuplicates;
            sortInput = !support.sortStable && results.slice(0);
            results.sort(sortOrder);
            if (hasDuplicate) {
                while ((elem = results[i++])) {
                    if (elem === results[i]) {
                        j = duplicates.push(i);
                    }
                }
                while (j--) {
                    results.splice(duplicates[j], 1);
                }
            }
            // Clear input after sorting to release objects
            // See https://github.com/jquery/sizzle/pull/225
            sortInput = null;
            return results;
        };
        /**
         * Utility function for retrieving the text value of an array of DOM nodes
         * @param {Array|Element} elem
         */
        getText = Sizzle.getText = function (elem) {
            var node, ret = "", i = 0, nodeType = elem.nodeType;
            if (!nodeType) {
                // If no nodeType, this is expected to be an array
                while ((node = elem[i++])) {
                    // Do not traverse comment nodes
                    ret += getText(node);
                }
            }
            else if (nodeType === 1 || nodeType === 9 || nodeType === 11) {
                // Use textContent for elements
                // innerText usage removed for consistency of new lines (jQuery #11153)
                if (typeof elem.textContent === "string") {
                    return elem.textContent;
                }
                else {
                    // Traverse its children
                    for (elem = elem.firstChild; elem; elem = elem.nextSibling) {
                        ret += getText(elem);
                    }
                }
            }
            else if (nodeType === 3 || nodeType === 4) {
                return elem.nodeValue;
            }
            // Do not include comment or processing instruction nodes
            return ret;
        };
        Expr = Sizzle.selectors = {
            // Can be adjusted by the user
            cacheLength: 50,
            createPseudo: markFunction,
            match: matchExpr,
            attrHandle: {},
            find: {},
            relative: {
                ">": { dir: "parentNode", first: true },
                " ": { dir: "parentNode" },
                "+": { dir: "previousSibling", first: true },
                "~": { dir: "previousSibling" }
            },
            preFilter: {
                "ATTR": function (match) {
                    match[1] = match[1].replace(runescape, funescape);
                    // Move the given value to match[3] whether quoted or unquoted
                    match[3] = (match[3] || match[4] || match[5] || "").replace(runescape, funescape);
                    if (match[2] === "~=") {
                        match[3] = " " + match[3] + " ";
                    }
                    return match.slice(0, 4);
                },
                "CHILD": function (match) {
                    /* matches from matchExpr["CHILD"]
                        1 type (only|nth|...)
                        2 what (child|of-type)
                        3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
                        4 xn-component of xn+y argument ([+-]?\d*n|)
                        5 sign of xn-component
                        6 x of xn-component
                        7 sign of y-component
                        8 y of y-component
                    */
                    match[1] = match[1].toLowerCase();
                    if (match[1].slice(0, 3) === "nth") {
                        // nth-* requires argument
                        if (!match[3]) {
                            Sizzle.error(match[0]);
                        }
                        // numeric x and y parameters for Expr.filter.CHILD
                        // remember that false/true cast respectively to 0/1
                        match[4] = +(match[4] ? match[5] + (match[6] || 1) : 2 * (match[3] === "even" || match[3] === "odd"));
                        match[5] = +((match[7] + match[8]) || match[3] === "odd");
                    }
                    else if (match[3]) {
                        Sizzle.error(match[0]);
                    }
                    return match;
                },
                "PSEUDO": function (match) {
                    var excess, unquoted = !match[6] && match[2];
                    if (matchExpr["CHILD"].test(match[0])) {
                        return null;
                    }
                    // Accept quoted arguments as-is
                    if (match[3]) {
                        match[2] = match[4] || match[5] || "";
                    }
                    else if (unquoted && rpseudo.test(unquoted) &&
                        // Get excess from tokenize (recursively)
                        (excess = tokenize(unquoted, true)) &&
                        // advance to the next closing parenthesis
                        (excess = unquoted.indexOf(")", unquoted.length - excess) - unquoted.length)) {
                        // excess is a negative index
                        match[0] = match[0].slice(0, excess);
                        match[2] = unquoted.slice(0, excess);
                    }
                    // Return only captures needed by the pseudo filter method (type and argument)
                    return match.slice(0, 3);
                }
            },
            filter: {
                "TAG": function (nodeNameSelector) {
                    var nodeName = nodeNameSelector.replace(runescape, funescape).toLowerCase();
                    return nodeNameSelector === "*" ?
                        function () { return true; } :
                        function (elem) {
                            return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
                        };
                },
                "CLASS": function (className) {
                    var pattern = classCache[className + " "];
                    return pattern ||
                        (pattern = new RegExp("(^|" + whitespace + ")" + className + "(" + whitespace + "|$)")) &&
                            classCache(className, function (elem) {
                                return pattern.test(typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "");
                            });
                },
                "ATTR": function (name, operator, check) {
                    return function (elem) {
                        var result = Sizzle.attr(elem, name);
                        if (result == null) {
                            return operator === "!=";
                        }
                        if (!operator) {
                            return true;
                        }
                        result += "";
                        return operator === "=" ? result === check :
                            operator === "!=" ? result !== check :
                                operator === "^=" ? check && result.indexOf(check) === 0 :
                                    operator === "*=" ? check && result.indexOf(check) > -1 :
                                        operator === "$=" ? check && result.slice(-check.length) === check :
                                            operator === "~=" ? (" " + result.replace(rwhitespace, " ") + " ").indexOf(check) > -1 :
                                                operator === "|=" ? result === check || result.slice(0, check.length + 1) === check + "-" :
                                                    false;
                    };
                },
                "CHILD": function (type, what, argument, first, last) {
                    var simple = type.slice(0, 3) !== "nth", forward = type.slice(-4) !== "last", ofType = what === "of-type";
                    return first === 1 && last === 0 ?
                        // Shortcut for :nth-*(n)
                        function (elem) {
                            return !!elem.parentNode;
                        } :
                        function (elem, context, xml) {
                            var cache, uniqueCache, outerCache, node, nodeIndex, start, dir = simple !== forward ? "nextSibling" : "previousSibling", parent = elem.parentNode, name = ofType && elem.nodeName.toLowerCase(), useCache = !xml && !ofType, diff = false;
                            if (parent) {
                                // :(first|last|only)-(child|of-type)
                                if (simple) {
                                    while (dir) {
                                        node = elem;
                                        while ((node = node[dir])) {
                                            if (ofType ?
                                                node.nodeName.toLowerCase() === name :
                                                node.nodeType === 1) {
                                                return false;
                                            }
                                        }
                                        // Reverse direction for :only-* (if we haven't yet done so)
                                        start = dir = type === "only" && !start && "nextSibling";
                                    }
                                    return true;
                                }
                                start = [forward ? parent.firstChild : parent.lastChild];
                                // non-xml :nth-child(...) stores cache data on `parent`
                                if (forward && useCache) {
                                    // Seek `elem` from a previously-cached index
                                    // ...in a gzip-friendly way
                                    node = parent;
                                    outerCache = node[expando] || (node[expando] = {});
                                    // Support: IE <9 only
                                    // Defend against cloned attroperties (jQuery gh-1709)
                                    uniqueCache = outerCache[node.uniqueID] ||
                                        (outerCache[node.uniqueID] = {});
                                    cache = uniqueCache[type] || [];
                                    nodeIndex = cache[0] === dirruns && cache[1];
                                    diff = nodeIndex && cache[2];
                                    node = nodeIndex && parent.childNodes[nodeIndex];
                                    while ((node = ++nodeIndex && node && node[dir] ||
                                        // Fallback to seeking `elem` from the start
                                        (diff = nodeIndex = 0) || start.pop())) {
                                        // When found, cache indexes on `parent` and break
                                        if (node.nodeType === 1 && ++diff && node === elem) {
                                            uniqueCache[type] = [dirruns, nodeIndex, diff];
                                            break;
                                        }
                                    }
                                }
                                else {
                                    // Use previously-cached element index if available
                                    if (useCache) {
                                        // ...in a gzip-friendly way
                                        node = elem;
                                        outerCache = node[expando] || (node[expando] = {});
                                        // Support: IE <9 only
                                        // Defend against cloned attroperties (jQuery gh-1709)
                                        uniqueCache = outerCache[node.uniqueID] ||
                                            (outerCache[node.uniqueID] = {});
                                        cache = uniqueCache[type] || [];
                                        nodeIndex = cache[0] === dirruns && cache[1];
                                        diff = nodeIndex;
                                    }
                                    // xml :nth-child(...)
                                    // or :nth-last-child(...) or :nth(-last)?-of-type(...)
                                    if (diff === false) {
                                        // Use the same loop as above to seek `elem` from the start
                                        while ((node = ++nodeIndex && node && node[dir] ||
                                            (diff = nodeIndex = 0) || start.pop())) {
                                            if ((ofType ?
                                                node.nodeName.toLowerCase() === name :
                                                node.nodeType === 1) &&
                                                ++diff) {
                                                // Cache the index of each encountered element
                                                if (useCache) {
                                                    outerCache = node[expando] || (node[expando] = {});
                                                    // Support: IE <9 only
                                                    // Defend against cloned attroperties (jQuery gh-1709)
                                                    uniqueCache = outerCache[node.uniqueID] ||
                                                        (outerCache[node.uniqueID] = {});
                                                    uniqueCache[type] = [dirruns, diff];
                                                }
                                                if (node === elem) {
                                                    break;
                                                }
                                            }
                                        }
                                    }
                                }
                                // Incorporate the offset, then check against cycle size
                                diff -= last;
                                return diff === first || (diff % first === 0 && diff / first >= 0);
                            }
                        };
                },
                "PSEUDO": function (pseudo, argument) {
                    // pseudo-class names are case-insensitive
                    // http://www.w3.org/TR/selectors/#pseudo-classes
                    // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
                    // Remember that setFilters inherits from pseudos
                    var args, fn = Expr.pseudos[pseudo] || Expr.setFilters[pseudo.toLowerCase()] ||
                        Sizzle.error("unsupported pseudo: " + pseudo);
                    // The user may use createPseudo to indicate that
                    // arguments are needed to create the filter function
                    // just as Sizzle does
                    if (fn[expando]) {
                        return fn(argument);
                    }
                    // But maintain support for old signatures
                    if (fn.length > 1) {
                        args = [pseudo, pseudo, "", argument];
                        return Expr.setFilters.hasOwnProperty(pseudo.toLowerCase()) ?
                            markFunction(function (seed, matches) {
                                var idx, matched = fn(seed, argument), i = matched.length;
                                while (i--) {
                                    idx = indexOf(seed, matched[i]);
                                    seed[idx] = !(matches[idx] = matched[i]);
                                }
                            }) :
                            function (elem) {
                                return fn(elem, 0, args);
                            };
                    }
                    return fn;
                }
            },
            pseudos: {
                // Potentially complex pseudos
                "not": markFunction(function (selector) {
                    // Trim the selector passed to compile
                    // to avoid treating leading and trailing
                    // spaces as combinators
                    var input = [], results = [], matcher = compile(selector.replace(rtrim, "$1"));
                    return matcher[expando] ?
                        markFunction(function (seed, matches, context, xml) {
                            var elem, unmatched = matcher(seed, null, xml, []), i = seed.length;
                            // Match elements unmatched by `matcher`
                            while (i--) {
                                if ((elem = unmatched[i])) {
                                    seed[i] = !(matches[i] = elem);
                                }
                            }
                        }) :
                        function (elem, context, xml) {
                            input[0] = elem;
                            matcher(input, null, xml, results);
                            // Don't keep the element (issue #299)
                            input[0] = null;
                            return !results.pop();
                        };
                }),
                "has": markFunction(function (selector) {
                    return function (elem) {
                        return Sizzle(selector, elem).length > 0;
                    };
                }),
                "contains": markFunction(function (text) {
                    text = text.replace(runescape, funescape);
                    return function (elem) {
                        return (elem.textContent || elem.innerText || getText(elem)).indexOf(text) > -1;
                    };
                }),
                // "Whether an element is represented by a :lang() selector
                // is based solely on the element's language value
                // being equal to the identifier C,
                // or beginning with the identifier C immediately followed by "-".
                // The matching of C against the element's language value is performed case-insensitively.
                // The identifier C does not have to be a valid language name."
                // http://www.w3.org/TR/selectors/#lang-pseudo
                "lang": markFunction(function (lang) {
                    // lang value must be a valid identifier
                    if (!ridentifier.test(lang || "")) {
                        Sizzle.error("unsupported lang: " + lang);
                    }
                    lang = lang.replace(runescape, funescape).toLowerCase();
                    return function (elem) {
                        var elemLang;
                        do {
                            if ((elemLang = documentIsHTML ?
                                elem.lang :
                                elem.getAttribute("xml:lang") || elem.getAttribute("lang"))) {
                                elemLang = elemLang.toLowerCase();
                                return elemLang === lang || elemLang.indexOf(lang + "-") === 0;
                            }
                        } while ((elem = elem.parentNode) && elem.nodeType === 1);
                        return false;
                    };
                }),
                // Miscellaneous
                "target": function (elem) {
                    var hash = window.location && window.location.hash;
                    return hash && hash.slice(1) === elem.id;
                },
                "root": function (elem) {
                    return elem === docElem;
                },
                "focus": function (elem) {
                    return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
                },
                // Boolean properties
                "enabled": createDisabledPseudo(false),
                "disabled": createDisabledPseudo(true),
                "checked": function (elem) {
                    // In CSS3, :checked should return both checked and selected elements
                    // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
                    var nodeName = elem.nodeName.toLowerCase();
                    return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
                },
                "selected": function (elem) {
                    // Accessing this property makes selected-by-default
                    // options in Safari work properly
                    if (elem.parentNode) {
                        elem.parentNode.selectedIndex;
                    }
                    return elem.selected === true;
                },
                // Contents
                "empty": function (elem) {
                    // http://www.w3.org/TR/selectors/#empty-pseudo
                    // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),
                    //   but not by others (comment: 8; processing instruction: 7; etc.)
                    // nodeType < 6 works because attributes (2) do not appear as children
                    for (elem = elem.firstChild; elem; elem = elem.nextSibling) {
                        if (elem.nodeType < 6) {
                            return false;
                        }
                    }
                    return true;
                },
                "parent": function (elem) {
                    return !Expr.pseudos["empty"](elem);
                },
                // Element/input types
                "header": function (elem) {
                    return rheader.test(elem.nodeName);
                },
                "input": function (elem) {
                    return rinputs.test(elem.nodeName);
                },
                "button": function (elem) {
                    var name = elem.nodeName.toLowerCase();
                    return name === "input" && elem.type === "button" || name === "button";
                },
                "text": function (elem) {
                    var attr;
                    return elem.nodeName.toLowerCase() === "input" &&
                        elem.type === "text" &&
                        // Support: IE<8
                        // New HTML5 attribute values (e.g., "search") appear with elem.type === "text"
                        ((attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text");
                },
                // Position-in-collection
                "first": createPositionalPseudo(function () {
                    return [0];
                }),
                "last": createPositionalPseudo(function (matchIndexes, length) {
                    return [length - 1];
                }),
                "eq": createPositionalPseudo(function (matchIndexes, length, argument) {
                    return [argument < 0 ? argument + length : argument];
                }),
                "even": createPositionalPseudo(function (matchIndexes, length) {
                    var i = 0;
                    for (; i < length; i += 2) {
                        matchIndexes.push(i);
                    }
                    return matchIndexes;
                }),
                "odd": createPositionalPseudo(function (matchIndexes, length) {
                    var i = 1;
                    for (; i < length; i += 2) {
                        matchIndexes.push(i);
                    }
                    return matchIndexes;
                }),
                "lt": createPositionalPseudo(function (matchIndexes, length, argument) {
                    var i = argument < 0 ? argument + length : argument;
                    for (; --i >= 0;) {
                        matchIndexes.push(i);
                    }
                    return matchIndexes;
                }),
                "gt": createPositionalPseudo(function (matchIndexes, length, argument) {
                    var i = argument < 0 ? argument + length : argument;
                    for (; ++i < length;) {
                        matchIndexes.push(i);
                    }
                    return matchIndexes;
                })
            }
        };
        Expr.pseudos["nth"] = Expr.pseudos["eq"];
        // Add button/input type pseudos
        for (i in { radio: true, checkbox: true, file: true, password: true, image: true }) {
            Expr.pseudos[i] = createInputPseudo(i);
        }
        for (i in { submit: true, reset: true }) {
            Expr.pseudos[i] = createButtonPseudo(i);
        }
        // Easy API for creating new setFilters
        function setFilters() { }
        setFilters.prototype = Expr.filters = Expr.pseudos;
        Expr.setFilters = new setFilters();
        tokenize = Sizzle.tokenize = function (selector, parseOnly) {
            var matched, match, tokens, type, soFar, groups, preFilters, cached = tokenCache[selector + " "];
            if (cached) {
                return parseOnly ? 0 : cached.slice(0);
            }
            soFar = selector;
            groups = [];
            preFilters = Expr.preFilter;
            while (soFar) {
                // Comma and first run
                if (!matched || (match = rcomma.exec(soFar))) {
                    if (match) {
                        // Don't consume trailing commas as valid
                        soFar = soFar.slice(match[0].length) || soFar;
                    }
                    groups.push((tokens = []));
                }
                matched = false;
                // Combinators
                if ((match = rcombinators.exec(soFar))) {
                    matched = match.shift();
                    tokens.push({
                        value: matched,
                        // Cast descendant combinators to space
                        type: match[0].replace(rtrim, " ")
                    });
                    soFar = soFar.slice(matched.length);
                }
                // Filters
                for (type in Expr.filter) {
                    if ((match = matchExpr[type].exec(soFar)) && (!preFilters[type] ||
                        (match = preFilters[type](match)))) {
                        matched = match.shift();
                        tokens.push({
                            value: matched,
                            type: type,
                            matches: match
                        });
                        soFar = soFar.slice(matched.length);
                    }
                }
                if (!matched) {
                    break;
                }
            }
            // Return the length of the invalid excess
            // if we're just parsing
            // Otherwise, throw an error or return tokens
            return parseOnly ?
                soFar.length :
                soFar ?
                    Sizzle.error(selector) :
                    // Cache the tokens
                    tokenCache(selector, groups).slice(0);
        };
        function toSelector(tokens) {
            var i = 0, len = tokens.length, selector = "";
            for (; i < len; i++) {
                selector += tokens[i].value;
            }
            return selector;
        }
        function addCombinator(matcher, combinator, base) {
            var dir = combinator.dir, skip = combinator.next, key = skip || dir, checkNonElements = base && key === "parentNode", doneName = done++;
            return combinator.first ?
                // Check against closest ancestor/preceding element
                function (elem, context, xml) {
                    while ((elem = elem[dir])) {
                        if (elem.nodeType === 1 || checkNonElements) {
                            return matcher(elem, context, xml);
                        }
                    }
                    return false;
                } :
                // Check against all ancestor/preceding elements
                function (elem, context, xml) {
                    var oldCache, uniqueCache, outerCache, newCache = [dirruns, doneName];
                    // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching
                    if (xml) {
                        while ((elem = elem[dir])) {
                            if (elem.nodeType === 1 || checkNonElements) {
                                if (matcher(elem, context, xml)) {
                                    return true;
                                }
                            }
                        }
                    }
                    else {
                        while ((elem = elem[dir])) {
                            if (elem.nodeType === 1 || checkNonElements) {
                                outerCache = elem[expando] || (elem[expando] = {});
                                // Support: IE <9 only
                                // Defend against cloned attroperties (jQuery gh-1709)
                                uniqueCache = outerCache[elem.uniqueID] || (outerCache[elem.uniqueID] = {});
                                if (skip && skip === elem.nodeName.toLowerCase()) {
                                    elem = elem[dir] || elem;
                                }
                                else if ((oldCache = uniqueCache[key]) &&
                                    oldCache[0] === dirruns && oldCache[1] === doneName) {
                                    // Assign to newCache so results back-propagate to previous elements
                                    return (newCache[2] = oldCache[2]);
                                }
                                else {
                                    // Reuse newcache so results back-propagate to previous elements
                                    uniqueCache[key] = newCache;
                                    // A match means we're done; a fail means we have to keep checking
                                    if ((newCache[2] = matcher(elem, context, xml))) {
                                        return true;
                                    }
                                }
                            }
                        }
                    }
                    return false;
                };
        }
        function elementMatcher(matchers) {
            return matchers.length > 1 ?
                function (elem, context, xml) {
                    var i = matchers.length;
                    while (i--) {
                        if (!matchers[i](elem, context, xml)) {
                            return false;
                        }
                    }
                    return true;
                } :
                matchers[0];
        }
        function multipleContexts(selector, contexts, results) {
            var i = 0, len = contexts.length;
            for (; i < len; i++) {
                Sizzle(selector, contexts[i], results);
            }
            return results;
        }
        function condense(unmatched, map, filter, context, xml) {
            var elem, newUnmatched = [], i = 0, len = unmatched.length, mapped = map != null;
            for (; i < len; i++) {
                if ((elem = unmatched[i])) {
                    if (!filter || filter(elem, context, xml)) {
                        newUnmatched.push(elem);
                        if (mapped) {
                            map.push(i);
                        }
                    }
                }
            }
            return newUnmatched;
        }
        function setMatcher(preFilter, selector, matcher, postFilter, postFinder, postSelector) {
            if (postFilter && !postFilter[expando]) {
                postFilter = setMatcher(postFilter);
            }
            if (postFinder && !postFinder[expando]) {
                postFinder = setMatcher(postFinder, postSelector);
            }
            return markFunction(function (seed, results, context, xml) {
                var temp, i, elem, preMap = [], postMap = [], preexisting = results.length, 
                // Get initial elements from seed or context
                elems = seed || multipleContexts(selector || "*", context.nodeType ? [context] : context, []), 
                // Prefilter to get matcher input, preserving a map for seed-results synchronization
                matcherIn = preFilter && (seed || !selector) ?
                    condense(elems, preMap, preFilter, context, xml) :
                    elems, matcherOut = matcher ?
                    // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
                    postFinder || (seed ? preFilter : preexisting || postFilter) ?
                        // ...intermediate processing is necessary
                        [] :
                        // ...otherwise use results directly
                        results :
                    matcherIn;
                // Find primary matches
                if (matcher) {
                    matcher(matcherIn, matcherOut, context, xml);
                }
                // Apply postFilter
                if (postFilter) {
                    temp = condense(matcherOut, postMap);
                    postFilter(temp, [], context, xml);
                    // Un-match failing elements by moving them back to matcherIn
                    i = temp.length;
                    while (i--) {
                        if ((elem = temp[i])) {
                            matcherOut[postMap[i]] = !(matcherIn[postMap[i]] = elem);
                        }
                    }
                }
                if (seed) {
                    if (postFinder || preFilter) {
                        if (postFinder) {
                            // Get the final matcherOut by condensing this intermediate into postFinder contexts
                            temp = [];
                            i = matcherOut.length;
                            while (i--) {
                                if ((elem = matcherOut[i])) {
                                    // Restore matcherIn since elem is not yet a final match
                                    temp.push((matcherIn[i] = elem));
                                }
                            }
                            postFinder(null, (matcherOut = []), temp, xml);
                        }
                        // Move matched elements from seed to results to keep them synchronized
                        i = matcherOut.length;
                        while (i--) {
                            if ((elem = matcherOut[i]) &&
                                (temp = postFinder ? indexOf(seed, elem) : preMap[i]) > -1) {
                                seed[temp] = !(results[temp] = elem);
                            }
                        }
                    }
                }
                else {
                    matcherOut = condense(matcherOut === results ?
                        matcherOut.splice(preexisting, matcherOut.length) :
                        matcherOut);
                    if (postFinder) {
                        postFinder(null, results, matcherOut, xml);
                    }
                    else {
                        push.apply(results, matcherOut);
                    }
                }
            });
        }
        function matcherFromTokens(tokens) {
            var checkContext, matcher, j, len = tokens.length, leadingRelative = Expr.relative[tokens[0].type], implicitRelative = leadingRelative || Expr.relative[" "], i = leadingRelative ? 1 : 0, 
            // The foundational matcher ensures that elements are reachable from top-level context(s)
            matchContext = addCombinator(function (elem) {
                return elem === checkContext;
            }, implicitRelative, true), matchAnyContext = addCombinator(function (elem) {
                return indexOf(checkContext, elem) > -1;
            }, implicitRelative, true), matchers = [function (elem, context, xml) {
                    var ret = (!leadingRelative && (xml || context !== outermostContext)) || ((checkContext = context).nodeType ?
                        matchContext(elem, context, xml) :
                        matchAnyContext(elem, context, xml));
                    // Avoid hanging onto element (issue #299)
                    checkContext = null;
                    return ret;
                }];
            for (; i < len; i++) {
                if ((matcher = Expr.relative[tokens[i].type])) {
                    matchers = [addCombinator(elementMatcher(matchers), matcher)];
                }
                else {
                    matcher = Expr.filter[tokens[i].type].apply(null, tokens[i].matches);
                    // Return special upon seeing a positional matcher
                    if (matcher[expando]) {
                        // Find the next relative operator (if any) for proper handling
                        j = ++i;
                        for (; j < len; j++) {
                            if (Expr.relative[tokens[j].type]) {
                                break;
                            }
                        }
                        return setMatcher(i > 1 && elementMatcher(matchers), i > 1 && toSelector(
                        // If the preceding token was a descendant combinator, insert an implicit any-element `*`
                        tokens.slice(0, i - 1).concat({ value: tokens[i - 2].type === " " ? "*" : "" })).replace(rtrim, "$1"), matcher, i < j && matcherFromTokens(tokens.slice(i, j)), j < len && matcherFromTokens((tokens = tokens.slice(j))), j < len && toSelector(tokens));
                    }
                    matchers.push(matcher);
                }
            }
            return elementMatcher(matchers);
        }
        function matcherFromGroupMatchers(elementMatchers, setMatchers) {
            var bySet = setMatchers.length > 0, byElement = elementMatchers.length > 0, superMatcher = function (seed, context, xml, results, outermost) {
                var elem, j, matcher, matchedCount = 0, i = "0", unmatched = seed && [], setMatched = [], contextBackup = outermostContext, 
                // We must always have either seed elements or outermost context
                elems = seed || byElement && Expr.find["TAG"]("*", outermost), 
                // Use integer dirruns iff this is the outermost matcher
                dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1), len = elems.length;
                if (outermost) {
                    outermostContext = context === document || context || outermost;
                }
                // Add elements passing elementMatchers directly to results
                // Support: IE<9, Safari
                // Tolerate NodeList properties (IE: "length"; Safari: <number>) matching elements by id
                for (; i !== len && (elem = elems[i]) != null; i++) {
                    if (byElement && elem) {
                        j = 0;
                        if (!context && elem.ownerDocument !== document) {
                            setDocument(elem);
                            xml = !documentIsHTML;
                        }
                        while ((matcher = elementMatchers[j++])) {
                            if (matcher(elem, context || document, xml)) {
                                results.push(elem);
                                break;
                            }
                        }
                        if (outermost) {
                            dirruns = dirrunsUnique;
                        }
                    }
                    // Track unmatched elements for set filters
                    if (bySet) {
                        // They will have gone through all possible matchers
                        if ((elem = !matcher && elem)) {
                            matchedCount--;
                        }
                        // Lengthen the array for every element, matched or not
                        if (seed) {
                            unmatched.push(elem);
                        }
                    }
                }
                // `i` is now the count of elements visited above, and adding it to `matchedCount`
                // makes the latter nonnegative.
                matchedCount += i;
                // Apply set filters to unmatched elements
                // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount`
                // equals `i`), unless we didn't visit _any_ elements in the above loop because we have
                // no element matchers and no seed.
                // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that
                // case, which will result in a "00" `matchedCount` that differs from `i` but is also
                // numerically zero.
                if (bySet && i !== matchedCount) {
                    j = 0;
                    while ((matcher = setMatchers[j++])) {
                        matcher(unmatched, setMatched, context, xml);
                    }
                    if (seed) {
                        // Reintegrate element matches to eliminate the need for sorting
                        if (matchedCount > 0) {
                            while (i--) {
                                if (!(unmatched[i] || setMatched[i])) {
                                    setMatched[i] = pop.call(results);
                                }
                            }
                        }
                        // Discard index placeholder values to get only actual matches
                        setMatched = condense(setMatched);
                    }
                    // Add matches to results
                    push.apply(results, setMatched);
                    // Seedless set matches succeeding multiple successful matchers stipulate sorting
                    if (outermost && !seed && setMatched.length > 0 &&
                        (matchedCount + setMatchers.length) > 1) {
                        Sizzle.uniqueSort(results);
                    }
                }
                // Override manipulation of globals by nested matchers
                if (outermost) {
                    dirruns = dirrunsUnique;
                    outermostContext = contextBackup;
                }
                return unmatched;
            };
            return bySet ?
                markFunction(superMatcher) :
                superMatcher;
        }
        compile = Sizzle.compile = function (selector, match /* Internal Use Only */) {
            var i, setMatchers = [], elementMatchers = [], cached = compilerCache[selector + " "];
            if (!cached) {
                // Generate a function of recursive functions that can be used to check each element
                if (!match) {
                    match = tokenize(selector);
                }
                i = match.length;
                while (i--) {
                    cached = matcherFromTokens(match[i]);
                    if (cached[expando]) {
                        setMatchers.push(cached);
                    }
                    else {
                        elementMatchers.push(cached);
                    }
                }
                // Cache the compiled function
                cached = compilerCache(selector, matcherFromGroupMatchers(elementMatchers, setMatchers));
                // Save selector and tokenization
                cached.selector = selector;
            }
            return cached;
        };
        /**
         * A low-level selection function that works with Sizzle's compiled
         *  selector functions
         * @param {String|Function} selector A selector or a pre-compiled
         *  selector function built with Sizzle.compile
         * @param {Element} context
         * @param {Array} [results]
         * @param {Array} [seed] A set of elements to match against
         */
        select = Sizzle.select = function (selector, context, results, seed) {
            var i, tokens, token, type, find, compiled = typeof selector === "function" && selector, match = !seed && tokenize((selector = compiled.selector || selector));
            results = results || [];
            // Try to minimize operations if there is only one selector in the list and no seed
            // (the latter of which guarantees us context)
            if (match.length === 1) {
                // Reduce context if the leading compound selector is an ID
                tokens = match[0] = match[0].slice(0);
                if (tokens.length > 2 && (token = tokens[0]).type === "ID" &&
                    context.nodeType === 9 && documentIsHTML && Expr.relative[tokens[1].type]) {
                    context = (Expr.find["ID"](token.matches[0].replace(runescape, funescape), context) || [])[0];
                    if (!context) {
                        return results;
                    }
                    else if (compiled) {
                        context = context.parentNode;
                    }
                    selector = selector.slice(tokens.shift().value.length);
                }
                // Fetch a seed set for right-to-left matching
                i = matchExpr["needsContext"].test(selector) ? 0 : tokens.length;
                while (i--) {
                    token = tokens[i];
                    // Abort if we hit a combinator
                    if (Expr.relative[(type = token.type)]) {
                        break;
                    }
                    if ((find = Expr.find[type])) {
                        // Search, expanding context for leading sibling combinators
                        if ((seed = find(token.matches[0].replace(runescape, funescape), rsibling.test(tokens[0].type) && testContext(context.parentNode) || context))) {
                            // If seed is empty or no tokens remain, we can return early
                            tokens.splice(i, 1);
                            selector = seed.length && toSelector(tokens);
                            if (!selector) {
                                push.apply(results, seed);
                                return results;
                            }
                            break;
                        }
                    }
                }
            }
            // Compile and execute a filtering function if one is not provided
            // Provide `match` to avoid retokenization if we modified the selector above
            (compiled || compile(selector, match))(seed, context, !documentIsHTML, results, !context || rsibling.test(selector) && testContext(context.parentNode) || context);
            return results;
        };
        // One-time assignments
        // Sort stability
        support.sortStable = expando.split("").sort(sortOrder).join("") === expando;
        // Support: Chrome 14-35+
        // Always assume duplicates if they aren't passed to the comparison function
        support.detectDuplicates = !!hasDuplicate;
        // Initialize against the default document
        setDocument();
        // Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)
        // Detached nodes confoundingly follow *each other*
        support.sortDetached = assert(function (el) {
            // Should return 1, but returns 4 (following)
            return el.compareDocumentPosition(document.createElement("fieldset")) & 1;
        });
        // Support: IE<8
        // Prevent attribute/property "interpolation"
        // https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
        if (!assert(function (el) {
            el.innerHTML = "<a href='#'></a>";
            return el.firstChild.getAttribute("href") === "#";
        })) {
            addHandle("type|href|height|width", function (elem, name, isXML) {
                if (!isXML) {
                    return elem.getAttribute(name, name.toLowerCase() === "type" ? 1 : 2);
                }
            });
        }
        // Support: IE<9
        // Use defaultValue in place of getAttribute("value")
        if (!support.attributes || !assert(function (el) {
            el.innerHTML = "<input/>";
            el.firstChild.setAttribute("value", "");
            return el.firstChild.getAttribute("value") === "";
        })) {
            addHandle("value", function (elem, name, isXML) {
                if (!isXML && elem.nodeName.toLowerCase() === "input") {
                    return elem.defaultValue;
                }
            });
        }
        // Support: IE<9
        // Use getAttributeNode to fetch booleans when getAttribute lies
        if (!assert(function (el) {
            return el.getAttribute("disabled") == null;
        })) {
            addHandle(booleans, function (elem, name, isXML) {
                var val;
                if (!isXML) {
                    return elem[name] === true ? name.toLowerCase() :
                        (val = elem.getAttributeNode(name)) && val.specified ?
                            val.value :
                            null;
                }
            });
        }
        return Sizzle;
    })(window);
    jQuery.find = Sizzle;
    jQuery.expr = Sizzle.selectors;
    // Deprecated
    jQuery.expr[":"] = jQuery.expr.pseudos;
    jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort;
    jQuery.text = Sizzle.getText;
    jQuery.isXMLDoc = Sizzle.isXML;
    jQuery.contains = Sizzle.contains;
    jQuery.escapeSelector = Sizzle.escape;
    var dir = function (elem, dir, until) {
        var matched = [], truncate = until !== undefined;
        while ((elem = elem[dir]) && elem.nodeType !== 9) {
            if (elem.nodeType === 1) {
                if (truncate && jQuery(elem).is(until)) {
                    break;
                }
                matched.push(elem);
            }
        }
        return matched;
    };
    var siblings = function (n, elem) {
        var matched = [];
        for (; n; n = n.nextSibling) {
            if (n.nodeType === 1 && n !== elem) {
                matched.push(n);
            }
        }
        return matched;
    };
    var rneedsContext = jQuery.expr.match.needsContext;
    var rsingleTag = (/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i);
    var risSimple = /^.[^:#\[\.,]*$/;
    // Implement the identical functionality for filter and not
    function winnow(elements, qualifier, not) {
        if (jQuery.isFunction(qualifier)) {
            return jQuery.grep(elements, function (elem, i) {
                return !!qualifier.call(elem, i, elem) !== not;
            });
        }
        // Single element
        if (qualifier.nodeType) {
            return jQuery.grep(elements, function (elem) {
                return (elem === qualifier) !== not;
            });
        }
        // Arraylike of elements (jQuery, arguments, Array)
        if (typeof qualifier !== "string") {
            return jQuery.grep(elements, function (elem) {
                return (indexOf.call(qualifier, elem) > -1) !== not;
            });
        }
        // Simple selector that can be filtered directly, removing non-Elements
        if (risSimple.test(qualifier)) {
            return jQuery.filter(qualifier, elements, not);
        }
        // Complex selector, compare the two sets, removing non-Elements
        qualifier = jQuery.filter(qualifier, elements);
        return jQuery.grep(elements, function (elem) {
            return (indexOf.call(qualifier, elem) > -1) !== not && elem.nodeType === 1;
        });
    }
    jQuery.filter = function (expr, elems, not) {
        var elem = elems[0];
        if (not) {
            expr = ":not(" + expr + ")";
        }
        if (elems.length === 1 && elem.nodeType === 1) {
            return jQuery.find.matchesSelector(elem, expr) ? [elem] : [];
        }
        return jQuery.find.matches(expr, jQuery.grep(elems, function (elem) {
            return elem.nodeType === 1;
        }));
    };
    jQuery.fn.extend({
        find: function (selector) {
            var i, ret, len = this.length, self = this;
            if (typeof selector !== "string") {
                return this.pushStack(jQuery(selector).filter(function () {
                    for (i = 0; i < len; i++) {
                        if (jQuery.contains(self[i], this)) {
                            return true;
                        }
                    }
                }));
            }
            ret = this.pushStack([]);
            for (i = 0; i < len; i++) {
                jQuery.find(selector, self[i], ret);
            }
            return len > 1 ? jQuery.uniqueSort(ret) : ret;
        },
        filter: function (selector) {
            return this.pushStack(winnow(this, selector || [], false));
        },
        not: function (selector) {
            return this.pushStack(winnow(this, selector || [], true));
        },
        is: function (selector) {
            return !!winnow(this, 
            // If this is a positional/relative selector, check membership in the returned set
            // so $("p:first").is("p:last") won't return true for a doc with two "p".
            typeof selector === "string" && rneedsContext.test(selector) ?
                jQuery(selector) :
                selector || [], false).length;
        }
    });
    // Initialize a jQuery object
    // A central reference to the root jQuery(document)
    var rootjQuery, 
    // A simple way to check for HTML strings
    // Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
    // Strict HTML recognition (#11290: must start with <)
    // Shortcut simple #id case for speed
    rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, init = jQuery.fn.init = function (selector, context, root) {
        var match, elem;
        // HANDLE: $(""), $(null), $(undefined), $(false)
        if (!selector) {
            return this;
        }
        // Method init() accepts an alternate rootjQuery
        // so migrate can support jQuery.sub (gh-2101)
        root = root || rootjQuery;
        // Handle HTML strings
        if (typeof selector === "string") {
            if (selector[0] === "<" &&
                selector[selector.length - 1] === ">" &&
                selector.length >= 3) {
                // Assume that strings that start and end with <> are HTML and skip the regex check
                match = [null, selector, null];
            }
            else {
                match = rquickExpr.exec(selector);
            }
            // Match html or make sure no context is specified for #id
            if (match && (match[1] || !context)) {
                // HANDLE: $(html) -> $(array)
                if (match[1]) {
                    context = context instanceof jQuery ? context[0] : context;
                    // Option to run scripts is true for back-compat
                    // Intentionally let the error be thrown if parseHTML is not present
                    jQuery.merge(this, jQuery.parseHTML(match[1], context && context.nodeType ? context.ownerDocument || context : document, true));
                    // HANDLE: $(html, props)
                    if (rsingleTag.test(match[1]) && jQuery.isPlainObject(context)) {
                        for (match in context) {
                            // Properties of context are called as methods if possible
                            if (jQuery.isFunction(this[match])) {
                                this[match](context[match]);
                            }
                            else {
                                this.attr(match, context[match]);
                            }
                        }
                    }
                    return this;
                }
                else {
                    elem = document.getElementById(match[2]);
                    if (elem) {
                        // Inject the element directly into the jQuery object
                        this[0] = elem;
                        this.length = 1;
                    }
                    return this;
                }
            }
            else if (!context || context.jquery) {
                return (context || root).find(selector);
            }
            else {
                return this.constructor(context).find(selector);
            }
        }
        else if (selector.nodeType) {
            this[0] = selector;
            this.length = 1;
            return this;
        }
        else if (jQuery.isFunction(selector)) {
            return root.ready !== undefined ?
                root.ready(selector) :
                // Execute immediately if ready is not present
                selector(jQuery);
        }
        return jQuery.makeArray(selector, this);
    };
    // Give the init function the jQuery prototype for later instantiation
    init.prototype = jQuery.fn;
    // Initialize central reference
    rootjQuery = jQuery(document);
    var rparentsprev = /^(?:parents|prev(?:Until|All))/, 
    // Methods guaranteed to produce a unique set when starting from a unique set
    guaranteedUnique = {
        children: true,
        contents: true,
        next: true,
        prev: true
    };
    jQuery.fn.extend({
        has: function (target) {
            var targets = jQuery(target, this), l = targets.length;
            return this.filter(function () {
                var i = 0;
                for (; i < l; i++) {
                    if (jQuery.contains(this, targets[i])) {
                        return true;
                    }
                }
            });
        },
        closest: function (selectors, context) {
            var cur, i = 0, l = this.length, matched = [], targets = typeof selectors !== "string" && jQuery(selectors);
            // Positional selectors never match, since there's no _selection_ context
            if (!rneedsContext.test(selectors)) {
                for (; i < l; i++) {
                    for (cur = this[i]; cur && cur !== context; cur = cur.parentNode) {
                        // Always skip document fragments
                        if (cur.nodeType < 11 && (targets ?
                            targets.index(cur) > -1 :
                            // Don't pass non-elements to Sizzle
                            cur.nodeType === 1 &&
                                jQuery.find.matchesSelector(cur, selectors))) {
                            matched.push(cur);
                            break;
                        }
                    }
                }
            }
            return this.pushStack(matched.length > 1 ? jQuery.uniqueSort(matched) : matched);
        },
        // Determine the position of an element within the set
        index: function (elem) {
            // No argument, return index in parent
            if (!elem) {
                return (this[0] && this[0].parentNode) ? this.first().prevAll().length : -1;
            }
            // Index in selector
            if (typeof elem === "string") {
                return indexOf.call(jQuery(elem), this[0]);
            }
            // Locate the position of the desired element
            return indexOf.call(this, 
            // If it receives a jQuery object, the first element is used
            elem.jquery ? elem[0] : elem);
        },
        add: function (selector, context) {
            return this.pushStack(jQuery.uniqueSort(jQuery.merge(this.get(), jQuery(selector, context))));
        },
        addBack: function (selector) {
            return this.add(selector == null ?
                this.prevObject : this.prevObject.filter(selector));
        }
    });
    function sibling(cur, dir) {
        while ((cur = cur[dir]) && cur.nodeType !== 1) { }
        return cur;
    }
    jQuery.each({
        parent: function (elem) {
            var parent = elem.parentNode;
            return parent && parent.nodeType !== 11 ? parent : null;
        },
        parents: function (elem) {
            return dir(elem, "parentNode");
        },
        parentsUntil: function (elem, i, until) {
            return dir(elem, "parentNode", until);
        },
        next: function (elem) {
            return sibling(elem, "nextSibling");
        },
        prev: function (elem) {
            return sibling(elem, "previousSibling");
        },
        nextAll: function (elem) {
            return dir(elem, "nextSibling");
        },
        prevAll: function (elem) {
            return dir(elem, "previousSibling");
        },
        nextUntil: function (elem, i, until) {
            return dir(elem, "nextSibling", until);
        },
        prevUntil: function (elem, i, until) {
            return dir(elem, "previousSibling", until);
        },
        siblings: function (elem) {
            return siblings((elem.parentNode || {}).firstChild, elem);
        },
        children: function (elem) {
            return siblings(elem.firstChild);
        },
        contents: function (elem) {
            return elem.contentDocument || jQuery.merge([], elem.childNodes);
        }
    }, function (name, fn) {
        jQuery.fn[name] = function (until, selector) {
            var matched = jQuery.map(this, fn, until);
            if (name.slice(-5) !== "Until") {
                selector = until;
            }
            if (selector && typeof selector === "string") {
                matched = jQuery.filter(selector, matched);
            }
            if (this.length > 1) {
                // Remove duplicates
                if (!guaranteedUnique[name]) {
                    jQuery.uniqueSort(matched);
                }
                // Reverse order for parents* and prev-derivatives
                if (rparentsprev.test(name)) {
                    matched.reverse();
                }
            }
            return this.pushStack(matched);
        };
    });
    var rnothtmlwhite = (/[^\x20\t\r\n\f]+/g);
    // Convert String-formatted options into Object-formatted ones
    function createOptions(options) {
        var object = {};
        jQuery.each(options.match(rnothtmlwhite) || [], function (_, flag) {
            object[flag] = true;
        });
        return object;
    }
    /*
     * Create a callback list using the following parameters:
     *
     *	options: an optional list of space-separated options that will change how
     *			the callback list behaves or a more traditional option object
     *
     * By default a callback list will act like an event callback list and can be
     * "fired" multiple times.
     *
     * Possible options:
     *
     *	once:			will ensure the callback list can only be fired once (like a Deferred)
     *
     *	memory:			will keep track of previous values and will call any callback added
     *					after the list has been fired right away with the latest "memorized"
     *					values (like a Deferred)
     *
     *	unique:			will ensure a callback can only be added once (no duplicate in the list)
     *
     *	stopOnFalse:	interrupt callings when a callback returns false
     *
     */
    jQuery.Callbacks = function (options) {
        // Convert options from String-formatted to Object-formatted if needed
        // (we check in cache first)
        options = typeof options === "string" ?
            createOptions(options) :
            jQuery.extend({}, options);
        var // Flag to know if list is currently firing
        firing, 
        // Last fire value for non-forgettable lists
        memory, 
        // Flag to know if list was already fired
        fired, 
        // Flag to prevent firing
        locked, 
        // Actual callback list
        list = [], 
        // Queue of execution data for repeatable lists
        queue = [], 
        // Index of currently firing callback (modified by add/remove as needed)
        firingIndex = -1, 
        // Fire callbacks
        fire = function () {
            // Enforce single-firing
            locked = options.once;
            // Execute callbacks for all pending executions,
            // respecting firingIndex overrides and runtime changes
            fired = firing = true;
            for (; queue.length; firingIndex = -1) {
                memory = queue.shift();
                while (++firingIndex < list.length) {
                    // Run callback and check for early termination
                    if (list[firingIndex].apply(memory[0], memory[1]) === false &&
                        options.stopOnFalse) {
                        // Jump to end and forget the data so .add doesn't re-fire
                        firingIndex = list.length;
                        memory = false;
                    }
                }
            }
            // Forget the data if we're done with it
            if (!options.memory) {
                memory = false;
            }
            firing = false;
            // Clean up if we're done firing for good
            if (locked) {
                // Keep an empty list if we have data for future add calls
                if (memory) {
                    list = [];
                }
                else {
                    list = "";
                }
            }
        }, 
        // Actual Callbacks object
        self = {
            // Add a callback or a collection of callbacks to the list
            add: function () {
                if (list) {
                    // If we have memory from a past run, we should fire after adding
                    if (memory && !firing) {
                        firingIndex = list.length - 1;
                        queue.push(memory);
                    }
                    (function add(args) {
                        jQuery.each(args, function (_, arg) {
                            if (jQuery.isFunction(arg)) {
                                if (!options.unique || !self.has(arg)) {
                                    list.push(arg);
                                }
                            }
                            else if (arg && arg.length && jQuery.type(arg) !== "string") {
                                // Inspect recursively
                                add(arg);
                            }
                        });
                    })(arguments);
                    if (memory && !firing) {
                        fire();
                    }
                }
                return this;
            },
            // Remove a callback from the list
            remove: function () {
                jQuery.each(arguments, function (_, arg) {
                    var index;
                    while ((index = jQuery.inArray(arg, list, index)) > -1) {
                        list.splice(index, 1);
                        // Handle firing indexes
                        if (index <= firingIndex) {
                            firingIndex--;
                        }
                    }
                });
                return this;
            },
            // Check if a given callback is in the list.
            // If no argument is given, return whether or not list has callbacks attached.
            has: function (fn) {
                return fn ?
                    jQuery.inArray(fn, list) > -1 :
                    list.length > 0;
            },
            // Remove all callbacks from the list
            empty: function () {
                if (list) {
                    list = [];
                }
                return this;
            },
            // Disable .fire and .add
            // Abort any current/pending executions
            // Clear all callbacks and values
            disable: function () {
                locked = queue = [];
                list = memory = "";
                return this;
            },
            disabled: function () {
                return !list;
            },
            // Disable .fire
            // Also disable .add unless we have memory (since it would have no effect)
            // Abort any pending executions
            lock: function () {
                locked = queue = [];
                if (!memory && !firing) {
                    list = memory = "";
                }
                return this;
            },
            locked: function () {
                return !!locked;
            },
            // Call all callbacks with the given context and arguments
            fireWith: function (context, args) {
                if (!locked) {
                    args = args || [];
                    args = [context, args.slice ? args.slice() : args];
                    queue.push(args);
                    if (!firing) {
                        fire();
                    }
                }
                return this;
            },
            // Call all the callbacks with the given arguments
            fire: function () {
                self.fireWith(this, arguments);
                return this;
            },
            // To know if the callbacks have already been called at least once
            fired: function () {
                return !!fired;
            }
        };
        return self;
    };
    function Identity(v) {
        return v;
    }
    function Thrower(ex) {
        throw ex;
    }
    function adoptValue(value, resolve, reject) {
        var method;
        try {
            // Check for promise aspect first to privilege synchronous behavior
            if (value && jQuery.isFunction((method = value.promise))) {
                method.call(value).done(resolve).fail(reject);
            }
            else if (value && jQuery.isFunction((method = value.then))) {
                method.call(value, resolve, reject);
            }
            else {
                // Support: Android 4.0 only
                // Strict mode functions invoked without .call/.apply get global-object context
                resolve.call(undefined, value);
            }
        }
        catch (value) {
            // Support: Android 4.0 only
            // Strict mode functions invoked without .call/.apply get global-object context
            reject.call(undefined, value);
        }
    }
    jQuery.extend({
        Deferred: function (func) {
            var tuples = [
                // action, add listener, callbacks,
                // ... .then handlers, argument index, [final state]
                ["notify", "progress", jQuery.Callbacks("memory"),
                    jQuery.Callbacks("memory"), 2],
                ["resolve", "done", jQuery.Callbacks("once memory"),
                    jQuery.Callbacks("once memory"), 0, "resolved"],
                ["reject", "fail", jQuery.Callbacks("once memory"),
                    jQuery.Callbacks("once memory"), 1, "rejected"]
            ], state = "pending", promise = {
                state: function () {
                    return state;
                },
                always: function () {
                    deferred.done(arguments).fail(arguments);
                    return this;
                },
                "catch": function (fn) {
                    return promise.then(null, fn);
                },
                // Keep pipe for back-compat
                pipe: function () {
                    var fns = arguments;
                    return jQuery.Deferred(function (newDefer) {
                        jQuery.each(tuples, function (i, tuple) {
                            // Map tuples (progress, done, fail) to arguments (done, fail, progress)
                            var fn = jQuery.isFunction(fns[tuple[4]]) && fns[tuple[4]];
                            // deferred.progress(function() { bind to newDefer or newDefer.notify })
                            // deferred.done(function() { bind to newDefer or newDefer.resolve })
                            // deferred.fail(function() { bind to newDefer or newDefer.reject })
                            deferred[tuple[1]](function () {
                                var returned = fn && fn.apply(this, arguments);
                                if (returned && jQuery.isFunction(returned.promise)) {
                                    returned.promise()
                                        .progress(newDefer.notify)
                                        .done(newDefer.resolve)
                                        .fail(newDefer.reject);
                                }
                                else {
                                    newDefer[tuple[0] + "With"](this, fn ? [returned] : arguments);
                                }
                            });
                        });
                        fns = null;
                    }).promise();
                },
                then: function (onFulfilled, onRejected, onProgress) {
                    var maxDepth = 0;
                    function resolve(depth, deferred, handler, special) {
                        return function () {
                            var that = this, args = arguments, mightThrow = function () {
                                var returned, then;
                                // Support: Promises/A+ section 2.3.3.3.3
                                // https://promisesaplus.com/#point-59
                                // Ignore double-resolution attempts
                                if (depth < maxDepth) {
                                    return;
                                }
                                returned = handler.apply(that, args);
                                // Support: Promises/A+ section 2.3.1
                                // https://promisesaplus.com/#point-48
                                if (returned === deferred.promise()) {
                                    throw new TypeError("Thenable self-resolution");
                                }
                                // Support: Promises/A+ sections 2.3.3.1, 3.5
                                // https://promisesaplus.com/#point-54
                                // https://promisesaplus.com/#point-75
                                // Retrieve `then` only once
                                then = returned &&
                                    // Support: Promises/A+ section 2.3.4
                                    // https://promisesaplus.com/#point-64
                                    // Only check objects and functions for thenability
                                    (typeof returned === "object" ||
                                        typeof returned === "function") &&
                                    returned.then;
                                // Handle a returned thenable
                                if (jQuery.isFunction(then)) {
                                    // Special processors (notify) just wait for resolution
                                    if (special) {
                                        then.call(returned, resolve(maxDepth, deferred, Identity, special), resolve(maxDepth, deferred, Thrower, special));
                                    }
                                    else {
                                        // ...and disregard older resolution values
                                        maxDepth++;
                                        then.call(returned, resolve(maxDepth, deferred, Identity, special), resolve(maxDepth, deferred, Thrower, special), resolve(maxDepth, deferred, Identity, deferred.notifyWith));
                                    }
                                }
                                else {
                                    // Only substitute handlers pass on context
                                    // and multiple values (non-spec behavior)
                                    if (handler !== Identity) {
                                        that = undefined;
                                        args = [returned];
                                    }
                                    // Process the value(s)
                                    // Default process is resolve
                                    (special || deferred.resolveWith)(that, args);
                                }
                            }, 
                            // Only normal processors (resolve) catch and reject exceptions
                            process = special ?
                                mightThrow :
                                function () {
                                    try {
                                        mightThrow();
                                    }
                                    catch (e) {
                                        if (jQuery.Deferred.exceptionHook) {
                                            jQuery.Deferred.exceptionHook(e, process.stackTrace);
                                        }
                                        // Support: Promises/A+ section 2.3.3.3.4.1
                                        // https://promisesaplus.com/#point-61
                                        // Ignore post-resolution exceptions
                                        if (depth + 1 >= maxDepth) {
                                            // Only substitute handlers pass on context
                                            // and multiple values (non-spec behavior)
                                            if (handler !== Thrower) {
                                                that = undefined;
                                                args = [e];
                                            }
                                            deferred.rejectWith(that, args);
                                        }
                                    }
                                };
                            // Support: Promises/A+ section 2.3.3.3.1
                            // https://promisesaplus.com/#point-57
                            // Re-resolve promises immediately to dodge false rejection from
                            // subsequent errors
                            if (depth) {
                                process();
                            }
                            else {
                                // Call an optional hook to record the stack, in case of exception
                                // since it's otherwise lost when execution goes async
                                if (jQuery.Deferred.getStackHook) {
                                    process.stackTrace = jQuery.Deferred.getStackHook();
                                }
                                window.setTimeout(process);
                            }
                        };
                    }
                    return jQuery.Deferred(function (newDefer) {
                        // progress_handlers.add( ... )
                        tuples[0][3].add(resolve(0, newDefer, jQuery.isFunction(onProgress) ?
                            onProgress :
                            Identity, newDefer.notifyWith));
                        // fulfilled_handlers.add( ... )
                        tuples[1][3].add(resolve(0, newDefer, jQuery.isFunction(onFulfilled) ?
                            onFulfilled :
                            Identity));
                        // rejected_handlers.add( ... )
                        tuples[2][3].add(resolve(0, newDefer, jQuery.isFunction(onRejected) ?
                            onRejected :
                            Thrower));
                    }).promise();
                },
                // Get a promise for this deferred
                // If obj is provided, the promise aspect is added to the object
                promise: function (obj) {
                    return obj != null ? jQuery.extend(obj, promise) : promise;
                }
            }, deferred = {};
            // Add list-specific methods
            jQuery.each(tuples, function (i, tuple) {
                var list = tuple[2], stateString = tuple[5];
                // promise.progress = list.add
                // promise.done = list.add
                // promise.fail = list.add
                promise[tuple[1]] = list.add;
                // Handle state
                if (stateString) {
                    list.add(function () {
                        // state = "resolved" (i.e., fulfilled)
                        // state = "rejected"
                        state = stateString;
                    }, 
                    // rejected_callbacks.disable
                    // fulfilled_callbacks.disable
                    tuples[3 - i][2].disable, 
                    // progress_callbacks.lock
                    tuples[0][2].lock);
                }
                // progress_handlers.fire
                // fulfilled_handlers.fire
                // rejected_handlers.fire
                list.add(tuple[3].fire);
                // deferred.notify = function() { deferred.notifyWith(...) }
                // deferred.resolve = function() { deferred.resolveWith(...) }
                // deferred.reject = function() { deferred.rejectWith(...) }
                deferred[tuple[0]] = function () {
                    deferred[tuple[0] + "With"](this === deferred ? undefined : this, arguments);
                    return this;
                };
                // deferred.notifyWith = list.fireWith
                // deferred.resolveWith = list.fireWith
                // deferred.rejectWith = list.fireWith
                deferred[tuple[0] + "With"] = list.fireWith;
            });
            // Make the deferred a promise
            promise.promise(deferred);
            // Call given func if any
            if (func) {
                func.call(deferred, deferred);
            }
            // All done!
            return deferred;
        },
        // Deferred helper
        when: function (singleValue) {
            var 
            // count of uncompleted subordinates
            remaining = arguments.length, 
            // count of unprocessed arguments
            i = remaining, 
            // subordinate fulfillment data
            resolveContexts = Array(i), resolveValues = slice.call(arguments), 
            // the master Deferred
            master = jQuery.Deferred(), 
            // subordinate callback factory
            updateFunc = function (i) {
                return function (value) {
                    resolveContexts[i] = this;
                    resolveValues[i] = arguments.length > 1 ? slice.call(arguments) : value;
                    if (!(--remaining)) {
                        master.resolveWith(resolveContexts, resolveValues);
                    }
                };
            };
            // Single- and empty arguments are adopted like Promise.resolve
            if (remaining <= 1) {
                adoptValue(singleValue, master.done(updateFunc(i)).resolve, master.reject);
                // Use .then() to unwrap secondary thenables (cf. gh-3000)
                if (master.state() === "pending" ||
                    jQuery.isFunction(resolveValues[i] && resolveValues[i].then)) {
                    return master.then();
                }
            }
            // Multiple arguments are aggregated like Promise.all array elements
            while (i--) {
                adoptValue(resolveValues[i], updateFunc(i), master.reject);
            }
            return master.promise();
        }
    });
    // These usually indicate a programmer mistake during development,
    // warn about them ASAP rather than swallowing them by default.
    var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;
    jQuery.Deferred.exceptionHook = function (error, stack) {
        // Support: IE 8 - 9 only
        // Console exists when dev tools are open, which can happen at any time
        if (window.console && window.console.warn && error && rerrorNames.test(error.name)) {
            window.console.warn("jQuery.Deferred exception: " + error.message, error.stack, stack);
        }
    };
    jQuery.readyException = function (error) {
        window.setTimeout(function () {
            throw error;
        });
    };
    // The deferred used on DOM ready
    var readyList = jQuery.Deferred();
    jQuery.fn.ready = function (fn) {
        readyList
            .then(fn)
            .catch(function (error) {
            jQuery.readyException(error);
        });
        return this;
    };
    jQuery.extend({
        // Is the DOM ready to be used? Set to true once it occurs.
        isReady: false,
        // A counter to track how many items to wait for before
        // the ready event fires. See #6781
        readyWait: 1,
        // Hold (or release) the ready event
        holdReady: function (hold) {
            if (hold) {
                jQuery.readyWait++;
            }
            else {
                jQuery.ready(true);
            }
        },
        // Handle when the DOM is ready
        ready: function (wait) {
            // Abort if there are pending holds or we're already ready
            if (wait === true ? --jQuery.readyWait : jQuery.isReady) {
                return;
            }
            // Remember that the DOM is ready
            jQuery.isReady = true;
            // If a normal DOM Ready event fired, decrement, and wait if need be
            if (wait !== true && --jQuery.readyWait > 0) {
                return;
            }
            // If there are functions bound, to execute
            readyList.resolveWith(document, [jQuery]);
        }
    });
    jQuery.ready.then = readyList.then;
    // The ready event handler and self cleanup method
    function completed() {
        document.removeEventListener("DOMContentLoaded", completed);
        window.removeEventListener("load", completed);
        jQuery.ready();
    }
    // Catch cases where $(document).ready() is called
    // after the browser event has already occurred.
    // Support: IE <=9 - 10 only
    // Older IE sometimes signals "interactive" too soon
    if (document.readyState === "complete" ||
        (document.readyState !== "loading" && !document.documentElement.doScroll)) {
        // Handle it asynchronously to allow scripts the opportunity to delay ready
        window.setTimeout(jQuery.ready);
    }
    else {
        // Use the handy event callback
        document.addEventListener("DOMContentLoaded", completed);
        // A fallback to window.onload, that will always work
        window.addEventListener("load", completed);
    }
    // Multifunctional method to get and set values of a collection
    // The value/s can optionally be executed if it's a function
    var access = function (elems, fn, key, value, chainable, emptyGet, raw) {
        var i = 0, len = elems.length, bulk = key == null;
        // Sets many values
        if (jQuery.type(key) === "object") {
            chainable = true;
            for (i in key) {
                access(elems, fn, i, key[i], true, emptyGet, raw);
            }
        }
        else if (value !== undefined) {
            chainable = true;
            if (!jQuery.isFunction(value)) {
                raw = true;
            }
            if (bulk) {
                // Bulk operations run against the entire set
                if (raw) {
                    fn.call(elems, value);
                    fn = null;
                }
                else {
                    bulk = fn;
                    fn = function (elem, key, value) {
                        return bulk.call(jQuery(elem), value);
                    };
                }
            }
            if (fn) {
                for (; i < len; i++) {
                    fn(elems[i], key, raw ?
                        value :
                        value.call(elems[i], i, fn(elems[i], key)));
                }
            }
        }
        if (chainable) {
            return elems;
        }
        // Gets
        if (bulk) {
            return fn.call(elems);
        }
        return len ? fn(elems[0], key) : emptyGet;
    };
    var acceptData = function (owner) {
        // Accepts only:
        //  - Node
        //    - Node.ELEMENT_NODE
        //    - Node.DOCUMENT_NODE
        //  - Object
        //    - Any
        return owner.nodeType === 1 || owner.nodeType === 9 || !(+owner.nodeType);
    };
    function Data() {
        this.expando = jQuery.expando + Data.uid++;
    }
    Data.uid = 1;
    Data.prototype = {
        cache: function (owner) {
            // Check if the owner object already has a cache
            var value = owner[this.expando];
            // If not, create one
            if (!value) {
                value = {};
                // We can accept data for non-element nodes in modern browsers,
                // but we should not, see #8335.
                // Always return an empty object.
                if (acceptData(owner)) {
                    // If it is a node unlikely to be stringify-ed or looped over
                    // use plain assignment
                    if (owner.nodeType) {
                        owner[this.expando] = value;
                    }
                    else {
                        Object.defineProperty(owner, this.expando, {
                            value: value,
                            configurable: true
                        });
                    }
                }
            }
            return value;
        },
        set: function (owner, data, value) {
            var prop, cache = this.cache(owner);
            // Handle: [ owner, key, value ] args
            // Always use camelCase key (gh-2257)
            if (typeof data === "string") {
                cache[jQuery.camelCase(data)] = value;
            }
            else {
                // Copy the properties one-by-one to the cache object
                for (prop in data) {
                    cache[jQuery.camelCase(prop)] = data[prop];
                }
            }
            return cache;
        },
        get: function (owner, key) {
            return key === undefined ?
                this.cache(owner) :
                // Always use camelCase key (gh-2257)
                owner[this.expando] && owner[this.expando][jQuery.camelCase(key)];
        },
        access: function (owner, key, value) {
            // In cases where either:
            //
            //   1. No key was specified
            //   2. A string key was specified, but no value provided
            //
            // Take the "read" path and allow the get method to determine
            // which value to return, respectively either:
            //
            //   1. The entire cache object
            //   2. The data stored at the key
            //
            if (key === undefined ||
                ((key && typeof key === "string") && value === undefined)) {
                return this.get(owner, key);
            }
            // When the key is not a string, or both a key and value
            // are specified, set or extend (existing objects) with either:
            //
            //   1. An object of properties
            //   2. A key and value
            //
            this.set(owner, key, value);
            // Since the "set" path can have two possible entry points
            // return the expected data based on which path was taken[*]
            return value !== undefined ? value : key;
        },
        remove: function (owner, key) {
            var i, cache = owner[this.expando];
            if (cache === undefined) {
                return;
            }
            if (key !== undefined) {
                // Support array or space separated string of keys
                if (jQuery.isArray(key)) {
                    // If key is an array of keys...
                    // We always set camelCase keys, so remove that.
                    key = key.map(jQuery.camelCase);
                }
                else {
                    key = jQuery.camelCase(key);
                    // If a key with the spaces exists, use it.
                    // Otherwise, create an array by matching non-whitespace
                    key = key in cache ?
                        [key] :
                        (key.match(rnothtmlwhite) || []);
                }
                i = key.length;
                while (i--) {
                    delete cache[key[i]];
                }
            }
            // Remove the expando if there's no more data
            if (key === undefined || jQuery.isEmptyObject(cache)) {
                // Support: Chrome <=35 - 45
                // Webkit & Blink performance suffers when deleting properties
                // from DOM nodes, so set to undefined instead
                // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted)
                if (owner.nodeType) {
                    owner[this.expando] = undefined;
                }
                else {
                    delete owner[this.expando];
                }
            }
        },
        hasData: function (owner) {
            var cache = owner[this.expando];
            return cache !== undefined && !jQuery.isEmptyObject(cache);
        }
    };
    var dataPriv = new Data();
    var dataUser = new Data();
    //	Implementation Summary
    //
    //	1. Enforce API surface and semantic compatibility with 1.9.x branch
    //	2. Improve the module's maintainability by reducing the storage
    //		paths to a single mechanism.
    //	3. Use the same single mechanism to support "private" and "user" data.
    //	4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData)
    //	5. Avoid exposing implementation details on user objects (eg. expando properties)
    //	6. Provide a clear path for implementation upgrade to WeakMap in 2014
    var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, rmultiDash = /[A-Z]/g;
    function getData(data) {
        if (data === "true") {
            return true;
        }
        if (data === "false") {
            return false;
        }
        if (data === "null") {
            return null;
        }
        // Only convert to a number if it doesn't change the string
        if (data === +data + "") {
            return +data;
        }
        if (rbrace.test(data)) {
            return JSON.parse(data);
        }
        return data;
    }
    function dataAttr(elem, key, data) {
        var name;
        // If nothing was found internally, try to fetch any
        // data from the HTML5 data-* attribute
        if (data === undefined && elem.nodeType === 1) {
            name = "data-" + key.replace(rmultiDash, "-$&").toLowerCase();
            data = elem.getAttribute(name);
            if (typeof data === "string") {
                try {
                    data = getData(data);
                }
                catch (e) { }
                // Make sure we set the data so it isn't changed later
                dataUser.set(elem, key, data);
            }
            else {
                data = undefined;
            }
        }
        return data;
    }
    jQuery.extend({
        hasData: function (elem) {
            return dataUser.hasData(elem) || dataPriv.hasData(elem);
        },
        data: function (elem, name, data) {
            return dataUser.access(elem, name, data);
        },
        removeData: function (elem, name) {
            dataUser.remove(elem, name);
        },
        // TODO: Now that all calls to _data and _removeData have been replaced
        // with direct calls to dataPriv methods, these can be deprecated.
        _data: function (elem, name, data) {
            return dataPriv.access(elem, name, data);
        },
        _removeData: function (elem, name) {
            dataPriv.remove(elem, name);
        }
    });
    jQuery.fn.extend({
        data: function (key, value) {
            var i, name, data, elem = this[0], attrs = elem && elem.attributes;
            // Gets all values
            if (key === undefined) {
                if (this.length) {
                    data = dataUser.get(elem);
                    if (elem.nodeType === 1 && !dataPriv.get(elem, "hasDataAttrs")) {
                        i = attrs.length;
                        while (i--) {
                            // Support: IE 11 only
                            // The attrs elements can be null (#14894)
                            if (attrs[i]) {
                                name = attrs[i].name;
                                if (name.indexOf("data-") === 0) {
                                    name = jQuery.camelCase(name.slice(5));
                                    dataAttr(elem, name, data[name]);
                                }
                            }
                        }
                        dataPriv.set(elem, "hasDataAttrs", true);
                    }
                }
                return data;
            }
            // Sets multiple values
            if (typeof key === "object") {
                return this.each(function () {
                    dataUser.set(this, key);
                });
            }
            return access(this, function (value) {
                var data;
                // The calling jQuery object (element matches) is not empty
                // (and therefore has an element appears at this[ 0 ]) and the
                // `value` parameter was not undefined. An empty jQuery object
                // will result in `undefined` for elem = this[ 0 ] which will
                // throw an exception if an attempt to read a data cache is made.
                if (elem && value === undefined) {
                    // Attempt to get data from the cache
                    // The key will always be camelCased in Data
                    data = dataUser.get(elem, key);
                    if (data !== undefined) {
                        return data;
                    }
                    // Attempt to "discover" the data in
                    // HTML5 custom data-* attrs
                    data = dataAttr(elem, key);
                    if (data !== undefined) {
                        return data;
                    }
                    // We tried really hard, but the data doesn't exist.
                    return;
                }
                // Set the data...
                this.each(function () {
                    // We always store the camelCased key
                    dataUser.set(this, key, value);
                });
            }, null, value, arguments.length > 1, null, true);
        },
        removeData: function (key) {
            return this.each(function () {
                dataUser.remove(this, key);
            });
        }
    });
    jQuery.extend({
        queue: function (elem, type, data) {
            var queue;
            if (elem) {
                type = (type || "fx") + "queue";
                queue = dataPriv.get(elem, type);
                // Speed up dequeue by getting out quickly if this is just a lookup
                if (data) {
                    if (!queue || jQuery.isArray(data)) {
                        queue = dataPriv.access(elem, type, jQuery.makeArray(data));
                    }
                    else {
                        queue.push(data);
                    }
                }
                return queue || [];
            }
        },
        dequeue: function (elem, type) {
            type = type || "fx";
            var queue = jQuery.queue(elem, type), startLength = queue.length, fn = queue.shift(), hooks = jQuery._queueHooks(elem, type), next = function () {
                jQuery.dequeue(elem, type);
            };
            // If the fx queue is dequeued, always remove the progress sentinel
            if (fn === "inprogress") {
                fn = queue.shift();
                startLength--;
            }
            if (fn) {
                // Add a progress sentinel to prevent the fx queue from being
                // automatically dequeued
                if (type === "fx") {
                    queue.unshift("inprogress");
                }
                // Clear up the last queue stop function
                delete hooks.stop;
                fn.call(elem, next, hooks);
            }
            if (!startLength && hooks) {
                hooks.empty.fire();
            }
        },
        // Not public - generate a queueHooks object, or return the current one
        _queueHooks: function (elem, type) {
            var key = type + "queueHooks";
            return dataPriv.get(elem, key) || dataPriv.access(elem, key, {
                empty: jQuery.Callbacks("once memory").add(function () {
                    dataPriv.remove(elem, [type + "queue", key]);
                })
            });
        }
    });
    jQuery.fn.extend({
        queue: function (type, data) {
            var setter = 2;
            if (typeof type !== "string") {
                data = type;
                type = "fx";
                setter--;
            }
            if (arguments.length < setter) {
                return jQuery.queue(this[0], type);
            }
            return data === undefined ?
                this :
                this.each(function () {
                    var queue = jQuery.queue(this, type, data);
                    // Ensure a hooks for this queue
                    jQuery._queueHooks(this, type);
                    if (type === "fx" && queue[0] !== "inprogress") {
                        jQuery.dequeue(this, type);
                    }
                });
        },
        dequeue: function (type) {
            return this.each(function () {
                jQuery.dequeue(this, type);
            });
        },
        clearQueue: function (type) {
            return this.queue(type || "fx", []);
        },
        // Get a promise resolved when queues of a certain type
        // are emptied (fx is the type by default)
        promise: function (type, obj) {
            var tmp, count = 1, defer = jQuery.Deferred(), elements = this, i = this.length, resolve = function () {
                if (!(--count)) {
                    defer.resolveWith(elements, [elements]);
                }
            };
            if (typeof type !== "string") {
                obj = type;
                type = undefined;
            }
            type = type || "fx";
            while (i--) {
                tmp = dataPriv.get(elements[i], type + "queueHooks");
                if (tmp && tmp.empty) {
                    count++;
                    tmp.empty.add(resolve);
                }
            }
            resolve();
            return defer.promise(obj);
        }
    });
    var pnum = (/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/).source;
    var rcssNum = new RegExp("^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i");
    var cssExpand = ["Top", "Right", "Bottom", "Left"];
    var isHiddenWithinTree = function (elem, el) {
        // isHiddenWithinTree might be called from jQuery#filter function;
        // in that case, element will be second argument
        elem = el || elem;
        // Inline style trumps all
        return elem.style.display === "none" ||
            elem.style.display === "" &&
                // Otherwise, check computed style
                // Support: Firefox <=43 - 45
                // Disconnected elements can have computed display: none, so first confirm that elem is
                // in the document.
                jQuery.contains(elem.ownerDocument, elem) &&
                jQuery.css(elem, "display") === "none";
    };
    var swap = function (elem, options, callback, args) {
        var ret, name, old = {};
        // Remember the old values, and insert the new ones
        for (name in options) {
            old[name] = elem.style[name];
            elem.style[name] = options[name];
        }
        ret = callback.apply(elem, args || []);
        // Revert the old values
        for (name in options) {
            elem.style[name] = old[name];
        }
        return ret;
    };
    function adjustCSS(elem, prop, valueParts, tween) {
        var adjusted, scale = 1, maxIterations = 20, currentValue = tween ?
            function () {
                return tween.cur();
            } :
            function () {
                return jQuery.css(elem, prop, "");
            }, initial = currentValue(), unit = valueParts && valueParts[3] || (jQuery.cssNumber[prop] ? "" : "px"), 
        // Starting value computation is required for potential unit mismatches
        initialInUnit = (jQuery.cssNumber[prop] || unit !== "px" && +initial) &&
            rcssNum.exec(jQuery.css(elem, prop));
        if (initialInUnit && initialInUnit[3] !== unit) {
            // Trust units reported by jQuery.css
            unit = unit || initialInUnit[3];
            // Make sure we update the tween properties later on
            valueParts = valueParts || [];
            // Iteratively approximate from a nonzero starting point
            initialInUnit = +initial || 1;
            do {
                // If previous iteration zeroed out, double until we get *something*.
                // Use string for doubling so we don't accidentally see scale as unchanged below
                scale = scale || ".5";
                // Adjust and apply
                initialInUnit = initialInUnit / scale;
                jQuery.style(elem, prop, initialInUnit + unit);
            } while (scale !== (scale = currentValue() / initial) && scale !== 1 && --maxIterations);
        }
        if (valueParts) {
            initialInUnit = +initialInUnit || +initial || 0;
            // Apply relative offset (+=/-=) if specified
            adjusted = valueParts[1] ?
                initialInUnit + (valueParts[1] + 1) * valueParts[2] :
                +valueParts[2];
            if (tween) {
                tween.unit = unit;
                tween.start = initialInUnit;
                tween.end = adjusted;
            }
        }
        return adjusted;
    }
    var defaultDisplayMap = {};
    function getDefaultDisplay(elem) {
        var temp, doc = elem.ownerDocument, nodeName = elem.nodeName, display = defaultDisplayMap[nodeName];
        if (display) {
            return display;
        }
        temp = doc.body.appendChild(doc.createElement(nodeName));
        display = jQuery.css(temp, "display");
        temp.parentNode.removeChild(temp);
        if (display === "none") {
            display = "block";
        }
        defaultDisplayMap[nodeName] = display;
        return display;
    }
    function showHide(elements, show) {
        var display, elem, values = [], index = 0, length = elements.length;
        // Determine new display value for elements that need to change
        for (; index < length; index++) {
            elem = elements[index];
            if (!elem.style) {
                continue;
            }
            display = elem.style.display;
            if (show) {
                // Since we force visibility upon cascade-hidden elements, an immediate (and slow)
                // check is required in this first loop unless we have a nonempty display value (either
                // inline or about-to-be-restored)
                if (display === "none") {
                    values[index] = dataPriv.get(elem, "display") || null;
                    if (!values[index]) {
                        elem.style.display = "";
                    }
                }
                if (elem.style.display === "" && isHiddenWithinTree(elem)) {
                    values[index] = getDefaultDisplay(elem);
                }
            }
            else {
                if (display !== "none") {
                    values[index] = "none";
                    // Remember what we're overwriting
                    dataPriv.set(elem, "display", display);
                }
            }
        }
        // Set the display of the elements in a second loop to avoid constant reflow
        for (index = 0; index < length; index++) {
            if (values[index] != null) {
                elements[index].style.display = values[index];
            }
        }
        return elements;
    }
    jQuery.fn.extend({
        show: function () {
            return showHide(this, true);
        },
        hide: function () {
            return showHide(this);
        },
        toggle: function (state) {
            if (typeof state === "boolean") {
                return state ? this.show() : this.hide();
            }
            return this.each(function () {
                if (isHiddenWithinTree(this)) {
                    jQuery(this).show();
                }
                else {
                    jQuery(this).hide();
                }
            });
        }
    });
    var rcheckableType = (/^(?:checkbox|radio)$/i);
    var rtagName = (/<([a-z][^\/\0>\x20\t\r\n\f]+)/i);
    var rscriptType = (/^$|\/(?:java|ecma)script/i);
    // We have to close these tags to support XHTML (#13200)
    var wrapMap = {
        // Support: IE <=9 only
        option: [1, "<select multiple='multiple'>", "</select>"],
        // XHTML parsers do not magically insert elements in the
        // same way that tag soup parsers do. So we cannot shorten
        // this by omitting <tbody> or other required elements.
        thead: [1, "<table>", "</table>"],
        col: [2, "<table><colgroup>", "</colgroup></table>"],
        tr: [2, "<table><tbody>", "</tbody></table>"],
        td: [3, "<table><tbody><tr>", "</tr></tbody></table>"],
        _default: [0, "", ""]
    };
    // Support: IE <=9 only
    wrapMap.optgroup = wrapMap.option;
    wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
    wrapMap.th = wrapMap.td;
    function getAll(context, tag) {
        // Support: IE <=9 - 11 only
        // Use typeof to avoid zero-argument method invocation on host objects (#15151)
        var ret;
        if (typeof context.getElementsByTagName !== "undefined") {
            ret = context.getElementsByTagName(tag || "*");
        }
        else if (typeof context.querySelectorAll !== "undefined") {
            ret = context.querySelectorAll(tag || "*");
        }
        else {
            ret = [];
        }
        if (tag === undefined || tag && jQuery.nodeName(context, tag)) {
            return jQuery.merge([context], ret);
        }
        return ret;
    }
    // Mark scripts as having already been evaluated
    function setGlobalEval(elems, refElements) {
        var i = 0, l = elems.length;
        for (; i < l; i++) {
            dataPriv.set(elems[i], "globalEval", !refElements || dataPriv.get(refElements[i], "globalEval"));
        }
    }
    var rhtml = /<|&#?\w+;/;
    function buildFragment(elems, context, scripts, selection, ignored) {
        var elem, tmp, tag, wrap, contains, j, fragment = context.createDocumentFragment(), nodes = [], i = 0, l = elems.length;
        for (; i < l; i++) {
            elem = elems[i];
            if (elem || elem === 0) {
                // Add nodes directly
                if (jQuery.type(elem) === "object") {
                    // Support: Android <=4.0 only, PhantomJS 1 only
                    // push.apply(_, arraylike) throws on ancient WebKit
                    jQuery.merge(nodes, elem.nodeType ? [elem] : elem);
                }
                else if (!rhtml.test(elem)) {
                    nodes.push(context.createTextNode(elem));
                }
                else {
                    tmp = tmp || fragment.appendChild(context.createElement("div"));
                    // Deserialize a standard representation
                    tag = (rtagName.exec(elem) || ["", ""])[1].toLowerCase();
                    wrap = wrapMap[tag] || wrapMap._default;
                    tmp.innerHTML = wrap[1] + jQuery.htmlPrefilter(elem) + wrap[2];
                    // Descend through wrappers to the right content
                    j = wrap[0];
                    while (j--) {
                        tmp = tmp.lastChild;
                    }
                    // Support: Android <=4.0 only, PhantomJS 1 only
                    // push.apply(_, arraylike) throws on ancient WebKit
                    jQuery.merge(nodes, tmp.childNodes);
                    // Remember the top-level container
                    tmp = fragment.firstChild;
                    // Ensure the created nodes are orphaned (#12392)
                    tmp.textContent = "";
                }
            }
        }
        // Remove wrapper from fragment
        fragment.textContent = "";
        i = 0;
        while ((elem = nodes[i++])) {
            // Skip elements already in the context collection (trac-4087)
            if (selection && jQuery.inArray(elem, selection) > -1) {
                if (ignored) {
                    ignored.push(elem);
                }
                continue;
            }
            contains = jQuery.contains(elem.ownerDocument, elem);
            // Append to fragment
            tmp = getAll(fragment.appendChild(elem), "script");
            // Preserve script evaluation history
            if (contains) {
                setGlobalEval(tmp);
            }
            // Capture executables
            if (scripts) {
                j = 0;
                while ((elem = tmp[j++])) {
                    if (rscriptType.test(elem.type || "")) {
                        scripts.push(elem);
                    }
                }
            }
        }
        return fragment;
    }
    (function () {
        var fragment = document.createDocumentFragment(), div = fragment.appendChild(document.createElement("div")), input = document.createElement("input");
        // Support: Android 4.0 - 4.3 only
        // Check state lost if the name is set (#11217)
        // Support: Windows Web Apps (WWA)
        // `name` and `type` must use .setAttribute for WWA (#14901)
        input.setAttribute("type", "radio");
        input.setAttribute("checked", "checked");
        input.setAttribute("name", "t");
        div.appendChild(input);
        // Support: Android <=4.1 only
        // Older WebKit doesn't clone checked state correctly in fragments
        support.checkClone = div.cloneNode(true).cloneNode(true).lastChild.checked;
        // Support: IE <=11 only
        // Make sure textarea (and checkbox) defaultValue is properly cloned
        div.innerHTML = "<textarea>x</textarea>";
        support.noCloneChecked = !!div.cloneNode(true).lastChild.defaultValue;
    })();
    var documentElement = document.documentElement;
    var rkeyEvent = /^key/, rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, rtypenamespace = /^([^.]*)(?:\.(.+)|)/;
    function returnTrue() {
        return true;
    }
    function returnFalse() {
        return false;
    }
    // Support: IE <=9 only
    // See #13393 for more info
    function safeActiveElement() {
        try {
            return document.activeElement;
        }
        catch (err) { }
    }
    function on(elem, types, selector, data, fn, one) {
        var origFn, type;
        // Types can be a map of types/handlers
        if (typeof types === "object") {
            // ( types-Object, selector, data )
            if (typeof selector !== "string") {
                // ( types-Object, data )
                data = data || selector;
                selector = undefined;
            }
            for (type in types) {
                on(elem, type, selector, data, types[type], one);
            }
            return elem;
        }
        if (data == null && fn == null) {
            // ( types, fn )
            fn = selector;
            data = selector = undefined;
        }
        else if (fn == null) {
            if (typeof selector === "string") {
                // ( types, selector, fn )
                fn = data;
                data = undefined;
            }
            else {
                // ( types, data, fn )
                fn = data;
                data = selector;
                selector = undefined;
            }
        }
        if (fn === false) {
            fn = returnFalse;
        }
        else if (!fn) {
            return elem;
        }
        if (one === 1) {
            origFn = fn;
            fn = function (event) {
                // Can use an empty set, since event contains the info
                jQuery().off(event);
                return origFn.apply(this, arguments);
            };
            // Use same guid so caller can remove using origFn
            fn.guid = origFn.guid || (origFn.guid = jQuery.guid++);
        }
        return elem.each(function () {
            jQuery.event.add(this, types, fn, data, selector);
        });
    }
    /*
     * Helper functions for managing events -- not part of the public interface.
     * Props to Dean Edwards' addEvent library for many of the ideas.
     */
    jQuery.event = {
        global: {},
        add: function (elem, types, handler, data, selector) {
            var handleObjIn, eventHandle, tmp, events, t, handleObj, special, handlers, type, namespaces, origType, elemData = dataPriv.get(elem);
            // Don't attach events to noData or text/comment nodes (but allow plain objects)
            if (!elemData) {
                return;
            }
            // Caller can pass in an object of custom data in lieu of the handler
            if (handler.handler) {
                handleObjIn = handler;
                handler = handleObjIn.handler;
                selector = handleObjIn.selector;
            }
            // Ensure that invalid selectors throw exceptions at attach time
            // Evaluate against documentElement in case elem is a non-element node (e.g., document)
            if (selector) {
                jQuery.find.matchesSelector(documentElement, selector);
            }
            // Make sure that the handler has a unique ID, used to find/remove it later
            if (!handler.guid) {
                handler.guid = jQuery.guid++;
            }
            // Init the element's event structure and main handler, if this is the first
            if (!(events = elemData.events)) {
                events = elemData.events = {};
            }
            if (!(eventHandle = elemData.handle)) {
                eventHandle = elemData.handle = function (e) {
                    // Discard the second event of a jQuery.event.trigger() and
                    // when an event is called after a page has unloaded
                    return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ?
                        jQuery.event.dispatch.apply(elem, arguments) : undefined;
                };
            }
            // Handle multiple events separated by a space
            types = (types || "").match(rnothtmlwhite) || [""];
            t = types.length;
            while (t--) {
                tmp = rtypenamespace.exec(types[t]) || [];
                type = origType = tmp[1];
                namespaces = (tmp[2] || "").split(".").sort();
                // There *must* be a type, no attaching namespace-only handlers
                if (!type) {
                    continue;
                }
                // If event changes its type, use the special event handlers for the changed type
                special = jQuery.event.special[type] || {};
                // If selector defined, determine special event api type, otherwise given type
                type = (selector ? special.delegateType : special.bindType) || type;
                // Update special based on newly reset type
                special = jQuery.event.special[type] || {};
                // handleObj is passed to all event handlers
                handleObj = jQuery.extend({
                    type: type,
                    origType: origType,
                    data: data,
                    handler: handler,
                    guid: handler.guid,
                    selector: selector,
                    needsContext: selector && jQuery.expr.match.needsContext.test(selector),
                    namespace: namespaces.join(".")
                }, handleObjIn);
                // Init the event handler queue if we're the first
                if (!(handlers = events[type])) {
                    handlers = events[type] = [];
                    handlers.delegateCount = 0;
                    // Only use addEventListener if the special events handler returns false
                    if (!special.setup ||
                        special.setup.call(elem, data, namespaces, eventHandle) === false) {
                        if (elem.addEventListener) {
                            elem.addEventListener(type, eventHandle);
                        }
                    }
                }
                if (special.add) {
                    special.add.call(elem, handleObj);
                    if (!handleObj.handler.guid) {
                        handleObj.handler.guid = handler.guid;
                    }
                }
                // Add to the element's handler list, delegates in front
                if (selector) {
                    handlers.splice(handlers.delegateCount++, 0, handleObj);
                }
                else {
                    handlers.push(handleObj);
                }
                // Keep track of which events have ever been used, for event optimization
                jQuery.event.global[type] = true;
            }
        },
        // Detach an event or set of events from an element
        remove: function (elem, types, handler, selector, mappedTypes) {
            var j, origCount, tmp, events, t, handleObj, special, handlers, type, namespaces, origType, elemData = dataPriv.hasData(elem) && dataPriv.get(elem);
            if (!elemData || !(events = elemData.events)) {
                return;
            }
            // Once for each type.namespace in types; type may be omitted
            types = (types || "").match(rnothtmlwhite) || [""];
            t = types.length;
            while (t--) {
                tmp = rtypenamespace.exec(types[t]) || [];
                type = origType = tmp[1];
                namespaces = (tmp[2] || "").split(".").sort();
                // Unbind all events (on this namespace, if provided) for the element
                if (!type) {
                    for (type in events) {
                        jQuery.event.remove(elem, type + types[t], handler, selector, true);
                    }
                    continue;
                }
                special = jQuery.event.special[type] || {};
                type = (selector ? special.delegateType : special.bindType) || type;
                handlers = events[type] || [];
                tmp = tmp[2] &&
                    new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)");
                // Remove matching events
                origCount = j = handlers.length;
                while (j--) {
                    handleObj = handlers[j];
                    if ((mappedTypes || origType === handleObj.origType) &&
                        (!handler || handler.guid === handleObj.guid) &&
                        (!tmp || tmp.test(handleObj.namespace)) &&
                        (!selector || selector === handleObj.selector ||
                            selector === "**" && handleObj.selector)) {
                        handlers.splice(j, 1);
                        if (handleObj.selector) {
                            handlers.delegateCount--;
                        }
                        if (special.remove) {
                            special.remove.call(elem, handleObj);
                        }
                    }
                }
                // Remove generic event handler if we removed something and no more handlers exist
                // (avoids potential for endless recursion during removal of special event handlers)
                if (origCount && !handlers.length) {
                    if (!special.teardown ||
                        special.teardown.call(elem, namespaces, elemData.handle) === false) {
                        jQuery.removeEvent(elem, type, elemData.handle);
                    }
                    delete events[type];
                }
            }
            // Remove data and the expando if it's no longer used
            if (jQuery.isEmptyObject(events)) {
                dataPriv.remove(elem, "handle events");
            }
        },
        dispatch: function (nativeEvent) {
            // Make a writable jQuery.Event from the native event object
            var event = jQuery.event.fix(nativeEvent);
            var i, j, ret, matched, handleObj, handlerQueue, args = new Array(arguments.length), handlers = (dataPriv.get(this, "events") || {})[event.type] || [], special = jQuery.event.special[event.type] || {};
            // Use the fix-ed jQuery.Event rather than the (read-only) native event
            args[0] = event;
            for (i = 1; i < arguments.length; i++) {
                args[i] = arguments[i];
            }
            event.delegateTarget = this;
            // Call the preDispatch hook for the mapped type, and let it bail if desired
            if (special.preDispatch && special.preDispatch.call(this, event) === false) {
                return;
            }
            // Determine handlers
            handlerQueue = jQuery.event.handlers.call(this, event, handlers);
            // Run delegates first; they may want to stop propagation beneath us
            i = 0;
            while ((matched = handlerQueue[i++]) && !event.isPropagationStopped()) {
                event.currentTarget = matched.elem;
                j = 0;
                while ((handleObj = matched.handlers[j++]) &&
                    !event.isImmediatePropagationStopped()) {
                    // Triggered event must either 1) have no namespace, or 2) have namespace(s)
                    // a subset or equal to those in the bound event (both can have no namespace).
                    if (!event.rnamespace || event.rnamespace.test(handleObj.namespace)) {
                        event.handleObj = handleObj;
                        event.data = handleObj.data;
                        ret = ((jQuery.event.special[handleObj.origType] || {}).handle ||
                            handleObj.handler).apply(matched.elem, args);
                        if (ret !== undefined) {
                            if ((event.result = ret) === false) {
                                event.preventDefault();
                                event.stopPropagation();
                            }
                        }
                    }
                }
            }
            // Call the postDispatch hook for the mapped type
            if (special.postDispatch) {
                special.postDispatch.call(this, event);
            }
            return event.result;
        },
        handlers: function (event, handlers) {
            var i, handleObj, sel, matchedHandlers, matchedSelectors, handlerQueue = [], delegateCount = handlers.delegateCount, cur = event.target;
            // Find delegate handlers
            if (delegateCount &&
                // Support: IE <=9
                // Black-hole SVG <use> instance trees (trac-13180)
                cur.nodeType &&
                // Support: Firefox <=42
                // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861)
                // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click
                // Support: IE 11 only
                // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343)
                !(event.type === "click" && event.button >= 1)) {
                for (; cur !== this; cur = cur.parentNode || this) {
                    // Don't check non-elements (#13208)
                    // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)
                    if (cur.nodeType === 1 && !(event.type === "click" && cur.disabled === true)) {
                        matchedHandlers = [];
                        matchedSelectors = {};
                        for (i = 0; i < delegateCount; i++) {
                            handleObj = handlers[i];
                            // Don't conflict with Object.prototype properties (#13203)
                            sel = handleObj.selector + " ";
                            if (matchedSelectors[sel] === undefined) {
                                matchedSelectors[sel] = handleObj.needsContext ?
                                    jQuery(sel, this).index(cur) > -1 :
                                    jQuery.find(sel, this, null, [cur]).length;
                            }
                            if (matchedSelectors[sel]) {
                                matchedHandlers.push(handleObj);
                            }
                        }
                        if (matchedHandlers.length) {
                            handlerQueue.push({ elem: cur, handlers: matchedHandlers });
                        }
                    }
                }
            }
            // Add the remaining (directly-bound) handlers
            cur = this;
            if (delegateCount < handlers.length) {
                handlerQueue.push({ elem: cur, handlers: handlers.slice(delegateCount) });
            }
            return handlerQueue;
        },
        addProp: function (name, hook) {
            Object.defineProperty(jQuery.Event.prototype, name, {
                enumerable: true,
                configurable: true,
                get: jQuery.isFunction(hook) ?
                    function () {
                        if (this.originalEvent) {
                            return hook(this.originalEvent);
                        }
                    } :
                    function () {
                        if (this.originalEvent) {
                            return this.originalEvent[name];
                        }
                    },
                set: function (value) {
                    Object.defineProperty(this, name, {
                        enumerable: true,
                        configurable: true,
                        writable: true,
                        value: value
                    });
                }
            });
        },
        fix: function (originalEvent) {
            return originalEvent[jQuery.expando] ?
                originalEvent :
                new jQuery.Event(originalEvent);
        },
        special: {
            load: {
                // Prevent triggered image.load events from bubbling to window.load
                noBubble: true
            },
            focus: {
                // Fire native event if possible so blur/focus sequence is correct
                trigger: function () {
                    if (this !== safeActiveElement() && this.focus) {
                        this.focus();
                        return false;
                    }
                },
                delegateType: "focusin"
            },
            blur: {
                trigger: function () {
                    if (this === safeActiveElement() && this.blur) {
                        this.blur();
                        return false;
                    }
                },
                delegateType: "focusout"
            },
            click: {
                // For checkbox, fire native event so checked state will be right
                trigger: function () {
                    if (this.type === "checkbox" && this.click && jQuery.nodeName(this, "input")) {
                        this.click();
                        return false;
                    }
                },
                // For cross-browser consistency, don't fire native .click() on links
                _default: function (event) {
                    return jQuery.nodeName(event.target, "a");
                }
            },
            beforeunload: {
                postDispatch: function (event) {
                    // Support: Firefox 20+
                    // Firefox doesn't alert if the returnValue field is not set.
                    if (event.result !== undefined && event.originalEvent) {
                        event.originalEvent.returnValue = event.result;
                    }
                }
            }
        }
    };
    jQuery.removeEvent = function (elem, type, handle) {
        // This "if" is needed for plain objects
        if (elem.removeEventListener) {
            elem.removeEventListener(type, handle);
        }
    };
    jQuery.Event = function (src, props) {
        // Allow instantiation without the 'new' keyword
        if (!(this instanceof jQuery.Event)) {
            return new jQuery.Event(src, props);
        }
        // Event object
        if (src && src.type) {
            this.originalEvent = src;
            this.type = src.type;
            // Events bubbling up the document may have been marked as prevented
            // by a handler lower down the tree; reflect the correct value.
            this.isDefaultPrevented = src.defaultPrevented ||
                src.defaultPrevented === undefined &&
                    // Support: Android <=2.3 only
                    src.returnValue === false ?
                returnTrue :
                returnFalse;
            // Create target properties
            // Support: Safari <=6 - 7 only
            // Target should not be a text node (#504, #13143)
            this.target = (src.target && src.target.nodeType === 3) ?
                src.target.parentNode :
                src.target;
            this.currentTarget = src.currentTarget;
            this.relatedTarget = src.relatedTarget;
        }
        else {
            this.type = src;
        }
        // Put explicitly provided properties onto the event object
        if (props) {
            jQuery.extend(this, props);
        }
        // Create a timestamp if incoming event doesn't have one
        this.timeStamp = src && src.timeStamp || jQuery.now();
        // Mark it as fixed
        this[jQuery.expando] = true;
    };
    // jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
    // https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
    jQuery.Event.prototype = {
        constructor: jQuery.Event,
        isDefaultPrevented: returnFalse,
        isPropagationStopped: returnFalse,
        isImmediatePropagationStopped: returnFalse,
        isSimulated: false,
        preventDefault: function () {
            var e = this.originalEvent;
            this.isDefaultPrevented = returnTrue;
            if (e && !this.isSimulated) {
                e.preventDefault();
            }
        },
        stopPropagation: function () {
            var e = this.originalEvent;
            this.isPropagationStopped = returnTrue;
            if (e && !this.isSimulated) {
                e.stopPropagation();
            }
        },
        stopImmediatePropagation: function () {
            var e = this.originalEvent;
            this.isImmediatePropagationStopped = returnTrue;
            if (e && !this.isSimulated) {
                e.stopImmediatePropagation();
            }
            this.stopPropagation();
        }
    };
    // Includes all common event props including KeyEvent and MouseEvent specific props
    jQuery.each({
        altKey: true,
        bubbles: true,
        cancelable: true,
        changedTouches: true,
        ctrlKey: true,
        detail: true,
        eventPhase: true,
        metaKey: true,
        pageX: true,
        pageY: true,
        shiftKey: true,
        view: true,
        "char": true,
        charCode: true,
        key: true,
        keyCode: true,
        button: true,
        buttons: true,
        clientX: true,
        clientY: true,
        offsetX: true,
        offsetY: true,
        pointerId: true,
        pointerType: true,
        screenX: true,
        screenY: true,
        targetTouches: true,
        toElement: true,
        touches: true,
        which: function (event) {
            var button = event.button;
            // Add which for key events
            if (event.which == null && rkeyEvent.test(event.type)) {
                return event.charCode != null ? event.charCode : event.keyCode;
            }
            // Add which for click: 1 === left; 2 === middle; 3 === right
            if (!event.which && button !== undefined && rmouseEvent.test(event.type)) {
                if (button & 1) {
                    return 1;
                }
                if (button & 2) {
                    return 3;
                }
                if (button & 4) {
                    return 2;
                }
                return 0;
            }
            return event.which;
        }
    }, jQuery.event.addProp);
    // Create mouseenter/leave events using mouseover/out and event-time checks
    // so that event delegation works in jQuery.
    // Do the same for pointerenter/pointerleave and pointerover/pointerout
    //
    // Support: Safari 7 only
    // Safari sends mouseenter too often; see:
    // https://bugs.chromium.org/p/chromium/issues/detail?id=470258
    // for the description of the bug (it existed in older Chrome versions as well).
    jQuery.each({
        mouseenter: "mouseover",
        mouseleave: "mouseout",
        pointerenter: "pointerover",
        pointerleave: "pointerout"
    }, function (orig, fix) {
        jQuery.event.special[orig] = {
            delegateType: fix,
            bindType: fix,
            handle: function (event) {
                var ret, target = this, related = event.relatedTarget, handleObj = event.handleObj;
                // For mouseenter/leave call the handler if related is outside the target.
                // NB: No relatedTarget if the mouse left/entered the browser window
                if (!related || (related !== target && !jQuery.contains(target, related))) {
                    event.type = handleObj.origType;
                    ret = handleObj.handler.apply(this, arguments);
                    event.type = fix;
                }
                return ret;
            }
        };
    });
    jQuery.fn.extend({
        on: function (types, selector, data, fn) {
            return on(this, types, selector, data, fn);
        },
        one: function (types, selector, data, fn) {
            return on(this, types, selector, data, fn, 1);
        },
        off: function (types, selector, fn) {
            var handleObj, type;
            if (types && types.preventDefault && types.handleObj) {
                // ( event )  dispatched jQuery.Event
                handleObj = types.handleObj;
                jQuery(types.delegateTarget).off(handleObj.namespace ?
                    handleObj.origType + "." + handleObj.namespace :
                    handleObj.origType, handleObj.selector, handleObj.handler);
                return this;
            }
            if (typeof types === "object") {
                // ( types-object [, selector] )
                for (type in types) {
                    this.off(type, selector, types[type]);
                }
                return this;
            }
            if (selector === false || typeof selector === "function") {
                // ( types [, fn] )
                fn = selector;
                selector = undefined;
            }
            if (fn === false) {
                fn = returnFalse;
            }
            return this.each(function () {
                jQuery.event.remove(this, types, fn, selector);
            });
        }
    });
    var 
    /* eslint-disable max-len */
    // See https://github.com/eslint/eslint/issues/3229
    rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi, 
    /* eslint-enable */
    // Support: IE <=10 - 11, Edge 12 - 13
    // In IE/Edge using regex groups here causes severe slowdowns.
    // See https://connect.microsoft.com/IE/feedback/details/1736512/
    rnoInnerhtml = /<script|<style|<link/i, 
    // checked="checked" or checked
    rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i, rscriptTypeMasked = /^true\/(.*)/, rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g;
    function manipulationTarget(elem, content) {
        if (jQuery.nodeName(elem, "table") &&
            jQuery.nodeName(content.nodeType !== 11 ? content : content.firstChild, "tr")) {
            return elem.getElementsByTagName("tbody")[0] || elem;
        }
        return elem;
    }
    // Replace/restore the type attribute of script elements for safe DOM manipulation
    function disableScript(elem) {
        elem.type = (elem.getAttribute("type") !== null) + "/" + elem.type;
        return elem;
    }
    function restoreScript(elem) {
        var match = rscriptTypeMasked.exec(elem.type);
        if (match) {
            elem.type = match[1];
        }
        else {
            elem.removeAttribute("type");
        }
        return elem;
    }
    function cloneCopyEvent(src, dest) {
        var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events;
        if (dest.nodeType !== 1) {
            return;
        }
        // 1. Copy private data: events, handlers, etc.
        if (dataPriv.hasData(src)) {
            pdataOld = dataPriv.access(src);
            pdataCur = dataPriv.set(dest, pdataOld);
            events = pdataOld.events;
            if (events) {
                delete pdataCur.handle;
                pdataCur.events = {};
                for (type in events) {
                    for (i = 0, l = events[type].length; i < l; i++) {
                        jQuery.event.add(dest, type, events[type][i]);
                    }
                }
            }
        }
        // 2. Copy user data
        if (dataUser.hasData(src)) {
            udataOld = dataUser.access(src);
            udataCur = jQuery.extend({}, udataOld);
            dataUser.set(dest, udataCur);
        }
    }
    // Fix IE bugs, see support tests
    function fixInput(src, dest) {
        var nodeName = dest.nodeName.toLowerCase();
        // Fails to persist the checked state of a cloned checkbox or radio button.
        if (nodeName === "input" && rcheckableType.test(src.type)) {
            dest.checked = src.checked;
        }
        else if (nodeName === "input" || nodeName === "textarea") {
            dest.defaultValue = src.defaultValue;
        }
    }
    function domManip(collection, args, callback, ignored) {
        // Flatten any nested arrays
        args = concat.apply([], args);
        var fragment, first, scripts, hasScripts, node, doc, i = 0, l = collection.length, iNoClone = l - 1, value = args[0], isFunction = jQuery.isFunction(value);
        // We can't cloneNode fragments that contain checked, in WebKit
        if (isFunction ||
            (l > 1 && typeof value === "string" &&
                !support.checkClone && rchecked.test(value))) {
            return collection.each(function (index) {
                var self = collection.eq(index);
                if (isFunction) {
                    args[0] = value.call(this, index, self.html());
                }
                domManip(self, args, callback, ignored);
            });
        }
        if (l) {
            fragment = buildFragment(args, collection[0].ownerDocument, false, collection, ignored);
            first = fragment.firstChild;
            if (fragment.childNodes.length === 1) {
                fragment = first;
            }
            // Require either new content or an interest in ignored elements to invoke the callback
            if (first || ignored) {
                scripts = jQuery.map(getAll(fragment, "script"), disableScript);
                hasScripts = scripts.length;
                // Use the original fragment for the last item
                // instead of the first because it can end up
                // being emptied incorrectly in certain situations (#8070).
                for (; i < l; i++) {
                    node = fragment;
                    if (i !== iNoClone) {
                        node = jQuery.clone(node, true, true);
                        // Keep references to cloned scripts for later restoration
                        if (hasScripts) {
                            // Support: Android <=4.0 only, PhantomJS 1 only
                            // push.apply(_, arraylike) throws on ancient WebKit
                            jQuery.merge(scripts, getAll(node, "script"));
                        }
                    }
                    callback.call(collection[i], node, i);
                }
                if (hasScripts) {
                    doc = scripts[scripts.length - 1].ownerDocument;
                    // Reenable scripts
                    jQuery.map(scripts, restoreScript);
                    // Evaluate executable scripts on first document insertion
                    for (i = 0; i < hasScripts; i++) {
                        node = scripts[i];
                        if (rscriptType.test(node.type || "") &&
                            !dataPriv.access(node, "globalEval") &&
                            jQuery.contains(doc, node)) {
                            if (node.src) {
                                // Optional AJAX dependency, but won't run scripts if not present
                                if (jQuery._evalUrl) {
                                    jQuery._evalUrl(node.src);
                                }
                            }
                            else {
                                DOMEval(node.textContent.replace(rcleanScript, ""), doc);
                            }
                        }
                    }
                }
            }
        }
        return collection;
    }
    function remove(elem, selector, keepData) {
        var node, nodes = selector ? jQuery.filter(selector, elem) : elem, i = 0;
        for (; (node = nodes[i]) != null; i++) {
            if (!keepData && node.nodeType === 1) {
                jQuery.cleanData(getAll(node));
            }
            if (node.parentNode) {
                if (keepData && jQuery.contains(node.ownerDocument, node)) {
                    setGlobalEval(getAll(node, "script"));
                }
                node.parentNode.removeChild(node);
            }
        }
        return elem;
    }
    jQuery.extend({
        htmlPrefilter: function (html) {
            return html.replace(rxhtmlTag, "<$1></$2>");
        },
        clone: function (elem, dataAndEvents, deepDataAndEvents) {
            var i, l, srcElements, destElements, clone = elem.cloneNode(true), inPage = jQuery.contains(elem.ownerDocument, elem);
            // Fix IE cloning issues
            if (!support.noCloneChecked && (elem.nodeType === 1 || elem.nodeType === 11) &&
                !jQuery.isXMLDoc(elem)) {
                // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2
                destElements = getAll(clone);
                srcElements = getAll(elem);
                for (i = 0, l = srcElements.length; i < l; i++) {
                    fixInput(srcElements[i], destElements[i]);
                }
            }
            // Copy the events from the original to the clone
            if (dataAndEvents) {
                if (deepDataAndEvents) {
                    srcElements = srcElements || getAll(elem);
                    destElements = destElements || getAll(clone);
                    for (i = 0, l = srcElements.length; i < l; i++) {
                        cloneCopyEvent(srcElements[i], destElements[i]);
                    }
                }
                else {
                    cloneCopyEvent(elem, clone);
                }
            }
            // Preserve script evaluation history
            destElements = getAll(clone, "script");
            if (destElements.length > 0) {
                setGlobalEval(destElements, !inPage && getAll(elem, "script"));
            }
            // Return the cloned set
            return clone;
        },
        cleanData: function (elems) {
            var data, elem, type, special = jQuery.event.special, i = 0;
            for (; (elem = elems[i]) !== undefined; i++) {
                if (acceptData(elem)) {
                    if ((data = elem[dataPriv.expando])) {
                        if (data.events) {
                            for (type in data.events) {
                                if (special[type]) {
                                    jQuery.event.remove(elem, type);
                                }
                                else {
                                    jQuery.removeEvent(elem, type, data.handle);
                                }
                            }
                        }
                        // Support: Chrome <=35 - 45+
                        // Assign undefined instead of using delete, see Data#remove
                        elem[dataPriv.expando] = undefined;
                    }
                    if (elem[dataUser.expando]) {
                        // Support: Chrome <=35 - 45+
                        // Assign undefined instead of using delete, see Data#remove
                        elem[dataUser.expando] = undefined;
                    }
                }
            }
        }
    });
    jQuery.fn.extend({
        detach: function (selector) {
            return remove(this, selector, true);
        },
        remove: function (selector) {
            return remove(this, selector);
        },
        text: function (value) {
            return access(this, function (value) {
                return value === undefined ?
                    jQuery.text(this) :
                    this.empty().each(function () {
                        if (this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9) {
                            this.textContent = value;
                        }
                    });
            }, null, value, arguments.length);
        },
        append: function () {
            return domManip(this, arguments, function (elem) {
                if (this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9) {
                    var target = manipulationTarget(this, elem);
                    target.appendChild(elem);
                }
            });
        },
        prepend: function () {
            return domManip(this, arguments, function (elem) {
                if (this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9) {
                    var target = manipulationTarget(this, elem);
                    target.insertBefore(elem, target.firstChild);
                }
            });
        },
        before: function () {
            return domManip(this, arguments, function (elem) {
                if (this.parentNode) {
                    this.parentNode.insertBefore(elem, this);
                }
            });
        },
        after: function () {
            return domManip(this, arguments, function (elem) {
                if (this.parentNode) {
                    this.parentNode.insertBefore(elem, this.nextSibling);
                }
            });
        },
        empty: function () {
            var elem, i = 0;
            for (; (elem = this[i]) != null; i++) {
                if (elem.nodeType === 1) {
                    // Prevent memory leaks
                    jQuery.cleanData(getAll(elem, false));
                    // Remove any remaining nodes
                    elem.textContent = "";
                }
            }
            return this;
        },
        clone: function (dataAndEvents, deepDataAndEvents) {
            dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
            deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
            return this.map(function () {
                return jQuery.clone(this, dataAndEvents, deepDataAndEvents);
            });
        },
        html: function (value) {
            return access(this, function (value) {
                var elem = this[0] || {}, i = 0, l = this.length;
                if (value === undefined && elem.nodeType === 1) {
                    return elem.innerHTML;
                }
                // See if we can take a shortcut and just use innerHTML
                if (typeof value === "string" && !rnoInnerhtml.test(value) &&
                    !wrapMap[(rtagName.exec(value) || ["", ""])[1].toLowerCase()]) {
                    value = jQuery.htmlPrefilter(value);
                    try {
                        for (; i < l; i++) {
                            elem = this[i] || {};
                            // Remove element nodes and prevent memory leaks
                            if (elem.nodeType === 1) {
                                jQuery.cleanData(getAll(elem, false));
                                elem.innerHTML = value;
                            }
                        }
                        elem = 0;
                    }
                    catch (e) { }
                }
                if (elem) {
                    this.empty().append(value);
                }
            }, null, value, arguments.length);
        },
        replaceWith: function () {
            var ignored = [];
            // Make the changes, replacing each non-ignored context element with the new content
            return domManip(this, arguments, function (elem) {
                var parent = this.parentNode;
                if (jQuery.inArray(this, ignored) < 0) {
                    jQuery.cleanData(getAll(this));
                    if (parent) {
                        parent.replaceChild(elem, this);
                    }
                }
                // Force callback invocation
            }, ignored);
        }
    });
    jQuery.each({
        appendTo: "append",
        prependTo: "prepend",
        insertBefore: "before",
        insertAfter: "after",
        replaceAll: "replaceWith"
    }, function (name, original) {
        jQuery.fn[name] = function (selector) {
            var elems, ret = [], insert = jQuery(selector), last = insert.length - 1, i = 0;
            for (; i <= last; i++) {
                elems = i === last ? this : this.clone(true);
                jQuery(insert[i])[original](elems);
                // Support: Android <=4.0 only, PhantomJS 1 only
                // .get() because push.apply(_, arraylike) throws on ancient WebKit
                push.apply(ret, elems.get());
            }
            return this.pushStack(ret);
        };
    });
    var rmargin = (/^margin/);
    var rnumnonpx = new RegExp("^(" + pnum + ")(?!px)[a-z%]+$", "i");
    var getStyles = function (elem) {
        // Support: IE <=11 only, Firefox <=30 (#15098, #14150)
        // IE throws on elements created in popups
        // FF meanwhile throws on frame elements through "defaultView.getComputedStyle"
        var view = elem.ownerDocument.defaultView;
        if (!view || !view.opener) {
            view = window;
        }
        return view.getComputedStyle(elem);
    };
    (function () {
        // Executing both pixelPosition & boxSizingReliable tests require only one layout
        // so they're executed at the same time to save the second computation.
        function computeStyleTests() {
            // This is a singleton, we need to execute it only once
            if (!div) {
                return;
            }
            div.style.cssText =
                "box-sizing:border-box;" +
                    "position:relative;display:block;" +
                    "margin:auto;border:1px;padding:1px;" +
                    "top:1%;width:50%";
            div.innerHTML = "";
            documentElement.appendChild(container);
            var divStyle = window.getComputedStyle(div);
            pixelPositionVal = divStyle.top !== "1%";
            // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44
            reliableMarginLeftVal = divStyle.marginLeft === "2px";
            boxSizingReliableVal = divStyle.width === "4px";
            // Support: Android 4.0 - 4.3 only
            // Some styles come back with percentage values, even though they shouldn't
            div.style.marginRight = "50%";
            pixelMarginRightVal = divStyle.marginRight === "4px";
            documentElement.removeChild(container);
            // Nullify the div so it wouldn't be stored in the memory and
            // it will also be a sign that checks already performed
            div = null;
        }
        var pixelPositionVal, boxSizingReliableVal, pixelMarginRightVal, reliableMarginLeftVal, container = document.createElement("div"), div = document.createElement("div");
        // Finish early in limited (non-browser) environments
        if (!div.style) {
            return;
        }
        // Support: IE <=9 - 11 only
        // Style of cloned element affects source element cloned (#8908)
        div.style.backgroundClip = "content-box";
        div.cloneNode(true).style.backgroundClip = "";
        support.clearCloneStyle = div.style.backgroundClip === "content-box";
        container.style.cssText = "border:0;width:8px;height:0;top:0;left:-9999px;" +
            "padding:0;margin-top:1px;position:absolute";
        container.appendChild(div);
        jQuery.extend(support, {
            pixelPosition: function () {
                computeStyleTests();
                return pixelPositionVal;
            },
            boxSizingReliable: function () {
                computeStyleTests();
                return boxSizingReliableVal;
            },
            pixelMarginRight: function () {
                computeStyleTests();
                return pixelMarginRightVal;
            },
            reliableMarginLeft: function () {
                computeStyleTests();
                return reliableMarginLeftVal;
            }
        });
    })();
    function curCSS(elem, name, computed) {
        var width, minWidth, maxWidth, ret, style = elem.style;
        computed = computed || getStyles(elem);
        // Support: IE <=9 only
        // getPropertyValue is only needed for .css('filter') (#12537)
        if (computed) {
            ret = computed.getPropertyValue(name) || computed[name];
            if (ret === "" && !jQuery.contains(elem.ownerDocument, elem)) {
                ret = jQuery.style(elem, name);
            }
            // A tribute to the "awesome hack by Dean Edwards"
            // Android Browser returns percentage for some values,
            // but width seems to be reliably pixels.
            // This is against the CSSOM draft spec:
            // https://drafts.csswg.org/cssom/#resolved-values
            if (!support.pixelMarginRight() && rnumnonpx.test(ret) && rmargin.test(name)) {
                // Remember the original values
                width = style.width;
                minWidth = style.minWidth;
                maxWidth = style.maxWidth;
                // Put in the new values to get a computed value out
                style.minWidth = style.maxWidth = style.width = ret;
                ret = computed.width;
                // Revert the changed values
                style.width = width;
                style.minWidth = minWidth;
                style.maxWidth = maxWidth;
            }
        }
        return ret !== undefined ?
            // Support: IE <=9 - 11 only
            // IE returns zIndex value as an integer.
            ret + "" :
            ret;
    }
    function addGetHookIf(conditionFn, hookFn) {
        // Define the hook, we'll check on the first run if it's really needed.
        return {
            get: function () {
                if (conditionFn()) {
                    // Hook not needed (or it's not possible to use it due
                    // to missing dependency), remove it.
                    delete this.get;
                    return;
                }
                // Hook needed; redefine it so that the support test is not executed again.
                return (this.get = hookFn).apply(this, arguments);
            }
        };
    }
    var 
    // Swappable if display is none or starts with table
    // except "table", "table-cell", or "table-caption"
    // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
    rdisplayswap = /^(none|table(?!-c[ea]).+)/, cssShow = { position: "absolute", visibility: "hidden", display: "block" }, cssNormalTransform = {
        letterSpacing: "0",
        fontWeight: "400"
    }, cssPrefixes = ["Webkit", "Moz", "ms"], emptyStyle = document.createElement("div").style;
    // Return a css property mapped to a potentially vendor prefixed property
    function vendorPropName(name) {
        // Shortcut for names that are not vendor prefixed
        if (name in emptyStyle) {
            return name;
        }
        // Check for vendor prefixed names
        var capName = name[0].toUpperCase() + name.slice(1), i = cssPrefixes.length;
        while (i--) {
            name = cssPrefixes[i] + capName;
            if (name in emptyStyle) {
                return name;
            }
        }
    }
    function setPositiveNumber(elem, value, subtract) {
        // Any relative (+/-) values have already been
        // normalized at this point
        var matches = rcssNum.exec(value);
        return matches ?
            // Guard against undefined "subtract", e.g., when used as in cssHooks
            Math.max(0, matches[2] - (subtract || 0)) + (matches[3] || "px") :
            value;
    }
    function augmentWidthOrHeight(elem, name, extra, isBorderBox, styles) {
        var i, val = 0;
        // If we already have the right measurement, avoid augmentation
        if (extra === (isBorderBox ? "border" : "content")) {
            i = 4;
        }
        else {
            i = name === "width" ? 1 : 0;
        }
        for (; i < 4; i += 2) {
            // Both box models exclude margin, so add it if we want it
            if (extra === "margin") {
                val += jQuery.css(elem, extra + cssExpand[i], true, styles);
            }
            if (isBorderBox) {
                // border-box includes padding, so remove it if we want content
                if (extra === "content") {
                    val -= jQuery.css(elem, "padding" + cssExpand[i], true, styles);
                }
                // At this point, extra isn't border nor margin, so remove border
                if (extra !== "margin") {
                    val -= jQuery.css(elem, "border" + cssExpand[i] + "Width", true, styles);
                }
            }
            else {
                // At this point, extra isn't content, so add padding
                val += jQuery.css(elem, "padding" + cssExpand[i], true, styles);
                // At this point, extra isn't content nor padding, so add border
                if (extra !== "padding") {
                    val += jQuery.css(elem, "border" + cssExpand[i] + "Width", true, styles);
                }
            }
        }
        return val;
    }
    function getWidthOrHeight(elem, name, extra) {
        // Start with offset property, which is equivalent to the border-box value
        var val, valueIsBorderBox = true, styles = getStyles(elem), isBorderBox = jQuery.css(elem, "boxSizing", false, styles) === "border-box";
        // Support: IE <=11 only
        // Running getBoundingClientRect on a disconnected node
        // in IE throws an error.
        if (elem.getClientRects().length) {
            val = elem.getBoundingClientRect()[name];
        }
        // Some non-html elements return undefined for offsetWidth, so check for null/undefined
        // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
        // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
        if (val <= 0 || val == null) {
            // Fall back to computed then uncomputed css if necessary
            val = curCSS(elem, name, styles);
            if (val < 0 || val == null) {
                val = elem.style[name];
            }
            // Computed unit is not pixels. Stop here and return.
            if (rnumnonpx.test(val)) {
                return val;
            }
            // Check for style in case a browser which returns unreliable values
            // for getComputedStyle silently falls back to the reliable elem.style
            valueIsBorderBox = isBorderBox &&
                (support.boxSizingReliable() || val === elem.style[name]);
            // Normalize "", auto, and prepare for extra
            val = parseFloat(val) || 0;
        }
        // Use the active box-sizing model to add/subtract irrelevant styles
        return (val +
            augmentWidthOrHeight(elem, name, extra || (isBorderBox ? "border" : "content"), valueIsBorderBox, styles)) + "px";
    }
    jQuery.extend({
        // Add in style property hooks for overriding the default
        // behavior of getting and setting a style property
        cssHooks: {
            opacity: {
                get: function (elem, computed) {
                    if (computed) {
                        // We should always get a number back from opacity
                        var ret = curCSS(elem, "opacity");
                        return ret === "" ? "1" : ret;
                    }
                }
            }
        },
        // Don't automatically add "px" to these possibly-unitless properties
        cssNumber: {
            "animationIterationCount": true,
            "columnCount": true,
            "fillOpacity": true,
            "flexGrow": true,
            "flexShrink": true,
            "fontWeight": true,
            "lineHeight": true,
            "opacity": true,
            "order": true,
            "orphans": true,
            "widows": true,
            "zIndex": true,
            "zoom": true
        },
        // Add in properties whose names you wish to fix before
        // setting or getting the value
        cssProps: {
            "float": "cssFloat"
        },
        // Get and set the style property on a DOM Node
        style: function (elem, name, value, extra) {
            // Don't set styles on text and comment nodes
            if (!elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style) {
                return;
            }
            // Make sure that we're working with the right name
            var ret, type, hooks, origName = jQuery.camelCase(name), style = elem.style;
            name = jQuery.cssProps[origName] ||
                (jQuery.cssProps[origName] = vendorPropName(origName) || origName);
            // Gets hook for the prefixed version, then unprefixed version
            hooks = jQuery.cssHooks[name] || jQuery.cssHooks[origName];
            // Check if we're setting a value
            if (value !== undefined) {
                type = typeof value;
                // Convert "+=" or "-=" to relative numbers (#7345)
                if (type === "string" && (ret = rcssNum.exec(value)) && ret[1]) {
                    value = adjustCSS(elem, name, ret);
                    // Fixes bug #9237
                    type = "number";
                }
                // Make sure that null and NaN values aren't set (#7116)
                if (value == null || value !== value) {
                    return;
                }
                // If a number was passed in, add the unit (except for certain CSS properties)
                if (type === "number") {
                    value += ret && ret[3] || (jQuery.cssNumber[origName] ? "" : "px");
                }
                // background-* props affect original clone's values
                if (!support.clearCloneStyle && value === "" && name.indexOf("background") === 0) {
                    style[name] = "inherit";
                }
                // If a hook was provided, use that value, otherwise just set the specified value
                if (!hooks || !("set" in hooks) ||
                    (value = hooks.set(elem, value, extra)) !== undefined) {
                    style[name] = value;
                }
            }
            else {
                // If a hook was provided get the non-computed value from there
                if (hooks && "get" in hooks &&
                    (ret = hooks.get(elem, false, extra)) !== undefined) {
                    return ret;
                }
                // Otherwise just get the value from the style object
                return style[name];
            }
        },
        css: function (elem, name, extra, styles) {
            var val, num, hooks, origName = jQuery.camelCase(name);
            // Make sure that we're working with the right name
            name = jQuery.cssProps[origName] ||
                (jQuery.cssProps[origName] = vendorPropName(origName) || origName);
            // Try prefixed name followed by the unprefixed name
            hooks = jQuery.cssHooks[name] || jQuery.cssHooks[origName];
            // If a hook was provided get the computed value from there
            if (hooks && "get" in hooks) {
                val = hooks.get(elem, true, extra);
            }
            // Otherwise, if a way to get the computed value exists, use that
            if (val === undefined) {
                val = curCSS(elem, name, styles);
            }
            // Convert "normal" to computed value
            if (val === "normal" && name in cssNormalTransform) {
                val = cssNormalTransform[name];
            }
            // Make numeric if forced or a qualifier was provided and val looks numeric
            if (extra === "" || extra) {
                num = parseFloat(val);
                return extra === true || isFinite(num) ? num || 0 : val;
            }
            return val;
        }
    });
    jQuery.each(["height", "width"], function (i, name) {
        jQuery.cssHooks[name] = {
            get: function (elem, computed, extra) {
                if (computed) {
                    // Certain elements can have dimension info if we invisibly show them
                    // but it must have a current display style that would benefit
                    return rdisplayswap.test(jQuery.css(elem, "display")) &&
                        // Support: Safari 8+
                        // Table columns in Safari have non-zero offsetWidth & zero
                        // getBoundingClientRect().width unless display is changed.
                        // Support: IE <=11 only
                        // Running getBoundingClientRect on a disconnected node
                        // in IE throws an error.
                        (!elem.getClientRects().length || !elem.getBoundingClientRect().width) ?
                        swap(elem, cssShow, function () {
                            return getWidthOrHeight(elem, name, extra);
                        }) :
                        getWidthOrHeight(elem, name, extra);
                }
            },
            set: function (elem, value, extra) {
                var matches, styles = extra && getStyles(elem), subtract = extra && augmentWidthOrHeight(elem, name, extra, jQuery.css(elem, "boxSizing", false, styles) === "border-box", styles);
                // Convert to pixels if value adjustment is needed
                if (subtract && (matches = rcssNum.exec(value)) &&
                    (matches[3] || "px") !== "px") {
                    elem.style[name] = value;
                    value = jQuery.css(elem, name);
                }
                return setPositiveNumber(elem, value, subtract);
            }
        };
    });
    jQuery.cssHooks.marginLeft = addGetHookIf(support.reliableMarginLeft, function (elem, computed) {
        if (computed) {
            return (parseFloat(curCSS(elem, "marginLeft")) ||
                elem.getBoundingClientRect().left -
                    swap(elem, { marginLeft: 0 }, function () {
                        return elem.getBoundingClientRect().left;
                    })) + "px";
        }
    });
    // These hooks are used by animate to expand properties
    jQuery.each({
        margin: "",
        padding: "",
        border: "Width"
    }, function (prefix, suffix) {
        jQuery.cssHooks[prefix + suffix] = {
            expand: function (value) {
                var i = 0, expanded = {}, 
                // Assumes a single number if not a string
                parts = typeof value === "string" ? value.split(" ") : [value];
                for (; i < 4; i++) {
                    expanded[prefix + cssExpand[i] + suffix] =
                        parts[i] || parts[i - 2] || parts[0];
                }
                return expanded;
            }
        };
        if (!rmargin.test(prefix)) {
            jQuery.cssHooks[prefix + suffix].set = setPositiveNumber;
        }
    });
    jQuery.fn.extend({
        css: function (name, value) {
            return access(this, function (elem, name, value) {
                var styles, len, map = {}, i = 0;
                if (jQuery.isArray(name)) {
                    styles = getStyles(elem);
                    len = name.length;
                    for (; i < len; i++) {
                        map[name[i]] = jQuery.css(elem, name[i], false, styles);
                    }
                    return map;
                }
                return value !== undefined ?
                    jQuery.style(elem, name, value) :
                    jQuery.css(elem, name);
            }, name, value, arguments.length > 1);
        }
    });
    function Tween(elem, options, prop, end, easing) {
        return new Tween.prototype.init(elem, options, prop, end, easing);
    }
    jQuery.Tween = Tween;
    Tween.prototype = {
        constructor: Tween,
        init: function (elem, options, prop, end, easing, unit) {
            this.elem = elem;
            this.prop = prop;
            this.easing = easing || jQuery.easing._default;
            this.options = options;
            this.start = this.now = this.cur();
            this.end = end;
            this.unit = unit || (jQuery.cssNumber[prop] ? "" : "px");
        },
        cur: function () {
            var hooks = Tween.propHooks[this.prop];
            return hooks && hooks.get ?
                hooks.get(this) :
                Tween.propHooks._default.get(this);
        },
        run: function (percent) {
            var eased, hooks = Tween.propHooks[this.prop];
            if (this.options.duration) {
                this.pos = eased = jQuery.easing[this.easing](percent, this.options.duration * percent, 0, 1, this.options.duration);
            }
            else {
                this.pos = eased = percent;
            }
            this.now = (this.end - this.start) * eased + this.start;
            if (this.options.step) {
                this.options.step.call(this.elem, this.now, this);
            }
            if (hooks && hooks.set) {
                hooks.set(this);
            }
            else {
                Tween.propHooks._default.set(this);
            }
            return this;
        }
    };
    Tween.prototype.init.prototype = Tween.prototype;
    Tween.propHooks = {
        _default: {
            get: function (tween) {
                var result;
                // Use a property on the element directly when it is not a DOM element,
                // or when there is no matching style property that exists.
                if (tween.elem.nodeType !== 1 ||
                    tween.elem[tween.prop] != null && tween.elem.style[tween.prop] == null) {
                    return tween.elem[tween.prop];
                }
                // Passing an empty string as a 3rd parameter to .css will automatically
                // attempt a parseFloat and fallback to a string if the parse fails.
                // Simple values such as "10px" are parsed to Float;
                // complex values such as "rotate(1rad)" are returned as-is.
                result = jQuery.css(tween.elem, tween.prop, "");
                // Empty strings, null, undefined and "auto" are converted to 0.
                return !result || result === "auto" ? 0 : result;
            },
            set: function (tween) {
                // Use step hook for back compat.
                // Use cssHook if its there.
                // Use .style if available and use plain properties where available.
                if (jQuery.fx.step[tween.prop]) {
                    jQuery.fx.step[tween.prop](tween);
                }
                else if (tween.elem.nodeType === 1 &&
                    (tween.elem.style[jQuery.cssProps[tween.prop]] != null ||
                        jQuery.cssHooks[tween.prop])) {
                    jQuery.style(tween.elem, tween.prop, tween.now + tween.unit);
                }
                else {
                    tween.elem[tween.prop] = tween.now;
                }
            }
        }
    };
    // Support: IE <=9 only
    // Panic based approach to setting things on disconnected nodes
    Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {
        set: function (tween) {
            if (tween.elem.nodeType && tween.elem.parentNode) {
                tween.elem[tween.prop] = tween.now;
            }
        }
    };
    jQuery.easing = {
        linear: function (p) {
            return p;
        },
        swing: function (p) {
            return 0.5 - Math.cos(p * Math.PI) / 2;
        },
        _default: "swing"
    };
    jQuery.fx = Tween.prototype.init;
    // Back compat <1.8 extension point
    jQuery.fx.step = {};
    var fxNow, timerId, rfxtypes = /^(?:toggle|show|hide)$/, rrun = /queueHooks$/;
    function raf() {
        if (timerId) {
            window.requestAnimationFrame(raf);
            jQuery.fx.tick();
        }
    }
    // Animations created synchronously will run synchronously
    function createFxNow() {
        window.setTimeout(function () {
            fxNow = undefined;
        });
        return (fxNow = jQuery.now());
    }
    // Generate parameters to create a standard animation
    function genFx(type, includeWidth) {
        var which, i = 0, attrs = { height: type };
        // If we include width, step value is 1 to do all cssExpand values,
        // otherwise step value is 2 to skip over Left and Right
        includeWidth = includeWidth ? 1 : 0;
        for (; i < 4; i += 2 - includeWidth) {
            which = cssExpand[i];
            attrs["margin" + which] = attrs["padding" + which] = type;
        }
        if (includeWidth) {
            attrs.opacity = attrs.width = type;
        }
        return attrs;
    }
    function createTween(value, prop, animation) {
        var tween, collection = (Animation.tweeners[prop] || []).concat(Animation.tweeners["*"]), index = 0, length = collection.length;
        for (; index < length; index++) {
            if ((tween = collection[index].call(animation, prop, value))) {
                // We're done with this property
                return tween;
            }
        }
    }
    function defaultPrefilter(elem, props, opts) {
        var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, isBox = "width" in props || "height" in props, anim = this, orig = {}, style = elem.style, hidden = elem.nodeType && isHiddenWithinTree(elem), dataShow = dataPriv.get(elem, "fxshow");
        // Queue-skipping animations hijack the fx hooks
        if (!opts.queue) {
            hooks = jQuery._queueHooks(elem, "fx");
            if (hooks.unqueued == null) {
                hooks.unqueued = 0;
                oldfire = hooks.empty.fire;
                hooks.empty.fire = function () {
                    if (!hooks.unqueued) {
                        oldfire();
                    }
                };
            }
            hooks.unqueued++;
            anim.always(function () {
                // Ensure the complete handler is called before this completes
                anim.always(function () {
                    hooks.unqueued--;
                    if (!jQuery.queue(elem, "fx").length) {
                        hooks.empty.fire();
                    }
                });
            });
        }
        // Detect show/hide animations
        for (prop in props) {
            value = props[prop];
            if (rfxtypes.test(value)) {
                delete props[prop];
                toggle = toggle || value === "toggle";
                if (value === (hidden ? "hide" : "show")) {
                    // Pretend to be hidden if this is a "show" and
                    // there is still data from a stopped show/hide
                    if (value === "show" && dataShow && dataShow[prop] !== undefined) {
                        hidden = true;
                    }
                    else {
                        continue;
                    }
                }
                orig[prop] = dataShow && dataShow[prop] || jQuery.style(elem, prop);
            }
        }
        // Bail out if this is a no-op like .hide().hide()
        propTween = !jQuery.isEmptyObject(props);
        if (!propTween && jQuery.isEmptyObject(orig)) {
            return;
        }
        // Restrict "overflow" and "display" styles during box animations
        if (isBox && elem.nodeType === 1) {
            // Support: IE <=9 - 11, Edge 12 - 13
            // Record all 3 overflow attributes because IE does not infer the shorthand
            // from identically-valued overflowX and overflowY
            opts.overflow = [style.overflow, style.overflowX, style.overflowY];
            // Identify a display type, preferring old show/hide data over the CSS cascade
            restoreDisplay = dataShow && dataShow.display;
            if (restoreDisplay == null) {
                restoreDisplay = dataPriv.get(elem, "display");
            }
            display = jQuery.css(elem, "display");
            if (display === "none") {
                if (restoreDisplay) {
                    display = restoreDisplay;
                }
                else {
                    // Get nonempty value(s) by temporarily forcing visibility
                    showHide([elem], true);
                    restoreDisplay = elem.style.display || restoreDisplay;
                    display = jQuery.css(elem, "display");
                    showHide([elem]);
                }
            }
            // Animate inline elements as inline-block
            if (display === "inline" || display === "inline-block" && restoreDisplay != null) {
                if (jQuery.css(elem, "float") === "none") {
                    // Restore the original display value at the end of pure show/hide animations
                    if (!propTween) {
                        anim.done(function () {
                            style.display = restoreDisplay;
                        });
                        if (restoreDisplay == null) {
                            display = style.display;
                            restoreDisplay = display === "none" ? "" : display;
                        }
                    }
                    style.display = "inline-block";
                }
            }
        }
        if (opts.overflow) {
            style.overflow = "hidden";
            anim.always(function () {
                style.overflow = opts.overflow[0];
                style.overflowX = opts.overflow[1];
                style.overflowY = opts.overflow[2];
            });
        }
        // Implement show/hide animations
        propTween = false;
        for (prop in orig) {
            // General show/hide setup for this element animation
            if (!propTween) {
                if (dataShow) {
                    if ("hidden" in dataShow) {
                        hidden = dataShow.hidden;
                    }
                }
                else {
                    dataShow = dataPriv.access(elem, "fxshow", { display: restoreDisplay });
                }
                // Store hidden/visible for toggle so `.stop().toggle()` "reverses"
                if (toggle) {
                    dataShow.hidden = !hidden;
                }
                // Show elements before animating them
                if (hidden) {
                    showHide([elem], true);
                }
                /* eslint-disable no-loop-func */
                anim.done(function () {
                    /* eslint-enable no-loop-func */
                    // The final step of a "hide" animation is actually hiding the element
                    if (!hidden) {
                        showHide([elem]);
                    }
                    dataPriv.remove(elem, "fxshow");
                    for (prop in orig) {
                        jQuery.style(elem, prop, orig[prop]);
                    }
                });
            }
            // Per-property setup
            propTween = createTween(hidden ? dataShow[prop] : 0, prop, anim);
            if (!(prop in dataShow)) {
                dataShow[prop] = propTween.start;
                if (hidden) {
                    propTween.end = propTween.start;
                    propTween.start = 0;
                }
            }
        }
    }
    function propFilter(props, specialEasing) {
        var index, name, easing, value, hooks;
        // camelCase, specialEasing and expand cssHook pass
        for (index in props) {
            name = jQuery.camelCase(index);
            easing = specialEasing[name];
            value = props[index];
            if (jQuery.isArray(value)) {
                easing = value[1];
                value = props[index] = value[0];
            }
            if (index !== name) {
                props[name] = value;
                delete props[index];
            }
            hooks = jQuery.cssHooks[name];
            if (hooks && "expand" in hooks) {
                value = hooks.expand(value);
                delete props[name];
                // Not quite $.extend, this won't overwrite existing keys.
                // Reusing 'index' because we have the correct "name"
                for (index in value) {
                    if (!(index in props)) {
                        props[index] = value[index];
                        specialEasing[index] = easing;
                    }
                }
            }
            else {
                specialEasing[name] = easing;
            }
        }
    }
    function Animation(elem, properties, options) {
        var result, stopped, index = 0, length = Animation.prefilters.length, deferred = jQuery.Deferred().always(function () {
            // Don't match elem in the :animated selector
            delete tick.elem;
        }), tick = function () {
            if (stopped) {
                return false;
            }
            var currentTime = fxNow || createFxNow(), remaining = Math.max(0, animation.startTime + animation.duration - currentTime), 
            // Support: Android 2.3 only
            // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497)
            temp = remaining / animation.duration || 0, percent = 1 - temp, index = 0, length = animation.tweens.length;
            for (; index < length; index++) {
                animation.tweens[index].run(percent);
            }
            deferred.notifyWith(elem, [animation, percent, remaining]);
            if (percent < 1 && length) {
                return remaining;
            }
            else {
                deferred.resolveWith(elem, [animation]);
                return false;
            }
        }, animation = deferred.promise({
            elem: elem,
            props: jQuery.extend({}, properties),
            opts: jQuery.extend(true, {
                specialEasing: {},
                easing: jQuery.easing._default
            }, options),
            originalProperties: properties,
            originalOptions: options,
            startTime: fxNow || createFxNow(),
            duration: options.duration,
            tweens: [],
            createTween: function (prop, end) {
                var tween = jQuery.Tween(elem, animation.opts, prop, end, animation.opts.specialEasing[prop] || animation.opts.easing);
                animation.tweens.push(tween);
                return tween;
            },
            stop: function (gotoEnd) {
                var index = 0, 
                // If we are going to the end, we want to run all the tweens
                // otherwise we skip this part
                length = gotoEnd ? animation.tweens.length : 0;
                if (stopped) {
                    return this;
                }
                stopped = true;
                for (; index < length; index++) {
                    animation.tweens[index].run(1);
                }
                // Resolve when we played the last frame; otherwise, reject
                if (gotoEnd) {
                    deferred.notifyWith(elem, [animation, 1, 0]);
                    deferred.resolveWith(elem, [animation, gotoEnd]);
                }
                else {
                    deferred.rejectWith(elem, [animation, gotoEnd]);
                }
                return this;
            }
        }), props = animation.props;
        propFilter(props, animation.opts.specialEasing);
        for (; index < length; index++) {
            result = Animation.prefilters[index].call(animation, elem, props, animation.opts);
            if (result) {
                if (jQuery.isFunction(result.stop)) {
                    jQuery._queueHooks(animation.elem, animation.opts.queue).stop =
                        jQuery.proxy(result.stop, result);
                }
                return result;
            }
        }
        jQuery.map(props, createTween, animation);
        if (jQuery.isFunction(animation.opts.start)) {
            animation.opts.start.call(elem, animation);
        }
        jQuery.fx.timer(jQuery.extend(tick, {
            elem: elem,
            anim: animation,
            queue: animation.opts.queue
        }));
        // attach callbacks from options
        return animation.progress(animation.opts.progress)
            .done(animation.opts.done, animation.opts.complete)
            .fail(animation.opts.fail)
            .always(animation.opts.always);
    }
    jQuery.Animation = jQuery.extend(Animation, {
        tweeners: {
            "*": [function (prop, value) {
                    var tween = this.createTween(prop, value);
                    adjustCSS(tween.elem, prop, rcssNum.exec(value), tween);
                    return tween;
                }]
        },
        tweener: function (props, callback) {
            if (jQuery.isFunction(props)) {
                callback = props;
                props = ["*"];
            }
            else {
                props = props.match(rnothtmlwhite);
            }
            var prop, index = 0, length = props.length;
            for (; index < length; index++) {
                prop = props[index];
                Animation.tweeners[prop] = Animation.tweeners[prop] || [];
                Animation.tweeners[prop].unshift(callback);
            }
        },
        prefilters: [defaultPrefilter],
        prefilter: function (callback, prepend) {
            if (prepend) {
                Animation.prefilters.unshift(callback);
            }
            else {
                Animation.prefilters.push(callback);
            }
        }
    });
    jQuery.speed = function (speed, easing, fn) {
        var opt = speed && typeof speed === "object" ? jQuery.extend({}, speed) : {
            complete: fn || !fn && easing ||
                jQuery.isFunction(speed) && speed,
            duration: speed,
            easing: fn && easing || easing && !jQuery.isFunction(easing) && easing
        };
        // Go to the end state if fx are off or if document is hidden
        if (jQuery.fx.off || document.hidden) {
            opt.duration = 0;
        }
        else {
            if (typeof opt.duration !== "number") {
                if (opt.duration in jQuery.fx.speeds) {
                    opt.duration = jQuery.fx.speeds[opt.duration];
                }
                else {
                    opt.duration = jQuery.fx.speeds._default;
                }
            }
        }
        // Normalize opt.queue - true/undefined/null -> "fx"
        if (opt.queue == null || opt.queue === true) {
            opt.queue = "fx";
        }
        // Queueing
        opt.old = opt.complete;
        opt.complete = function () {
            if (jQuery.isFunction(opt.old)) {
                opt.old.call(this);
            }
            if (opt.queue) {
                jQuery.dequeue(this, opt.queue);
            }
        };
        return opt;
    };
    jQuery.fn.extend({
        fadeTo: function (speed, to, easing, callback) {
            // Show any hidden elements after setting opacity to 0
            return this.filter(isHiddenWithinTree).css("opacity", 0).show()
                .end().animate({ opacity: to }, speed, easing, callback);
        },
        animate: function (prop, speed, easing, callback) {
            var empty = jQuery.isEmptyObject(prop), optall = jQuery.speed(speed, easing, callback), doAnimation = function () {
                // Operate on a copy of prop so per-property easing won't be lost
                var anim = Animation(this, jQuery.extend({}, prop), optall);
                // Empty animations, or finishing resolves immediately
                if (empty || dataPriv.get(this, "finish")) {
                    anim.stop(true);
                }
            };
            doAnimation.finish = doAnimation;
            return empty || optall.queue === false ?
                this.each(doAnimation) :
                this.queue(optall.queue, doAnimation);
        },
        stop: function (type, clearQueue, gotoEnd) {
            var stopQueue = function (hooks) {
                var stop = hooks.stop;
                delete hooks.stop;
                stop(gotoEnd);
            };
            if (typeof type !== "string") {
                gotoEnd = clearQueue;
                clearQueue = type;
                type = undefined;
            }
            if (clearQueue && type !== false) {
                this.queue(type || "fx", []);
            }
            return this.each(function () {
                var dequeue = true, index = type != null && type + "queueHooks", timers = jQuery.timers, data = dataPriv.get(this);
                if (index) {
                    if (data[index] && data[index].stop) {
                        stopQueue(data[index]);
                    }
                }
                else {
                    for (index in data) {
                        if (data[index] && data[index].stop && rrun.test(index)) {
                            stopQueue(data[index]);
                        }
                    }
                }
                for (index = timers.length; index--;) {
                    if (timers[index].elem === this &&
                        (type == null || timers[index].queue === type)) {
                        timers[index].anim.stop(gotoEnd);
                        dequeue = false;
                        timers.splice(index, 1);
                    }
                }
                // Start the next in the queue if the last step wasn't forced.
                // Timers currently will call their complete callbacks, which
                // will dequeue but only if they were gotoEnd.
                if (dequeue || !gotoEnd) {
                    jQuery.dequeue(this, type);
                }
            });
        },
        finish: function (type) {
            if (type !== false) {
                type = type || "fx";
            }
            return this.each(function () {
                var index, data = dataPriv.get(this), queue = data[type + "queue"], hooks = data[type + "queueHooks"], timers = jQuery.timers, length = queue ? queue.length : 0;
                // Enable finishing flag on private data
                data.finish = true;
                // Empty the queue first
                jQuery.queue(this, type, []);
                if (hooks && hooks.stop) {
                    hooks.stop.call(this, true);
                }
                // Look for any active animations, and finish them
                for (index = timers.length; index--;) {
                    if (timers[index].elem === this && timers[index].queue === type) {
                        timers[index].anim.stop(true);
                        timers.splice(index, 1);
                    }
                }
                // Look for any animations in the old queue and finish them
                for (index = 0; index < length; index++) {
                    if (queue[index] && queue[index].finish) {
                        queue[index].finish.call(this);
                    }
                }
                // Turn off finishing flag
                delete data.finish;
            });
        }
    });
    jQuery.each(["toggle", "show", "hide"], function (i, name) {
        var cssFn = jQuery.fn[name];
        jQuery.fn[name] = function (speed, easing, callback) {
            return speed == null || typeof speed === "boolean" ?
                cssFn.apply(this, arguments) :
                this.animate(genFx(name, true), speed, easing, callback);
        };
    });
    // Generate shortcuts for custom animations
    jQuery.each({
        slideDown: genFx("show"),
        slideUp: genFx("hide"),
        slideToggle: genFx("toggle"),
        fadeIn: { opacity: "show" },
        fadeOut: { opacity: "hide" },
        fadeToggle: { opacity: "toggle" }
    }, function (name, props) {
        jQuery.fn[name] = function (speed, easing, callback) {
            return this.animate(props, speed, easing, callback);
        };
    });
    jQuery.timers = [];
    jQuery.fx.tick = function () {
        var timer, i = 0, timers = jQuery.timers;
        fxNow = jQuery.now();
        for (; i < timers.length; i++) {
            timer = timers[i];
            // Checks the timer has not already been removed
            if (!timer() && timers[i] === timer) {
                timers.splice(i--, 1);
            }
        }
        if (!timers.length) {
            jQuery.fx.stop();
        }
        fxNow = undefined;
    };
    jQuery.fx.timer = function (timer) {
        jQuery.timers.push(timer);
        if (timer()) {
            jQuery.fx.start();
        }
        else {
            jQuery.timers.pop();
        }
    };
    jQuery.fx.interval = 13;
    jQuery.fx.start = function () {
        if (!timerId) {
            timerId = window.requestAnimationFrame ?
                window.requestAnimationFrame(raf) :
                window.setInterval(jQuery.fx.tick, jQuery.fx.interval);
        }
    };
    jQuery.fx.stop = function () {
        if (window.cancelAnimationFrame) {
            window.cancelAnimationFrame(timerId);
        }
        else {
            window.clearInterval(timerId);
        }
        timerId = null;
    };
    jQuery.fx.speeds = {
        slow: 600,
        fast: 200,
        // Default speed
        _default: 400
    };
    // Based off of the plugin by Clint Helfers, with permission.
    // https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/
    jQuery.fn.delay = function (time, type) {
        time = jQuery.fx ? jQuery.fx.speeds[time] || time : time;
        type = type || "fx";
        return this.queue(type, function (next, hooks) {
            var timeout = window.setTimeout(next, time);
            hooks.stop = function () {
                window.clearTimeout(timeout);
            };
        });
    };
    (function () {
        var input = document.createElement("input"), select = document.createElement("select"), opt = select.appendChild(document.createElement("option"));
        input.type = "checkbox";
        // Support: Android <=4.3 only
        // Default value for a checkbox should be "on"
        support.checkOn = input.value !== "";
        // Support: IE <=11 only
        // Must access selectedIndex to make default options select
        support.optSelected = opt.selected;
        // Support: IE <=11 only
        // An input loses its value after becoming a radio
        input = document.createElement("input");
        input.value = "t";
        input.type = "radio";
        support.radioValue = input.value === "t";
    })();
    var boolHook, attrHandle = jQuery.expr.attrHandle;
    jQuery.fn.extend({
        attr: function (name, value) {
            return access(this, jQuery.attr, name, value, arguments.length > 1);
        },
        removeAttr: function (name) {
            return this.each(function () {
                jQuery.removeAttr(this, name);
            });
        }
    });
    jQuery.extend({
        attr: function (elem, name, value) {
            var ret, hooks, nType = elem.nodeType;
            // Don't get/set attributes on text, comment and attribute nodes
            if (nType === 3 || nType === 8 || nType === 2) {
                return;
            }
            // Fallback to prop when attributes are not supported
            if (typeof elem.getAttribute === "undefined") {
                return jQuery.prop(elem, name, value);
            }
            // Attribute hooks are determined by the lowercase version
            // Grab necessary hook if one is defined
            if (nType !== 1 || !jQuery.isXMLDoc(elem)) {
                hooks = jQuery.attrHooks[name.toLowerCase()] ||
                    (jQuery.expr.match.bool.test(name) ? boolHook : undefined);
            }
            if (value !== undefined) {
                if (value === null) {
                    jQuery.removeAttr(elem, name);
                    return;
                }
                if (hooks && "set" in hooks &&
                    (ret = hooks.set(elem, value, name)) !== undefined) {
                    return ret;
                }
                elem.setAttribute(name, value + "");
                return value;
            }
            if (hooks && "get" in hooks && (ret = hooks.get(elem, name)) !== null) {
                return ret;
            }
            ret = jQuery.find.attr(elem, name);
            // Non-existent attributes return null, we normalize to undefined
            return ret == null ? undefined : ret;
        },
        attrHooks: {
            type: {
                set: function (elem, value) {
                    if (!support.radioValue && value === "radio" &&
                        jQuery.nodeName(elem, "input")) {
                        var val = elem.value;
                        elem.setAttribute("type", value);
                        if (val) {
                            elem.value = val;
                        }
                        return value;
                    }
                }
            }
        },
        removeAttr: function (elem, value) {
            var name, i = 0, 
            // Attribute names can contain non-HTML whitespace characters
            // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2
            attrNames = value && value.match(rnothtmlwhite);
            if (attrNames && elem.nodeType === 1) {
                while ((name = attrNames[i++])) {
                    elem.removeAttribute(name);
                }
            }
        }
    });
    // Hooks for boolean attributes
    boolHook = {
        set: function (elem, value, name) {
            if (value === false) {
                // Remove boolean attributes when set to false
                jQuery.removeAttr(elem, name);
            }
            else {
                elem.setAttribute(name, name);
            }
            return name;
        }
    };
    jQuery.each(jQuery.expr.match.bool.source.match(/\w+/g), function (i, name) {
        var getter = attrHandle[name] || jQuery.find.attr;
        attrHandle[name] = function (elem, name, isXML) {
            var ret, handle, lowercaseName = name.toLowerCase();
            if (!isXML) {
                // Avoid an infinite loop by temporarily removing this function from the getter
                handle = attrHandle[lowercaseName];
                attrHandle[lowercaseName] = ret;
                ret = getter(elem, name, isXML) != null ?
                    lowercaseName :
                    null;
                attrHandle[lowercaseName] = handle;
            }
            return ret;
        };
    });
    var rfocusable = /^(?:input|select|textarea|button)$/i, rclickable = /^(?:a|area)$/i;
    jQuery.fn.extend({
        prop: function (name, value) {
            return access(this, jQuery.prop, name, value, arguments.length > 1);
        },
        removeProp: function (name) {
            return this.each(function () {
                delete this[jQuery.propFix[name] || name];
            });
        }
    });
    jQuery.extend({
        prop: function (elem, name, value) {
            var ret, hooks, nType = elem.nodeType;
            // Don't get/set properties on text, comment and attribute nodes
            if (nType === 3 || nType === 8 || nType === 2) {
                return;
            }
            if (nType !== 1 || !jQuery.isXMLDoc(elem)) {
                // Fix name and attach hooks
                name = jQuery.propFix[name] || name;
                hooks = jQuery.propHooks[name];
            }
            if (value !== undefined) {
                if (hooks && "set" in hooks &&
                    (ret = hooks.set(elem, value, name)) !== undefined) {
                    return ret;
                }
                return (elem[name] = value);
            }
            if (hooks && "get" in hooks && (ret = hooks.get(elem, name)) !== null) {
                return ret;
            }
            return elem[name];
        },
        propHooks: {
            tabIndex: {
                get: function (elem) {
                    // Support: IE <=9 - 11 only
                    // elem.tabIndex doesn't always return the
                    // correct value when it hasn't been explicitly set
                    // https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
                    // Use proper attribute retrieval(#12072)
                    var tabindex = jQuery.find.attr(elem, "tabindex");
                    if (tabindex) {
                        return parseInt(tabindex, 10);
                    }
                    if (rfocusable.test(elem.nodeName) ||
                        rclickable.test(elem.nodeName) &&
                            elem.href) {
                        return 0;
                    }
                    return -1;
                }
            }
        },
        propFix: {
            "for": "htmlFor",
            "class": "className"
        }
    });
    // Support: IE <=11 only
    // Accessing the selectedIndex property
    // forces the browser to respect setting selected
    // on the option
    // The getter ensures a default option is selected
    // when in an optgroup
    // eslint rule "no-unused-expressions" is disabled for this code
    // since it considers such accessions noop
    if (!support.optSelected) {
        jQuery.propHooks.selected = {
            get: function (elem) {
                /* eslint no-unused-expressions: "off" */
                var parent = elem.parentNode;
                if (parent && parent.parentNode) {
                    parent.parentNode.selectedIndex;
                }
                return null;
            },
            set: function (elem) {
                /* eslint no-unused-expressions: "off" */
                var parent = elem.parentNode;
                if (parent) {
                    parent.selectedIndex;
                    if (parent.parentNode) {
                        parent.parentNode.selectedIndex;
                    }
                }
            }
        };
    }
    jQuery.each([
        "tabIndex",
        "readOnly",
        "maxLength",
        "cellSpacing",
        "cellPadding",
        "rowSpan",
        "colSpan",
        "useMap",
        "frameBorder",
        "contentEditable"
    ], function () {
        jQuery.propFix[this.toLowerCase()] = this;
    });
    // Strip and collapse whitespace according to HTML spec
    // https://html.spec.whatwg.org/multipage/infrastructure.html#strip-and-collapse-whitespace
    function stripAndCollapse(value) {
        var tokens = value.match(rnothtmlwhite) || [];
        return tokens.join(" ");
    }
    function getClass(elem) {
        return elem.getAttribute && elem.getAttribute("class") || "";
    }
    jQuery.fn.extend({
        addClass: function (value) {
            var classes, elem, cur, curValue, clazz, j, finalValue, i = 0;
            if (jQuery.isFunction(value)) {
                return this.each(function (j) {
                    jQuery(this).addClass(value.call(this, j, getClass(this)));
                });
            }
            if (typeof value === "string" && value) {
                classes = value.match(rnothtmlwhite) || [];
                while ((elem = this[i++])) {
                    curValue = getClass(elem);
                    cur = elem.nodeType === 1 && (" " + stripAndCollapse(curValue) + " ");
                    if (cur) {
                        j = 0;
                        while ((clazz = classes[j++])) {
                            if (cur.indexOf(" " + clazz + " ") < 0) {
                                cur += clazz + " ";
                            }
                        }
                        // Only assign if different to avoid unneeded rendering.
                        finalValue = stripAndCollapse(cur);
                        if (curValue !== finalValue) {
                            elem.setAttribute("class", finalValue);
                        }
                    }
                }
            }
            return this;
        },
        removeClass: function (value) {
            var classes, elem, cur, curValue, clazz, j, finalValue, i = 0;
            if (jQuery.isFunction(value)) {
                return this.each(function (j) {
                    jQuery(this).removeClass(value.call(this, j, getClass(this)));
                });
            }
            if (!arguments.length) {
                return this.attr("class", "");
            }
            if (typeof value === "string" && value) {
                classes = value.match(rnothtmlwhite) || [];
                while ((elem = this[i++])) {
                    curValue = getClass(elem);
                    // This expression is here for better compressibility (see addClass)
                    cur = elem.nodeType === 1 && (" " + stripAndCollapse(curValue) + " ");
                    if (cur) {
                        j = 0;
                        while ((clazz = classes[j++])) {
                            // Remove *all* instances
                            while (cur.indexOf(" " + clazz + " ") > -1) {
                                cur = cur.replace(" " + clazz + " ", " ");
                            }
                        }
                        // Only assign if different to avoid unneeded rendering.
                        finalValue = stripAndCollapse(cur);
                        if (curValue !== finalValue) {
                            elem.setAttribute("class", finalValue);
                        }
                    }
                }
            }
            return this;
        },
        toggleClass: function (value, stateVal) {
            var type = typeof value;
            if (typeof stateVal === "boolean" && type === "string") {
                return stateVal ? this.addClass(value) : this.removeClass(value);
            }
            if (jQuery.isFunction(value)) {
                return this.each(function (i) {
                    jQuery(this).toggleClass(value.call(this, i, getClass(this), stateVal), stateVal);
                });
            }
            return this.each(function () {
                var className, i, self, classNames;
                if (type === "string") {
                    // Toggle individual class names
                    i = 0;
                    self = jQuery(this);
                    classNames = value.match(rnothtmlwhite) || [];
                    while ((className = classNames[i++])) {
                        // Check each className given, space separated list
                        if (self.hasClass(className)) {
                            self.removeClass(className);
                        }
                        else {
                            self.addClass(className);
                        }
                    }
                }
                else if (value === undefined || type === "boolean") {
                    className = getClass(this);
                    if (className) {
                        // Store className if set
                        dataPriv.set(this, "__className__", className);
                    }
                    // If the element has a class name or if we're passed `false`,
                    // then remove the whole classname (if there was one, the above saved it).
                    // Otherwise bring back whatever was previously saved (if anything),
                    // falling back to the empty string if nothing was stored.
                    if (this.setAttribute) {
                        this.setAttribute("class", className || value === false ?
                            "" :
                            dataPriv.get(this, "__className__") || "");
                    }
                }
            });
        },
        hasClass: function (selector) {
            var className, elem, i = 0;
            className = " " + selector + " ";
            while ((elem = this[i++])) {
                if (elem.nodeType === 1 &&
                    (" " + stripAndCollapse(getClass(elem)) + " ").indexOf(className) > -1) {
                    return true;
                }
            }
            return false;
        }
    });
    var rreturn = /\r/g;
    jQuery.fn.extend({
        val: function (value) {
            var hooks, ret, isFunction, elem = this[0];
            if (!arguments.length) {
                if (elem) {
                    hooks = jQuery.valHooks[elem.type] ||
                        jQuery.valHooks[elem.nodeName.toLowerCase()];
                    if (hooks &&
                        "get" in hooks &&
                        (ret = hooks.get(elem, "value")) !== undefined) {
                        return ret;
                    }
                    ret = elem.value;
                    // Handle most common string cases
                    if (typeof ret === "string") {
                        return ret.replace(rreturn, "");
                    }
                    // Handle cases where value is null/undef or number
                    return ret == null ? "" : ret;
                }
                return;
            }
            isFunction = jQuery.isFunction(value);
            return this.each(function (i) {
                var val;
                if (this.nodeType !== 1) {
                    return;
                }
                if (isFunction) {
                    val = value.call(this, i, jQuery(this).val());
                }
                else {
                    val = value;
                }
                // Treat null/undefined as ""; convert numbers to string
                if (val == null) {
                    val = "";
                }
                else if (typeof val === "number") {
                    val += "";
                }
                else if (jQuery.isArray(val)) {
                    val = jQuery.map(val, function (value) {
                        return value == null ? "" : value + "";
                    });
                }
                hooks = jQuery.valHooks[this.type] || jQuery.valHooks[this.nodeName.toLowerCase()];
                // If set returns undefined, fall back to normal setting
                if (!hooks || !("set" in hooks) || hooks.set(this, val, "value") === undefined) {
                    this.value = val;
                }
            });
        }
    });
    jQuery.extend({
        valHooks: {
            option: {
                get: function (elem) {
                    var val = jQuery.find.attr(elem, "value");
                    return val != null ?
                        val :
                        // Support: IE <=10 - 11 only
                        // option.text throws exceptions (#14686, #14858)
                        // Strip and collapse whitespace
                        // https://html.spec.whatwg.org/#strip-and-collapse-whitespace
                        stripAndCollapse(jQuery.text(elem));
                }
            },
            select: {
                get: function (elem) {
                    var value, option, i, options = elem.options, index = elem.selectedIndex, one = elem.type === "select-one", values = one ? null : [], max = one ? index + 1 : options.length;
                    if (index < 0) {
                        i = max;
                    }
                    else {
                        i = one ? index : 0;
                    }
                    // Loop through all the selected options
                    for (; i < max; i++) {
                        option = options[i];
                        // Support: IE <=9 only
                        // IE8-9 doesn't update selected after form reset (#2551)
                        if ((option.selected || i === index) &&
                            // Don't return options that are disabled or in a disabled optgroup
                            !option.disabled &&
                            (!option.parentNode.disabled ||
                                !jQuery.nodeName(option.parentNode, "optgroup"))) {
                            // Get the specific value for the option
                            value = jQuery(option).val();
                            // We don't need an array for one selects
                            if (one) {
                                return value;
                            }
                            // Multi-Selects return an array
                            values.push(value);
                        }
                    }
                    return values;
                },
                set: function (elem, value) {
                    var optionSet, option, options = elem.options, values = jQuery.makeArray(value), i = options.length;
                    while (i--) {
                        option = options[i];
                        /* eslint-disable no-cond-assign */
                        if (option.selected =
                            jQuery.inArray(jQuery.valHooks.option.get(option), values) > -1) {
                            optionSet = true;
                        }
                    }
                    // Force browsers to behave consistently when non-matching value is set
                    if (!optionSet) {
                        elem.selectedIndex = -1;
                    }
                    return values;
                }
            }
        }
    });
    // Radios and checkboxes getter/setter
    jQuery.each(["radio", "checkbox"], function () {
        jQuery.valHooks[this] = {
            set: function (elem, value) {
                if (jQuery.isArray(value)) {
                    return (elem.checked = jQuery.inArray(jQuery(elem).val(), value) > -1);
                }
            }
        };
        if (!support.checkOn) {
            jQuery.valHooks[this].get = function (elem) {
                return elem.getAttribute("value") === null ? "on" : elem.value;
            };
        }
    });
    // Return jQuery for attributes-only inclusion
    var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/;
    jQuery.extend(jQuery.event, {
        trigger: function (event, data, elem, onlyHandlers) {
            var i, cur, tmp, bubbleType, ontype, handle, special, eventPath = [elem || document], type = hasOwn.call(event, "type") ? event.type : event, namespaces = hasOwn.call(event, "namespace") ? event.namespace.split(".") : [];
            cur = tmp = elem = elem || document;
            // Don't do events on text and comment nodes
            if (elem.nodeType === 3 || elem.nodeType === 8) {
                return;
            }
            // focus/blur morphs to focusin/out; ensure we're not firing them right now
            if (rfocusMorph.test(type + jQuery.event.triggered)) {
                return;
            }
            if (type.indexOf(".") > -1) {
                // Namespaced trigger; create a regexp to match event type in handle()
                namespaces = type.split(".");
                type = namespaces.shift();
                namespaces.sort();
            }
            ontype = type.indexOf(":") < 0 && "on" + type;
            // Caller can pass in a jQuery.Event object, Object, or just an event type string
            event = event[jQuery.expando] ?
                event :
                new jQuery.Event(type, typeof event === "object" && event);
            // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)
            event.isTrigger = onlyHandlers ? 2 : 3;
            event.namespace = namespaces.join(".");
            event.rnamespace = event.namespace ?
                new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)") :
                null;
            // Clean up the event in case it is being reused
            event.result = undefined;
            if (!event.target) {
                event.target = elem;
            }
            // Clone any incoming data and prepend the event, creating the handler arg list
            data = data == null ?
                [event] :
                jQuery.makeArray(data, [event]);
            // Allow special events to draw outside the lines
            special = jQuery.event.special[type] || {};
            if (!onlyHandlers && special.trigger && special.trigger.apply(elem, data) === false) {
                return;
            }
            // Determine event propagation path in advance, per W3C events spec (#9951)
            // Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
            if (!onlyHandlers && !special.noBubble && !jQuery.isWindow(elem)) {
                bubbleType = special.delegateType || type;
                if (!rfocusMorph.test(bubbleType + type)) {
                    cur = cur.parentNode;
                }
                for (; cur; cur = cur.parentNode) {
                    eventPath.push(cur);
                    tmp = cur;
                }
                // Only add window if we got to document (e.g., not plain obj or detached DOM)
                if (tmp === (elem.ownerDocument || document)) {
                    eventPath.push(tmp.defaultView || tmp.parentWindow || window);
                }
            }
            // Fire handlers on the event path
            i = 0;
            while ((cur = eventPath[i++]) && !event.isPropagationStopped()) {
                event.type = i > 1 ?
                    bubbleType :
                    special.bindType || type;
                // jQuery handler
                handle = (dataPriv.get(cur, "events") || {})[event.type] &&
                    dataPriv.get(cur, "handle");
                if (handle) {
                    handle.apply(cur, data);
                }
                // Native handler
                handle = ontype && cur[ontype];
                if (handle && handle.apply && acceptData(cur)) {
                    event.result = handle.apply(cur, data);
                    if (event.result === false) {
                        event.preventDefault();
                    }
                }
            }
            event.type = type;
            // If nobody prevented the default action, do it now
            if (!onlyHandlers && !event.isDefaultPrevented()) {
                if ((!special._default ||
                    special._default.apply(eventPath.pop(), data) === false) &&
                    acceptData(elem)) {
                    // Call a native DOM method on the target with the same name as the event.
                    // Don't do default actions on window, that's where global variables be (#6170)
                    if (ontype && jQuery.isFunction(elem[type]) && !jQuery.isWindow(elem)) {
                        // Don't re-trigger an onFOO event when we call its FOO() method
                        tmp = elem[ontype];
                        if (tmp) {
                            elem[ontype] = null;
                        }
                        // Prevent re-triggering of the same event, since we already bubbled it above
                        jQuery.event.triggered = type;
                        elem[type]();
                        jQuery.event.triggered = undefined;
                        if (tmp) {
                            elem[ontype] = tmp;
                        }
                    }
                }
            }
            return event.result;
        },
        // Piggyback on a donor event to simulate a different one
        // Used only for `focus(in | out)` events
        simulate: function (type, elem, event) {
            var e = jQuery.extend(new jQuery.Event(), event, {
                type: type,
                isSimulated: true
            });
            jQuery.event.trigger(e, null, elem);
        }
    });
    jQuery.fn.extend({
        trigger: function (type, data) {
            return this.each(function () {
                jQuery.event.trigger(type, data, this);
            });
        },
        triggerHandler: function (type, data) {
            var elem = this[0];
            if (elem) {
                return jQuery.event.trigger(type, data, elem, true);
            }
        }
    });
    jQuery.each(("blur focus focusin focusout resize scroll click dblclick " +
        "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
        "change select submit keydown keypress keyup contextmenu").split(" "), function (i, name) {
        // Handle event binding
        jQuery.fn[name] = function (data, fn) {
            return arguments.length > 0 ?
                this.on(name, null, data, fn) :
                this.trigger(name);
        };
    });
    jQuery.fn.extend({
        hover: function (fnOver, fnOut) {
            return this.mouseenter(fnOver).mouseleave(fnOut || fnOver);
        }
    });
    support.focusin = "onfocusin" in window;
    // Support: Firefox <=44
    // Firefox doesn't have focus(in | out) events
    // Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787
    //
    // Support: Chrome <=48 - 49, Safari <=9.0 - 9.1
    // focus(in | out) events fire after focus & blur events,
    // which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order
    // Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857
    if (!support.focusin) {
        jQuery.each({ focus: "focusin", blur: "focusout" }, function (orig, fix) {
            // Attach a single capturing handler on the document while someone wants focusin/focusout
            var handler = function (event) {
                jQuery.event.simulate(fix, event.target, jQuery.event.fix(event));
            };
            jQuery.event.special[fix] = {
                setup: function () {
                    var doc = this.ownerDocument || this, attaches = dataPriv.access(doc, fix);
                    if (!attaches) {
                        doc.addEventListener(orig, handler, true);
                    }
                    dataPriv.access(doc, fix, (attaches || 0) + 1);
                },
                teardown: function () {
                    var doc = this.ownerDocument || this, attaches = dataPriv.access(doc, fix) - 1;
                    if (!attaches) {
                        doc.removeEventListener(orig, handler, true);
                        dataPriv.remove(doc, fix);
                    }
                    else {
                        dataPriv.access(doc, fix, attaches);
                    }
                }
            };
        });
    }
    var location = window.location;
    var nonce = jQuery.now();
    var rquery = (/\?/);
    // Cross-browser xml parsing
    jQuery.parseXML = function (data) {
        var xml;
        if (!data || typeof data !== "string") {
            return null;
        }
        // Support: IE 9 - 11 only
        // IE throws on parseFromString with invalid input.
        try {
            xml = (new window.DOMParser()).parseFromString(data, "text/xml");
        }
        catch (e) {
            xml = undefined;
        }
        if (!xml || xml.getElementsByTagName("parsererror").length) {
            jQuery.error("Invalid XML: " + data);
        }
        return xml;
    };
    var rbracket = /\[\]$/, rCRLF = /\r?\n/g, rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, rsubmittable = /^(?:input|select|textarea|keygen)/i;
    function buildParams(prefix, obj, traditional, add) {
        var name;
        if (jQuery.isArray(obj)) {
            // Serialize array item.
            jQuery.each(obj, function (i, v) {
                if (traditional || rbracket.test(prefix)) {
                    // Treat each array item as a scalar.
                    add(prefix, v);
                }
                else {
                    // Item is non-scalar (array or object), encode its numeric index.
                    buildParams(prefix + "[" + (typeof v === "object" && v != null ? i : "") + "]", v, traditional, add);
                }
            });
        }
        else if (!traditional && jQuery.type(obj) === "object") {
            // Serialize object item.
            for (name in obj) {
                buildParams(prefix + "[" + name + "]", obj[name], traditional, add);
            }
        }
        else {
            // Serialize scalar item.
            add(prefix, obj);
        }
    }
    // Serialize an array of form elements or a set of
    // key/values into a query string
    jQuery.param = function (a, traditional) {
        var prefix, s = [], add = function (key, valueOrFunction) {
            // If value is a function, invoke it and use its return value
            var value = jQuery.isFunction(valueOrFunction) ?
                valueOrFunction() :
                valueOrFunction;
            s[s.length] = encodeURIComponent(key) + "=" +
                encodeURIComponent(value == null ? "" : value);
        };
        // If an array was passed in, assume that it is an array of form elements.
        if (jQuery.isArray(a) || (a.jquery && !jQuery.isPlainObject(a))) {
            // Serialize the form elements
            jQuery.each(a, function () {
                add(this.name, this.value);
            });
        }
        else {
            // If traditional, encode the "old" way (the way 1.3.2 or older
            // did it), otherwise encode params recursively.
            for (prefix in a) {
                buildParams(prefix, a[prefix], traditional, add);
            }
        }
        // Return the resulting serialization
        return s.join("&");
    };
    jQuery.fn.extend({
        serialize: function () {
            return jQuery.param(this.serializeArray());
        },
        serializeArray: function () {
            return this.map(function () {
                // Can add propHook for "elements" to filter or add form elements
                var elements = jQuery.prop(this, "elements");
                return elements ? jQuery.makeArray(elements) : this;
            })
                .filter(function () {
                var type = this.type;
                // Use .is( ":disabled" ) so that fieldset[disabled] works
                return this.name && !jQuery(this).is(":disabled") &&
                    rsubmittable.test(this.nodeName) && !rsubmitterTypes.test(type) &&
                    (this.checked || !rcheckableType.test(type));
            })
                .map(function (i, elem) {
                var val = jQuery(this).val();
                if (val == null) {
                    return null;
                }
                if (jQuery.isArray(val)) {
                    return jQuery.map(val, function (val) {
                        return { name: elem.name, value: val.replace(rCRLF, "\r\n") };
                    });
                }
                return { name: elem.name, value: val.replace(rCRLF, "\r\n") };
            }).get();
        }
    });
    var r20 = /%20/g, rhash = /#.*$/, rantiCache = /([?&])_=[^&]*/, rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, 
    // #7653, #8125, #8152: local protocol detection
    rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, rnoContent = /^(?:GET|HEAD)$/, rprotocol = /^\/\//, 
    /* Prefilters
     * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
     * 2) These are called:
     *    - BEFORE asking for a transport
     *    - AFTER param serialization (s.data is a string if s.processData is true)
     * 3) key is the dataType
     * 4) the catchall symbol "*" can be used
     * 5) execution will start with transport dataType and THEN continue down to "*" if needed
     */
    prefilters = {}, 
    /* Transports bindings
     * 1) key is the dataType
     * 2) the catchall symbol "*" can be used
     * 3) selection will start with transport dataType and THEN go to "*" if needed
     */
    transports = {}, 
    // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
    allTypes = "*/".concat("*"), 
    // Anchor tag for parsing the document origin
    originAnchor = document.createElement("a");
    originAnchor.href = location.href;
    // Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
    function addToPrefiltersOrTransports(structure) {
        // dataTypeExpression is optional and defaults to "*"
        return function (dataTypeExpression, func) {
            if (typeof dataTypeExpression !== "string") {
                func = dataTypeExpression;
                dataTypeExpression = "*";
            }
            var dataType, i = 0, dataTypes = dataTypeExpression.toLowerCase().match(rnothtmlwhite) || [];
            if (jQuery.isFunction(func)) {
                // For each dataType in the dataTypeExpression
                while ((dataType = dataTypes[i++])) {
                    // Prepend if requested
                    if (dataType[0] === "+") {
                        dataType = dataType.slice(1) || "*";
                        (structure[dataType] = structure[dataType] || []).unshift(func);
                    }
                    else {
                        (structure[dataType] = structure[dataType] || []).push(func);
                    }
                }
            }
        };
    }
    // Base inspection function for prefilters and transports
    function inspectPrefiltersOrTransports(structure, options, originalOptions, jqXHR) {
        var inspected = {}, seekingTransport = (structure === transports);
        function inspect(dataType) {
            var selected;
            inspected[dataType] = true;
            jQuery.each(structure[dataType] || [], function (_, prefilterOrFactory) {
                var dataTypeOrTransport = prefilterOrFactory(options, originalOptions, jqXHR);
                if (typeof dataTypeOrTransport === "string" &&
                    !seekingTransport && !inspected[dataTypeOrTransport]) {
                    options.dataTypes.unshift(dataTypeOrTransport);
                    inspect(dataTypeOrTransport);
                    return false;
                }
                else if (seekingTransport) {
                    return !(selected = dataTypeOrTransport);
                }
            });
            return selected;
        }
        return inspect(options.dataTypes[0]) || !inspected["*"] && inspect("*");
    }
    // A special extend for ajax options
    // that takes "flat" options (not to be deep extended)
    // Fixes #9887
    function ajaxExtend(target, src) {
        var key, deep, flatOptions = jQuery.ajaxSettings.flatOptions || {};
        for (key in src) {
            if (src[key] !== undefined) {
                (flatOptions[key] ? target : (deep || (deep = {})))[key] = src[key];
            }
        }
        if (deep) {
            jQuery.extend(true, target, deep);
        }
        return target;
    }
    /* Handles responses to an ajax request:
     * - finds the right dataType (mediates between content-type and expected dataType)
     * - returns the corresponding response
     */
    function ajaxHandleResponses(s, jqXHR, responses) {
        var ct, type, finalDataType, firstDataType, contents = s.contents, dataTypes = s.dataTypes;
        // Remove auto dataType and get content-type in the process
        while (dataTypes[0] === "*") {
            dataTypes.shift();
            if (ct === undefined) {
                ct = s.mimeType || jqXHR.getResponseHeader("Content-Type");
            }
        }
        // Check if we're dealing with a known content-type
        if (ct) {
            for (type in contents) {
                if (contents[type] && contents[type].test(ct)) {
                    dataTypes.unshift(type);
                    break;
                }
            }
        }
        // Check to see if we have a response for the expected dataType
        if (dataTypes[0] in responses) {
            finalDataType = dataTypes[0];
        }
        else {
            // Try convertible dataTypes
            for (type in responses) {
                if (!dataTypes[0] || s.converters[type + " " + dataTypes[0]]) {
                    finalDataType = type;
                    break;
                }
                if (!firstDataType) {
                    firstDataType = type;
                }
            }
            // Or just use first one
            finalDataType = finalDataType || firstDataType;
        }
        // If we found a dataType
        // We add the dataType to the list if needed
        // and return the corresponding response
        if (finalDataType) {
            if (finalDataType !== dataTypes[0]) {
                dataTypes.unshift(finalDataType);
            }
            return responses[finalDataType];
        }
    }
    /* Chain conversions given the request and the original response
     * Also sets the responseXXX fields on the jqXHR instance
     */
    function ajaxConvert(s, response, jqXHR, isSuccess) {
        var conv2, current, conv, tmp, prev, converters = {}, 
        // Work with a copy of dataTypes in case we need to modify it for conversion
        dataTypes = s.dataTypes.slice();
        // Create converters map with lowercased keys
        if (dataTypes[1]) {
            for (conv in s.converters) {
                converters[conv.toLowerCase()] = s.converters[conv];
            }
        }
        current = dataTypes.shift();
        // Convert to each sequential dataType
        while (current) {
            if (s.responseFields[current]) {
                jqXHR[s.responseFields[current]] = response;
            }
            // Apply the dataFilter if provided
            if (!prev && isSuccess && s.dataFilter) {
                response = s.dataFilter(response, s.dataType);
            }
            prev = current;
            current = dataTypes.shift();
            if (current) {
                // There's only work to do if current dataType is non-auto
                if (current === "*") {
                    current = prev;
                }
                else if (prev !== "*" && prev !== current) {
                    // Seek a direct converter
                    conv = converters[prev + " " + current] || converters["* " + current];
                    // If none found, seek a pair
                    if (!conv) {
                        for (conv2 in converters) {
                            // If conv2 outputs current
                            tmp = conv2.split(" ");
                            if (tmp[1] === current) {
                                // If prev can be converted to accepted input
                                conv = converters[prev + " " + tmp[0]] ||
                                    converters["* " + tmp[0]];
                                if (conv) {
                                    // Condense equivalence converters
                                    if (conv === true) {
                                        conv = converters[conv2];
                                    }
                                    else if (converters[conv2] !== true) {
                                        current = tmp[0];
                                        dataTypes.unshift(tmp[1]);
                                    }
                                    break;
                                }
                            }
                        }
                    }
                    // Apply converter (if not an equivalence)
                    if (conv !== true) {
                        // Unless errors are allowed to bubble, catch and return them
                        if (conv && s.throws) {
                            response = conv(response);
                        }
                        else {
                            try {
                                response = conv(response);
                            }
                            catch (e) {
                                return {
                                    state: "parsererror",
                                    error: conv ? e : "No conversion from " + prev + " to " + current
                                };
                            }
                        }
                    }
                }
            }
        }
        return { state: "success", data: response };
    }
    jQuery.extend({
        // Counter for holding the number of active queries
        active: 0,
        // Last-Modified header cache for next request
        lastModified: {},
        etag: {},
        ajaxSettings: {
            url: location.href,
            type: "GET",
            isLocal: rlocalProtocol.test(location.protocol),
            global: true,
            processData: true,
            async: true,
            contentType: "application/x-www-form-urlencoded; charset=UTF-8",
            /*
            timeout: 0,
            data: null,
            dataType: null,
            username: null,
            password: null,
            cache: null,
            throws: false,
            traditional: false,
            headers: {},
            */
            accepts: {
                "*": allTypes,
                text: "text/plain",
                html: "text/html",
                xml: "application/xml, text/xml",
                json: "application/json, text/javascript"
            },
            contents: {
                xml: /\bxml\b/,
                html: /\bhtml/,
                json: /\bjson\b/
            },
            responseFields: {
                xml: "responseXML",
                text: "responseText",
                json: "responseJSON"
            },
            // Data converters
            // Keys separate source (or catchall "*") and destination types with a single space
            converters: {
                // Convert anything to text
                "* text": String,
                // Text to html (true = no transformation)
                "text html": true,
                // Evaluate text as a json expression
                "text json": JSON.parse,
                // Parse text as xml
                "text xml": jQuery.parseXML
            },
            // For options that shouldn't be deep extended:
            // you can add your own custom options here if
            // and when you create one that shouldn't be
            // deep extended (see ajaxExtend)
            flatOptions: {
                url: true,
                context: true
            }
        },
        // Creates a full fledged settings object into target
        // with both ajaxSettings and settings fields.
        // If target is omitted, writes into ajaxSettings.
        ajaxSetup: function (target, settings) {
            return settings ?
                // Building a settings object
                ajaxExtend(ajaxExtend(target, jQuery.ajaxSettings), settings) :
                // Extending ajaxSettings
                ajaxExtend(jQuery.ajaxSettings, target);
        },
        ajaxPrefilter: addToPrefiltersOrTransports(prefilters),
        ajaxTransport: addToPrefiltersOrTransports(transports),
        // Main method
        ajax: function (url, options) {
            // If url is an object, simulate pre-1.5 signature
            if (typeof url === "object") {
                options = url;
                url = undefined;
            }
            // Force options to be an object
            options = options || {};
            var transport, 
            // URL without anti-cache param
            cacheURL, 
            // Response headers
            responseHeadersString, responseHeaders, 
            // timeout handle
            timeoutTimer, 
            // Url cleanup var
            urlAnchor, 
            // Request state (becomes false upon send and true upon completion)
            completed, 
            // To know if global events are to be dispatched
            fireGlobals, 
            // Loop variable
            i, 
            // uncached part of the url
            uncached, 
            // Create the final options object
            s = jQuery.ajaxSetup({}, options), 
            // Callbacks context
            callbackContext = s.context || s, 
            // Context for global events is callbackContext if it is a DOM node or jQuery collection
            globalEventContext = s.context &&
                (callbackContext.nodeType || callbackContext.jquery) ?
                jQuery(callbackContext) :
                jQuery.event, 
            // Deferreds
            deferred = jQuery.Deferred(), completeDeferred = jQuery.Callbacks("once memory"), 
            // Status-dependent callbacks
            statusCode = s.statusCode || {}, 
            // Headers (they are sent all at once)
            requestHeaders = {}, requestHeadersNames = {}, 
            // Default abort message
            strAbort = "canceled", 
            // Fake xhr
            jqXHR = {
                readyState: 0,
                // Builds headers hashtable if needed
                getResponseHeader: function (key) {
                    var match;
                    if (completed) {
                        if (!responseHeaders) {
                            responseHeaders = {};
                            while ((match = rheaders.exec(responseHeadersString))) {
                                responseHeaders[match[1].toLowerCase()] = match[2];
                            }
                        }
                        match = responseHeaders[key.toLowerCase()];
                    }
                    return match == null ? null : match;
                },
                // Raw string
                getAllResponseHeaders: function () {
                    return completed ? responseHeadersString : null;
                },
                // Caches the header
                setRequestHeader: function (name, value) {
                    if (completed == null) {
                        name = requestHeadersNames[name.toLowerCase()] =
                            requestHeadersNames[name.toLowerCase()] || name;
                        requestHeaders[name] = value;
                    }
                    return this;
                },
                // Overrides response content-type header
                overrideMimeType: function (type) {
                    if (completed == null) {
                        s.mimeType = type;
                    }
                    return this;
                },
                // Status-dependent callbacks
                statusCode: function (map) {
                    var code;
                    if (map) {
                        if (completed) {
                            // Execute the appropriate callbacks
                            jqXHR.always(map[jqXHR.status]);
                        }
                        else {
                            // Lazy-add the new callbacks in a way that preserves old ones
                            for (code in map) {
                                statusCode[code] = [statusCode[code], map[code]];
                            }
                        }
                    }
                    return this;
                },
                // Cancel the request
                abort: function (statusText) {
                    var finalText = statusText || strAbort;
                    if (transport) {
                        transport.abort(finalText);
                    }
                    done(0, finalText);
                    return this;
                }
            };
            // Attach deferreds
            deferred.promise(jqXHR);
            // Add protocol if not provided (prefilters might expect it)
            // Handle falsy url in the settings object (#10093: consistency with old signature)
            // We also use the url parameter if available
            s.url = ((url || s.url || location.href) + "")
                .replace(rprotocol, location.protocol + "//");
            // Alias method option to type as per ticket #12004
            s.type = options.method || options.type || s.method || s.type;
            // Extract dataTypes list
            s.dataTypes = (s.dataType || "*").toLowerCase().match(rnothtmlwhite) || [""];
            // A cross-domain request is in order when the origin doesn't match the current origin.
            if (s.crossDomain == null) {
                urlAnchor = document.createElement("a");
                // Support: IE <=8 - 11, Edge 12 - 13
                // IE throws exception on accessing the href property if url is malformed,
                // e.g. http://example.com:80x/
                try {
                    urlAnchor.href = s.url;
                    // Support: IE <=8 - 11 only
                    // Anchor's host property isn't correctly set when s.url is relative
                    urlAnchor.href = urlAnchor.href;
                    s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !==
                        urlAnchor.protocol + "//" + urlAnchor.host;
                }
                catch (e) {
                    // If there is an error parsing the URL, assume it is crossDomain,
                    // it can be rejected by the transport if it is invalid
                    s.crossDomain = true;
                }
            }
            // Convert data if not already a string
            if (s.data && s.processData && typeof s.data !== "string") {
                s.data = jQuery.param(s.data, s.traditional);
            }
            // Apply prefilters
            inspectPrefiltersOrTransports(prefilters, s, options, jqXHR);
            // If request was aborted inside a prefilter, stop there
            if (completed) {
                return jqXHR;
            }
            // We can fire global events as of now if asked to
            // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118)
            fireGlobals = jQuery.event && s.global;
            // Watch for a new set of requests
            if (fireGlobals && jQuery.active++ === 0) {
                jQuery.event.trigger("ajaxStart");
            }
            // Uppercase the type
            s.type = s.type.toUpperCase();
            // Determine if request has content
            s.hasContent = !rnoContent.test(s.type);
            // Save the URL in case we're toying with the If-Modified-Since
            // and/or If-None-Match header later on
            // Remove hash to simplify url manipulation
            cacheURL = s.url.replace(rhash, "");
            // More options handling for requests with no content
            if (!s.hasContent) {
                // Remember the hash so we can put it back
                uncached = s.url.slice(cacheURL.length);
                // If data is available, append data to url
                if (s.data) {
                    cacheURL += (rquery.test(cacheURL) ? "&" : "?") + s.data;
                    // #9682: remove data so that it's not used in an eventual retry
                    delete s.data;
                }
                // Add or update anti-cache param if needed
                if (s.cache === false) {
                    cacheURL = cacheURL.replace(rantiCache, "$1");
                    uncached = (rquery.test(cacheURL) ? "&" : "?") + "_=" + (nonce++) + uncached;
                }
                // Put hash and anti-cache on the URL that will be requested (gh-1732)
                s.url = cacheURL + uncached;
            }
            else if (s.data && s.processData &&
                (s.contentType || "").indexOf("application/x-www-form-urlencoded") === 0) {
                s.data = s.data.replace(r20, "+");
            }
            // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
            if (s.ifModified) {
                if (jQuery.lastModified[cacheURL]) {
                    jqXHR.setRequestHeader("If-Modified-Since", jQuery.lastModified[cacheURL]);
                }
                if (jQuery.etag[cacheURL]) {
                    jqXHR.setRequestHeader("If-None-Match", jQuery.etag[cacheURL]);
                }
            }
            // Set the correct header, if data is being sent
            if (s.data && s.hasContent && s.contentType !== false || options.contentType) {
                jqXHR.setRequestHeader("Content-Type", s.contentType);
            }
            // Set the Accepts header for the server, depending on the dataType
            jqXHR.setRequestHeader("Accept", s.dataTypes[0] && s.accepts[s.dataTypes[0]] ?
                s.accepts[s.dataTypes[0]] +
                    (s.dataTypes[0] !== "*" ? ", " + allTypes + "; q=0.01" : "") :
                s.accepts["*"]);
            // Check for headers option
            for (i in s.headers) {
                jqXHR.setRequestHeader(i, s.headers[i]);
            }
            // Allow custom headers/mimetypes and early abort
            if (s.beforeSend &&
                (s.beforeSend.call(callbackContext, jqXHR, s) === false || completed)) {
                // Abort if not done already and return
                return jqXHR.abort();
            }
            // Aborting is no longer a cancellation
            strAbort = "abort";
            // Install callbacks on deferreds
            completeDeferred.add(s.complete);
            jqXHR.done(s.success);
            jqXHR.fail(s.error);
            // Get transport
            transport = inspectPrefiltersOrTransports(transports, s, options, jqXHR);
            // If no transport, we auto-abort
            if (!transport) {
                done(-1, "No Transport");
            }
            else {
                jqXHR.readyState = 1;
                // Send global event
                if (fireGlobals) {
                    globalEventContext.trigger("ajaxSend", [jqXHR, s]);
                }
                // If request was aborted inside ajaxSend, stop there
                if (completed) {
                    return jqXHR;
                }
                // Timeout
                if (s.async && s.timeout > 0) {
                    timeoutTimer = window.setTimeout(function () {
                        jqXHR.abort("timeout");
                    }, s.timeout);
                }
                try {
                    completed = false;
                    transport.send(requestHeaders, done);
                }
                catch (e) {
                    // Rethrow post-completion exceptions
                    if (completed) {
                        throw e;
                    }
                    // Propagate others as results
                    done(-1, e);
                }
            }
            // Callback for when everything is done
            function done(status, nativeStatusText, responses, headers) {
                var isSuccess, success, error, response, modified, statusText = nativeStatusText;
                // Ignore repeat invocations
                if (completed) {
                    return;
                }
                completed = true;
                // Clear timeout if it exists
                if (timeoutTimer) {
                    window.clearTimeout(timeoutTimer);
                }
                // Dereference transport for early garbage collection
                // (no matter how long the jqXHR object will be used)
                transport = undefined;
                // Cache response headers
                responseHeadersString = headers || "";
                // Set readyState
                jqXHR.readyState = status > 0 ? 4 : 0;
                // Determine if successful
                isSuccess = status >= 200 && status < 300 || status === 304;
                // Get response data
                if (responses) {
                    response = ajaxHandleResponses(s, jqXHR, responses);
                }
                // Convert no matter what (that way responseXXX fields are always set)
                response = ajaxConvert(s, response, jqXHR, isSuccess);
                // If successful, handle type chaining
                if (isSuccess) {
                    // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
                    if (s.ifModified) {
                        modified = jqXHR.getResponseHeader("Last-Modified");
                        if (modified) {
                            jQuery.lastModified[cacheURL] = modified;
                        }
                        modified = jqXHR.getResponseHeader("etag");
                        if (modified) {
                            jQuery.etag[cacheURL] = modified;
                        }
                    }
                    // if no content
                    if (status === 204 || s.type === "HEAD") {
                        statusText = "nocontent";
                    }
                    else if (status === 304) {
                        statusText = "notmodified";
                    }
                    else {
                        statusText = response.state;
                        success = response.data;
                        error = response.error;
                        isSuccess = !error;
                    }
                }
                else {
                    // Extract error from statusText and normalize for non-aborts
                    error = statusText;
                    if (status || !statusText) {
                        statusText = "error";
                        if (status < 0) {
                            status = 0;
                        }
                    }
                }
                // Set data for the fake xhr object
                jqXHR.status = status;
                jqXHR.statusText = (nativeStatusText || statusText) + "";
                // Success/Error
                if (isSuccess) {
                    deferred.resolveWith(callbackContext, [success, statusText, jqXHR]);
                }
                else {
                    deferred.rejectWith(callbackContext, [jqXHR, statusText, error]);
                }
                // Status-dependent callbacks
                jqXHR.statusCode(statusCode);
                statusCode = undefined;
                if (fireGlobals) {
                    globalEventContext.trigger(isSuccess ? "ajaxSuccess" : "ajaxError", [jqXHR, s, isSuccess ? success : error]);
                }
                // Complete
                completeDeferred.fireWith(callbackContext, [jqXHR, statusText]);
                if (fireGlobals) {
                    globalEventContext.trigger("ajaxComplete", [jqXHR, s]);
                    // Handle the global AJAX counter
                    if (!(--jQuery.active)) {
                        jQuery.event.trigger("ajaxStop");
                    }
                }
            }
            return jqXHR;
        },
        getJSON: function (url, data, callback) {
            return jQuery.get(url, data, callback, "json");
        },
        getScript: function (url, callback) {
            return jQuery.get(url, undefined, callback, "script");
        }
    });
    jQuery.each(["get", "post"], function (i, method) {
        jQuery[method] = function (url, data, callback, type) {
            // Shift arguments if data argument was omitted
            if (jQuery.isFunction(data)) {
                type = type || callback;
                callback = data;
                data = undefined;
            }
            // The url can be an options object (which then must have .url)
            return jQuery.ajax(jQuery.extend({
                url: url,
                type: method,
                dataType: type,
                data: data,
                success: callback
            }, jQuery.isPlainObject(url) && url));
        };
    });
    jQuery._evalUrl = function (url) {
        return jQuery.ajax({
            url: url,
            // Make this explicit, since user can override this through ajaxSetup (#11264)
            type: "GET",
            dataType: "script",
            cache: true,
            async: false,
            global: false,
            "throws": true
        });
    };
    jQuery.fn.extend({
        wrapAll: function (html) {
            var wrap;
            if (this[0]) {
                if (jQuery.isFunction(html)) {
                    html = html.call(this[0]);
                }
                // The elements to wrap the target around
                wrap = jQuery(html, this[0].ownerDocument).eq(0).clone(true);
                if (this[0].parentNode) {
                    wrap.insertBefore(this[0]);
                }
                wrap.map(function () {
                    var elem = this;
                    while (elem.firstElementChild) {
                        elem = elem.firstElementChild;
                    }
                    return elem;
                }).append(this);
            }
            return this;
        },
        wrapInner: function (html) {
            if (jQuery.isFunction(html)) {
                return this.each(function (i) {
                    jQuery(this).wrapInner(html.call(this, i));
                });
            }
            return this.each(function () {
                var self = jQuery(this), contents = self.contents();
                if (contents.length) {
                    contents.wrapAll(html);
                }
                else {
                    self.append(html);
                }
            });
        },
        wrap: function (html) {
            var isFunction = jQuery.isFunction(html);
            return this.each(function (i) {
                jQuery(this).wrapAll(isFunction ? html.call(this, i) : html);
            });
        },
        unwrap: function (selector) {
            this.parent(selector).not("body").each(function () {
                jQuery(this).replaceWith(this.childNodes);
            });
            return this;
        }
    });
    jQuery.expr.pseudos.hidden = function (elem) {
        return !jQuery.expr.pseudos.visible(elem);
    };
    jQuery.expr.pseudos.visible = function (elem) {
        return !!(elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length);
    };
    jQuery.ajaxSettings.xhr = function () {
        try {
            return new window.XMLHttpRequest();
        }
        catch (e) { }
    };
    var xhrSuccessStatus = {
        // File protocol always yields status code 0, assume 200
        0: 200,
        // Support: IE <=9 only
        // #1450: sometimes IE returns 1223 when it should be 204
        1223: 204
    }, xhrSupported = jQuery.ajaxSettings.xhr();
    support.cors = !!xhrSupported && ("withCredentials" in xhrSupported);
    support.ajax = xhrSupported = !!xhrSupported;
    jQuery.ajaxTransport(function (options) {
        var callback, errorCallback;
        // Cross domain only allowed if supported through XMLHttpRequest
        if (support.cors || xhrSupported && !options.crossDomain) {
            return {
                send: function (headers, complete) {
                    var i, xhr = options.xhr();
                    xhr.open(options.type, options.url, options.async, options.username, options.password);
                    // Apply custom fields if provided
                    if (options.xhrFields) {
                        for (i in options.xhrFields) {
                            xhr[i] = options.xhrFields[i];
                        }
                    }
                    // Override mime type if needed
                    if (options.mimeType && xhr.overrideMimeType) {
                        xhr.overrideMimeType(options.mimeType);
                    }
                    // X-Requested-With header
                    // For cross-domain requests, seeing as conditions for a preflight are
                    // akin to a jigsaw puzzle, we simply never set it to be sure.
                    // (it can always be set on a per-request basis or even using ajaxSetup)
                    // For same-domain requests, won't change header if already provided.
                    if (!options.crossDomain && !headers["X-Requested-With"]) {
                        headers["X-Requested-With"] = "XMLHttpRequest";
                    }
                    // Set headers
                    for (i in headers) {
                        xhr.setRequestHeader(i, headers[i]);
                    }
                    // Callback
                    callback = function (type) {
                        return function () {
                            if (callback) {
                                callback = errorCallback = xhr.onload =
                                    xhr.onerror = xhr.onabort = xhr.onreadystatechange = null;
                                if (type === "abort") {
                                    xhr.abort();
                                }
                                else if (type === "error") {
                                    // Support: IE <=9 only
                                    // On a manual native abort, IE9 throws
                                    // errors on any property access that is not readyState
                                    if (typeof xhr.status !== "number") {
                                        complete(0, "error");
                                    }
                                    else {
                                        complete(
                                        // File: protocol always yields status 0; see #8605, #14207
                                        xhr.status, xhr.statusText);
                                    }
                                }
                                else {
                                    complete(xhrSuccessStatus[xhr.status] || xhr.status, xhr.statusText, 
                                    // Support: IE <=9 only
                                    // IE9 has no XHR2 but throws on binary (trac-11426)
                                    // For XHR2 non-text, let the caller handle it (gh-2498)
                                    (xhr.responseType || "text") !== "text" ||
                                        typeof xhr.responseText !== "string" ?
                                        { binary: xhr.response } :
                                        { text: xhr.responseText }, xhr.getAllResponseHeaders());
                                }
                            }
                        };
                    };
                    // Listen to events
                    xhr.onload = callback();
                    errorCallback = xhr.onerror = callback("error");
                    // Support: IE 9 only
                    // Use onreadystatechange to replace onabort
                    // to handle uncaught aborts
                    if (xhr.onabort !== undefined) {
                        xhr.onabort = errorCallback;
                    }
                    else {
                        xhr.onreadystatechange = function () {
                            // Check readyState before timeout as it changes
                            if (xhr.readyState === 4) {
                                // Allow onerror to be called first,
                                // but that will not handle a native abort
                                // Also, save errorCallback to a variable
                                // as xhr.onerror cannot be accessed
                                window.setTimeout(function () {
                                    if (callback) {
                                        errorCallback();
                                    }
                                });
                            }
                        };
                    }
                    // Create the abort callback
                    callback = callback("abort");
                    try {
                        // Do send the request (this may raise an exception)
                        xhr.send(options.hasContent && options.data || null);
                    }
                    catch (e) {
                        // #14683: Only rethrow if this hasn't been notified as an error yet
                        if (callback) {
                            throw e;
                        }
                    }
                },
                abort: function () {
                    if (callback) {
                        callback();
                    }
                }
            };
        }
    });
    // Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432)
    jQuery.ajaxPrefilter(function (s) {
        if (s.crossDomain) {
            s.contents.script = false;
        }
    });
    // Install script dataType
    jQuery.ajaxSetup({
        accepts: {
            script: "text/javascript, application/javascript, " +
                "application/ecmascript, application/x-ecmascript"
        },
        contents: {
            script: /\b(?:java|ecma)script\b/
        },
        converters: {
            "text script": function (text) {
                jQuery.globalEval(text);
                return text;
            }
        }
    });
    // Handle cache's special case and crossDomain
    jQuery.ajaxPrefilter("script", function (s) {
        if (s.cache === undefined) {
            s.cache = false;
        }
        if (s.crossDomain) {
            s.type = "GET";
        }
    });
    // Bind script tag hack transport
    jQuery.ajaxTransport("script", function (s) {
        // This transport only deals with cross domain requests
        if (s.crossDomain) {
            var script, callback;
            return {
                send: function (_, complete) {
                    script = jQuery("<script>").prop({
                        charset: s.scriptCharset,
                        src: s.url
                    }).on("load error", callback = function (evt) {
                        script.remove();
                        callback = null;
                        if (evt) {
                            complete(evt.type === "error" ? 404 : 200, evt.type);
                        }
                    });
                    // Use native DOM manipulation to avoid our domManip AJAX trickery
                    document.head.appendChild(script[0]);
                },
                abort: function () {
                    if (callback) {
                        callback();
                    }
                }
            };
        }
    });
    var oldCallbacks = [], rjsonp = /(=)\?(?=&|$)|\?\?/;
    // Default jsonp settings
    jQuery.ajaxSetup({
        jsonp: "callback",
        jsonpCallback: function () {
            var callback = oldCallbacks.pop() || (jQuery.expando + "_" + (nonce++));
            this[callback] = true;
            return callback;
        }
    });
    // Detect, normalize options and install callbacks for jsonp requests
    jQuery.ajaxPrefilter("json jsonp", function (s, originalSettings, jqXHR) {
        var callbackName, overwritten, responseContainer, jsonProp = s.jsonp !== false && (rjsonp.test(s.url) ?
            "url" :
            typeof s.data === "string" &&
                (s.contentType || "")
                    .indexOf("application/x-www-form-urlencoded") === 0 &&
                rjsonp.test(s.data) && "data");
        // Handle iff the expected data type is "jsonp" or we have a parameter to set
        if (jsonProp || s.dataTypes[0] === "jsonp") {
            // Get callback name, remembering preexisting value associated with it
            callbackName = s.jsonpCallback = jQuery.isFunction(s.jsonpCallback) ?
                s.jsonpCallback() :
                s.jsonpCallback;
            // Insert callback into url or form data
            if (jsonProp) {
                s[jsonProp] = s[jsonProp].replace(rjsonp, "$1" + callbackName);
            }
            else if (s.jsonp !== false) {
                s.url += (rquery.test(s.url) ? "&" : "?") + s.jsonp + "=" + callbackName;
            }
            // Use data converter to retrieve json after script execution
            s.converters["script json"] = function () {
                if (!responseContainer) {
                    jQuery.error(callbackName + " was not called");
                }
                return responseContainer[0];
            };
            // Force json dataType
            s.dataTypes[0] = "json";
            // Install callback
            overwritten = window[callbackName];
            window[callbackName] = function () {
                responseContainer = arguments;
            };
            // Clean-up function (fires after converters)
            jqXHR.always(function () {
                // If previous value didn't exist - remove it
                if (overwritten === undefined) {
                    jQuery(window).removeProp(callbackName);
                }
                else {
                    window[callbackName] = overwritten;
                }
                // Save back as free
                if (s[callbackName]) {
                    // Make sure that re-using the options doesn't screw things around
                    s.jsonpCallback = originalSettings.jsonpCallback;
                    // Save the callback name for future use
                    oldCallbacks.push(callbackName);
                }
                // Call if it was a function and we have a response
                if (responseContainer && jQuery.isFunction(overwritten)) {
                    overwritten(responseContainer[0]);
                }
                responseContainer = overwritten = undefined;
            });
            // Delegate to script
            return "script";
        }
    });
    // Support: Safari 8 only
    // In Safari 8 documents created via document.implementation.createHTMLDocument
    // collapse sibling forms: the second one becomes a child of the first one.
    // Because of that, this security measure has to be disabled in Safari 8.
    // https://bugs.webkit.org/show_bug.cgi?id=137337
    support.createHTMLDocument = (function () {
        var body = document.implementation.createHTMLDocument("").body;
        body.innerHTML = "<form></form><form></form>";
        return body.childNodes.length === 2;
    })();
    // Argument "data" should be string of html
    // context (optional): If specified, the fragment will be created in this context,
    // defaults to document
    // keepScripts (optional): If true, will include scripts passed in the html string
    jQuery.parseHTML = function (data, context, keepScripts) {
        if (typeof data !== "string") {
            return [];
        }
        if (typeof context === "boolean") {
            keepScripts = context;
            context = false;
        }
        var base, parsed, scripts;
        if (!context) {
            // Stop scripts or inline event handlers from being executed immediately
            // by using document.implementation
            if (support.createHTMLDocument) {
                context = document.implementation.createHTMLDocument("");
                // Set the base href for the created document
                // so any parsed elements with URLs
                // are based on the document's URL (gh-2965)
                base = context.createElement("base");
                base.href = document.location.href;
                context.head.appendChild(base);
            }
            else {
                context = document;
            }
        }
        parsed = rsingleTag.exec(data);
        scripts = !keepScripts && [];
        // Single tag
        if (parsed) {
            return [context.createElement(parsed[1])];
        }
        parsed = buildFragment([data], context, scripts);
        if (scripts && scripts.length) {
            jQuery(scripts).remove();
        }
        return jQuery.merge([], parsed.childNodes);
    };
    /**
     * Load a url into a page
     */
    jQuery.fn.load = function (url, params, callback) {
        var selector, type, response, self = this, off = url.indexOf(" ");
        if (off > -1) {
            selector = stripAndCollapse(url.slice(off));
            url = url.slice(0, off);
        }
        // If it's a function
        if (jQuery.isFunction(params)) {
            // We assume that it's the callback
            callback = params;
            params = undefined;
        }
        else if (params && typeof params === "object") {
            type = "POST";
        }
        // If we have elements to modify, make the request
        if (self.length > 0) {
            jQuery.ajax({
                url: url,
                // If "type" variable is undefined, then "GET" method will be used.
                // Make value of this field explicit since
                // user can override it through ajaxSetup method
                type: type || "GET",
                dataType: "html",
                data: params
            }).done(function (responseText) {
                // Save response for use in complete callback
                response = arguments;
                self.html(selector ?
                    // If a selector was specified, locate the right elements in a dummy div
                    // Exclude scripts to avoid IE 'Permission Denied' errors
                    jQuery("<div>").append(jQuery.parseHTML(responseText)).find(selector) :
                    // Otherwise use the full result
                    responseText);
                // If the request succeeds, this function gets "data", "status", "jqXHR"
                // but they are ignored because response was set above.
                // If it fails, this function gets "jqXHR", "status", "error"
            }).always(callback && function (jqXHR, status) {
                self.each(function () {
                    callback.apply(this, response || [jqXHR.responseText, status, jqXHR]);
                });
            });
        }
        return this;
    };
    // Attach a bunch of functions for handling common AJAX events
    jQuery.each([
        "ajaxStart",
        "ajaxStop",
        "ajaxComplete",
        "ajaxError",
        "ajaxSuccess",
        "ajaxSend"
    ], function (i, type) {
        jQuery.fn[type] = function (fn) {
            return this.on(type, fn);
        };
    });
    jQuery.expr.pseudos.animated = function (elem) {
        return jQuery.grep(jQuery.timers, function (fn) {
            return elem === fn.elem;
        }).length;
    };
    /**
     * Gets a window from an element
     */
    function getWindow(elem) {
        return jQuery.isWindow(elem) ? elem : elem.nodeType === 9 && elem.defaultView;
    }
    jQuery.offset = {
        setOffset: function (elem, options, i) {
            var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition, position = jQuery.css(elem, "position"), curElem = jQuery(elem), props = {};
            // Set position first, in-case top/left are set even on static elem
            if (position === "static") {
                elem.style.position = "relative";
            }
            curOffset = curElem.offset();
            curCSSTop = jQuery.css(elem, "top");
            curCSSLeft = jQuery.css(elem, "left");
            calculatePosition = (position === "absolute" || position === "fixed") &&
                (curCSSTop + curCSSLeft).indexOf("auto") > -1;
            // Need to be able to calculate position if either
            // top or left is auto and position is either absolute or fixed
            if (calculatePosition) {
                curPosition = curElem.position();
                curTop = curPosition.top;
                curLeft = curPosition.left;
            }
            else {
                curTop = parseFloat(curCSSTop) || 0;
                curLeft = parseFloat(curCSSLeft) || 0;
            }
            if (jQuery.isFunction(options)) {
                // Use jQuery.extend here to allow modification of coordinates argument (gh-1848)
                options = options.call(elem, i, jQuery.extend({}, curOffset));
            }
            if (options.top != null) {
                props.top = (options.top - curOffset.top) + curTop;
            }
            if (options.left != null) {
                props.left = (options.left - curOffset.left) + curLeft;
            }
            if ("using" in options) {
                options.using.call(elem, props);
            }
            else {
                curElem.css(props);
            }
        }
    };
    jQuery.fn.extend({
        offset: function (options) {
            // Preserve chaining for setter
            if (arguments.length) {
                return options === undefined ?
                    this :
                    this.each(function (i) {
                        jQuery.offset.setOffset(this, options, i);
                    });
            }
            var docElem, win, rect, doc, elem = this[0];
            if (!elem) {
                return;
            }
            // Support: IE <=11 only
            // Running getBoundingClientRect on a
            // disconnected node in IE throws an error
            if (!elem.getClientRects().length) {
                return { top: 0, left: 0 };
            }
            rect = elem.getBoundingClientRect();
            // Make sure element is not hidden (display: none)
            if (rect.width || rect.height) {
                doc = elem.ownerDocument;
                win = getWindow(doc);
                docElem = doc.documentElement;
                return {
                    top: rect.top + win.pageYOffset - docElem.clientTop,
                    left: rect.left + win.pageXOffset - docElem.clientLeft
                };
            }
            // Return zeros for disconnected and hidden elements (gh-2310)
            return rect;
        },
        position: function () {
            if (!this[0]) {
                return;
            }
            var offsetParent, offset, elem = this[0], parentOffset = { top: 0, left: 0 };
            // Fixed elements are offset from window (parentOffset = {top:0, left: 0},
            // because it is its only offset parent
            if (jQuery.css(elem, "position") === "fixed") {
                // Assume getBoundingClientRect is there when computed position is fixed
                offset = elem.getBoundingClientRect();
            }
            else {
                // Get *real* offsetParent
                offsetParent = this.offsetParent();
                // Get correct offsets
                offset = this.offset();
                if (!jQuery.nodeName(offsetParent[0], "html")) {
                    parentOffset = offsetParent.offset();
                }
                // Add offsetParent borders
                parentOffset = {
                    top: parentOffset.top + jQuery.css(offsetParent[0], "borderTopWidth", true),
                    left: parentOffset.left + jQuery.css(offsetParent[0], "borderLeftWidth", true)
                };
            }
            // Subtract parent offsets and element margins
            return {
                top: offset.top - parentOffset.top - jQuery.css(elem, "marginTop", true),
                left: offset.left - parentOffset.left - jQuery.css(elem, "marginLeft", true)
            };
        },
        // This method will return documentElement in the following cases:
        // 1) For the element inside the iframe without offsetParent, this method will return
        //    documentElement of the parent window
        // 2) For the hidden or detached element
        // 3) For body or html element, i.e. in case of the html node - it will return itself
        //
        // but those exceptions were never presented as a real life use-cases
        // and might be considered as more preferable results.
        //
        // This logic, however, is not guaranteed and can change at any point in the future
        offsetParent: function () {
            return this.map(function () {
                var offsetParent = this.offsetParent;
                while (offsetParent && jQuery.css(offsetParent, "position") === "static") {
                    offsetParent = offsetParent.offsetParent;
                }
                return offsetParent || documentElement;
            });
        }
    });
    // Create scrollLeft and scrollTop methods
    jQuery.each({ scrollLeft: "pageXOffset", scrollTop: "pageYOffset" }, function (method, prop) {
        var top = "pageYOffset" === prop;
        jQuery.fn[method] = function (val) {
            return access(this, function (elem, method, val) {
                var win = getWindow(elem);
                if (val === undefined) {
                    return win ? win[prop] : elem[method];
                }
                if (win) {
                    win.scrollTo(!top ? val : win.pageXOffset, top ? val : win.pageYOffset);
                }
                else {
                    elem[method] = val;
                }
            }, method, val, arguments.length);
        };
    });
    // Support: Safari <=7 - 9.1, Chrome <=37 - 49
    // Add the top/left cssHooks using jQuery.fn.position
    // Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
    // Blink bug: https://bugs.chromium.org/p/chromium/issues/detail?id=589347
    // getComputedStyle returns percent when specified for top/left/bottom/right;
    // rather than make the css module depend on the offset module, just check for it here
    jQuery.each(["top", "left"], function (i, prop) {
        jQuery.cssHooks[prop] = addGetHookIf(support.pixelPosition, function (elem, computed) {
            if (computed) {
                computed = curCSS(elem, prop);
                // If curCSS returns percentage, fallback to offset
                return rnumnonpx.test(computed) ?
                    jQuery(elem).position()[prop] + "px" :
                    computed;
            }
        });
    });
    // Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods
    jQuery.each({ Height: "height", Width: "width" }, function (name, type) {
        jQuery.each({ padding: "inner" + name, content: type, "": "outer" + name }, function (defaultExtra, funcName) {
            // Margin is only for outerHeight, outerWidth
            jQuery.fn[funcName] = function (margin, value) {
                var chainable = arguments.length && (defaultExtra || typeof margin !== "boolean"), extra = defaultExtra || (margin === true || value === true ? "margin" : "border");
                return access(this, function (elem, type, value) {
                    var doc;
                    if (jQuery.isWindow(elem)) {
                        // $( window ).outerWidth/Height return w/h including scrollbars (gh-1729)
                        return funcName.indexOf("outer") === 0 ?
                            elem["inner" + name] :
                            elem.document.documentElement["client" + name];
                    }
                    // Get document width or height
                    if (elem.nodeType === 9) {
                        doc = elem.documentElement;
                        // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height],
                        // whichever is greatest
                        return Math.max(elem.body["scroll" + name], doc["scroll" + name], elem.body["offset" + name], doc["offset" + name], doc["client" + name]);
                    }
                    return value === undefined ?
                        // Get width or height on the element, requesting but not forcing parseFloat
                        jQuery.css(elem, type, extra) :
                        // Set width or height on the element
                        jQuery.style(elem, type, value, extra);
                }, type, chainable ? margin : undefined, chainable);
            };
        });
    });
    jQuery.fn.extend({
        bind: function (types, data, fn) {
            return this.on(types, null, data, fn);
        },
        unbind: function (types, fn) {
            return this.off(types, null, fn);
        },
        delegate: function (selector, types, data, fn) {
            return this.on(types, selector, data, fn);
        },
        undelegate: function (selector, types, fn) {
            // ( namespace ) or ( selector, types [, fn] )
            return arguments.length === 1 ?
                this.off(selector, "**") :
                this.off(types, selector || "**", fn);
        }
    });
    jQuery.parseJSON = JSON.parse;
    // Register as a named AMD module, since jQuery can be concatenated with other
    // files that may use define, but not via a proper concatenation script that
    // understands anonymous AMD modules. A named AMD is safest and most robust
    // way to register. Lowercase jquery is used because AMD module names are
    // derived from file names, and jQuery is normally delivered in a lowercase
    // file name. Do this after creating the global so that if an AMD module wants
    // to call noConflict to hide this version of jQuery, it will work.
    // Note that for maximum portability, libraries that are not jQuery should
    // declare themselves as anonymous modules, and avoid setting a global if an
    // AMD loader is present. jQuery is a special case. For more information, see
    // https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon
    if (typeof define === "function" && define.amd) {
        define("jquery", [], function () {
            return jQuery;
        });
    }
    var 
    // Map over jQuery in case of overwrite
    _jQuery = window.jQuery, 
    // Map over the $ in case of overwrite
    _$ = window.$;
    jQuery.noConflict = function (deep) {
        if (window.$ === jQuery) {
            window.$ = _$;
        }
        if (deep && window.jQuery === jQuery) {
            window.jQuery = _jQuery;
        }
        return jQuery;
    };
    // Expose jQuery and $ identifiers, even in AMD
    // (#7102#comment:10, https://github.com/jquery/jquery/pull/557)
    // and CommonJS for browser emulators (#13566)
    if (!noGlobal) {
        window.jQuery = window.$ = jQuery;
    }
    return jQuery;
});
//# sourceMappingURL=02. jquery.js.map 
//# sourceMappingURL=02. jquery.js.map 
//# sourceMappingURL=02. jquery.js.map 
//# sourceMappingURL=02. jquery.js.map 
//# sourceMappingURL=02. jquery.js.map 
//# sourceMappingURL=02. jquery.js.map 
//# sourceMappingURL=02. jquery.js.map 
//# sourceMappingURL=02. jquery.js.map 
//# sourceMappingURL=02. jquery.js.map 
//# sourceMappingURL=02. jquery.js.map 
//# sourceMappingURL=02. jquery.js.map 
//# sourceMappingURL=02. jquery.js.map 
//# sourceMappingURL=02. jquery.js.map 
//# sourceMappingURL=02. jquery.js.map 
//# sourceMappingURL=02. jquery.js.map 
//# sourceMappingURL=02. jquery.js.map;
/*!
  * Bootstrap v4.0.0 (https://getbootstrap.com)
  * Copyright 2011-2018 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
  */
(function (global, factory) {
    typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('jquery'), require('popper.js')) :
        typeof define === 'function' && define.amd ? define(['exports', 'jquery', 'popper.js'], factory) :
            (factory((global.bootstrap = {}), global.jQuery, global.Popper));
}(this, (function (exports, $, Popper) {
    'use strict';

    $ = $ && $.hasOwnProperty('default') ? $['default'] : $;
    Popper = Popper && Popper.hasOwnProperty('default') ? Popper['default'] : Popper;

    function _defineProperties(target, props) {
        for (var i = 0; i < props.length; i++) {
            var descriptor = props[i];
            descriptor.enumerable = descriptor.enumerable || false;
            descriptor.configurable = true;
            if ("value" in descriptor) descriptor.writable = true;
            Object.defineProperty(target, descriptor.key, descriptor);
        }
    }

    function _createClass(Constructor, protoProps, staticProps) {
        if (protoProps) _defineProperties(Constructor.prototype, protoProps);
        if (staticProps) _defineProperties(Constructor, staticProps);
        return Constructor;
    }

    function _extends() {
        _extends = Object.assign || function (target) {
            for (var i = 1; i < arguments.length; i++) {
                var source = arguments[i];

                for (var key in source) {
                    if (Object.prototype.hasOwnProperty.call(source, key)) {
                        target[key] = source[key];
                    }
                }
            }

            return target;
        };

        return _extends.apply(this, arguments);
    }

    function _inheritsLoose(subClass, superClass) {
        subClass.prototype = Object.create(superClass.prototype);
        subClass.prototype.constructor = subClass;
        subClass.__proto__ = superClass;
    }

    /**
     * --------------------------------------------------------------------------
     * Bootstrap (v4.0.0): util.js
     * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
     * --------------------------------------------------------------------------
     */

    var Util = function ($$$1) {
        /**
         * ------------------------------------------------------------------------
         * Private TransitionEnd Helpers
         * ------------------------------------------------------------------------
         */
        var transition = false;
        var MAX_UID = 1000000; // Shoutout AngusCroll (https://goo.gl/pxwQGp)

        function toType(obj) {
            return {}.toString.call(obj).match(/\s([a-zA-Z]+)/)[1].toLowerCase();
        }

        function getSpecialTransitionEndEvent() {
            return {
                bindType: transition.end,
                delegateType: transition.end,
                handle: function handle(event) {
                    if ($$$1(event.target).is(this)) {
                        return event.handleObj.handler.apply(this, arguments); // eslint-disable-line prefer-rest-params
                    }

                    return undefined; // eslint-disable-line no-undefined
                }
            };
        }

        function transitionEndTest() {
            if (typeof window !== 'undefined' && window.QUnit) {
                return false;
            }

            return {
                end: 'transitionend'
            };
        }

        function transitionEndEmulator(duration) {
            var _this = this;

            var called = false;
            $$$1(this).one(Util.TRANSITION_END, function () {
                called = true;
            });
            setTimeout(function () {
                if (!called) {
                    Util.triggerTransitionEnd(_this);
                }
            }, duration);
            return this;
        }

        function setTransitionEndSupport() {
            transition = transitionEndTest();
            $$$1.fn.emulateTransitionEnd = transitionEndEmulator;

            if (Util.supportsTransitionEnd()) {
                $$$1.event.special[Util.TRANSITION_END] = getSpecialTransitionEndEvent();
            }
        }

        function escapeId(selector) {
            // We escape IDs in case of special selectors (selector = '#myId:something')
            // $.escapeSelector does not exist in jQuery < 3
            selector = typeof $$$1.escapeSelector === 'function' ? $$$1.escapeSelector(selector).substr(1) : selector.replace(/(:|\.|\[|\]|,|=|@)/g, '\\$1');
            return selector;
        }
        /**
         * --------------------------------------------------------------------------
         * Public Util Api
         * --------------------------------------------------------------------------
         */


        var Util = {
            TRANSITION_END: 'bsTransitionEnd',
            getUID: function getUID(prefix) {
                do {
                    // eslint-disable-next-line no-bitwise
                    prefix += ~~(Math.random() * MAX_UID); // "~~" acts like a faster Math.floor() here
                } while (document.getElementById(prefix));

                return prefix;
            },
            getSelectorFromElement: function getSelectorFromElement(element) {
                var selector = element.getAttribute('data-target');

                if (!selector || selector === '#') {
                    selector = element.getAttribute('href') || '';
                } // If it's an ID


                if (selector.charAt(0) === '#') {
                    selector = escapeId(selector);
                }

                try {
                    var $selector = $$$1(document).find(selector);
                    return $selector.length > 0 ? selector : null;
                } catch (err) {
                    return null;
                }
            },
            reflow: function reflow(element) {
                return element.offsetHeight;
            },
            triggerTransitionEnd: function triggerTransitionEnd(element) {
                $$$1(element).trigger(transition.end);
            },
            supportsTransitionEnd: function supportsTransitionEnd() {
                return Boolean(transition);
            },
            isElement: function isElement(obj) {
                return (obj[0] || obj).nodeType;
            },
            typeCheckConfig: function typeCheckConfig(componentName, config, configTypes) {
                for (var property in configTypes) {
                    if (Object.prototype.hasOwnProperty.call(configTypes, property)) {
                        var expectedTypes = configTypes[property];
                        var value = config[property];
                        var valueType = value && Util.isElement(value) ? 'element' : toType(value);

                        if (!new RegExp(expectedTypes).test(valueType)) {
                            throw new Error(componentName.toUpperCase() + ": " + ("Option \"" + property + "\" provided type \"" + valueType + "\" ") + ("but expected type \"" + expectedTypes + "\"."));
                        }
                    }
                }
            }
        };
        setTransitionEndSupport();
        return Util;
    }($);

    /**
     * --------------------------------------------------------------------------
     * Bootstrap (v4.0.0): alert.js
     * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
     * --------------------------------------------------------------------------
     */

    var Alert = function ($$$1) {
        /**
         * ------------------------------------------------------------------------
         * Constants
         * ------------------------------------------------------------------------
         */
        var NAME = 'alert';
        var VERSION = '4.0.0';
        var DATA_KEY = 'bs.alert';
        var EVENT_KEY = "." + DATA_KEY;
        var DATA_API_KEY = '.data-api';
        var JQUERY_NO_CONFLICT = $$$1.fn[NAME];
        var TRANSITION_DURATION = 150;
        var Selector = {
            DISMISS: '[data-dismiss="alert"]'
        };
        var Event = {
            CLOSE: "close" + EVENT_KEY,
            CLOSED: "closed" + EVENT_KEY,
            CLICK_DATA_API: "click" + EVENT_KEY + DATA_API_KEY
        };
        var ClassName = {
            ALERT: 'alert',
            FADE: 'fade',
            SHOW: 'show'
            /**
             * ------------------------------------------------------------------------
             * Class Definition
             * ------------------------------------------------------------------------
             */

        };

        var Alert =
            /*#__PURE__*/
            function () {
                function Alert(element) {
                    this._element = element;
                } // Getters


                var _proto = Alert.prototype;

                // Public
                _proto.close = function close(element) {
                    element = element || this._element;

                    var rootElement = this._getRootElement(element);

                    var customEvent = this._triggerCloseEvent(rootElement);

                    if (customEvent.isDefaultPrevented()) {
                        return;
                    }

                    this._removeElement(rootElement);
                };

                _proto.dispose = function dispose() {
                    $$$1.removeData(this._element, DATA_KEY);
                    this._element = null;
                }; // Private


                _proto._getRootElement = function _getRootElement(element) {
                    var selector = Util.getSelectorFromElement(element);
                    var parent = false;

                    if (selector) {
                        parent = $$$1(selector)[0];
                    }

                    if (!parent) {
                        parent = $$$1(element).closest("." + ClassName.ALERT)[0];
                    }

                    return parent;
                };

                _proto._triggerCloseEvent = function _triggerCloseEvent(element) {
                    var closeEvent = $$$1.Event(Event.CLOSE);
                    $$$1(element).trigger(closeEvent);
                    return closeEvent;
                };

                _proto._removeElement = function _removeElement(element) {
                    var _this = this;

                    $$$1(element).removeClass(ClassName.SHOW);

                    if (!Util.supportsTransitionEnd() || !$$$1(element).hasClass(ClassName.FADE)) {
                        this._destroyElement(element);

                        return;
                    }

                    $$$1(element).one(Util.TRANSITION_END, function (event) {
                        return _this._destroyElement(element, event);
                    }).emulateTransitionEnd(TRANSITION_DURATION);
                };

                _proto._destroyElement = function _destroyElement(element) {
                    $$$1(element).detach().trigger(Event.CLOSED).remove();
                }; // Static


                Alert._jQueryInterface = function _jQueryInterface(config) {
                    return this.each(function () {
                        var $element = $$$1(this);
                        var data = $element.data(DATA_KEY);

                        if (!data) {
                            data = new Alert(this);
                            $element.data(DATA_KEY, data);
                        }

                        if (config === 'close') {
                            data[config](this);
                        }
                    });
                };

                Alert._handleDismiss = function _handleDismiss(alertInstance) {
                    return function (event) {
                        if (event) {
                            event.preventDefault();
                        }

                        alertInstance.close(this);
                    };
                };

                _createClass(Alert, null, [{
                    key: "VERSION",
                    get: function get() {
                        return VERSION;
                    }
                }]);
                return Alert;
            }();
        /**
         * ------------------------------------------------------------------------
         * Data Api implementation
         * ------------------------------------------------------------------------
         */


        $$$1(document).on(Event.CLICK_DATA_API, Selector.DISMISS, Alert._handleDismiss(new Alert()));
        /**
         * ------------------------------------------------------------------------
         * jQuery
         * ------------------------------------------------------------------------
         */

        $$$1.fn[NAME] = Alert._jQueryInterface;
        $$$1.fn[NAME].Constructor = Alert;

        $$$1.fn[NAME].noConflict = function () {
            $$$1.fn[NAME] = JQUERY_NO_CONFLICT;
            return Alert._jQueryInterface;
        };

        return Alert;
    }($);

    /**
     * --------------------------------------------------------------------------
     * Bootstrap (v4.0.0): button.js
     * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
     * --------------------------------------------------------------------------
     */

    var Button = function ($$$1) {
        /**
         * ------------------------------------------------------------------------
         * Constants
         * ------------------------------------------------------------------------
         */
        var NAME = 'button';
        var VERSION = '4.0.0';
        var DATA_KEY = 'bs.button';
        var EVENT_KEY = "." + DATA_KEY;
        var DATA_API_KEY = '.data-api';
        var JQUERY_NO_CONFLICT = $$$1.fn[NAME];
        var ClassName = {
            ACTIVE: 'active',
            BUTTON: 'btn',
            FOCUS: 'focus'
        };
        var Selector = {
            DATA_TOGGLE_CARROT: '[data-toggle^="button"]',
            DATA_TOGGLE: '[data-toggle="buttons"]',
            INPUT: 'input',
            ACTIVE: '.active',
            BUTTON: '.btn'
        };
        var Event = {
            CLICK_DATA_API: "click" + EVENT_KEY + DATA_API_KEY,
            FOCUS_BLUR_DATA_API: "focus" + EVENT_KEY + DATA_API_KEY + " " + ("blur" + EVENT_KEY + DATA_API_KEY)
            /**
             * ------------------------------------------------------------------------
             * Class Definition
             * ------------------------------------------------------------------------
             */

        };

        var Button =
            /*#__PURE__*/
            function () {
                function Button(element) {
                    this._element = element;
                } // Getters


                var _proto = Button.prototype;

                // Public
                _proto.toggle = function toggle() {
                    var triggerChangeEvent = true;
                    var addAriaPressed = true;
                    var rootElement = $$$1(this._element).closest(Selector.DATA_TOGGLE)[0];

                    if (rootElement) {
                        var input = $$$1(this._element).find(Selector.INPUT)[0];

                        if (input) {
                            if (input.type === 'radio') {
                                if (input.checked && $$$1(this._element).hasClass(ClassName.ACTIVE)) {
                                    triggerChangeEvent = false;
                                } else {
                                    var activeElement = $$$1(rootElement).find(Selector.ACTIVE)[0];

                                    if (activeElement) {
                                        $$$1(activeElement).removeClass(ClassName.ACTIVE);
                                    }
                                }
                            }

                            if (triggerChangeEvent) {
                                if (input.hasAttribute('disabled') || rootElement.hasAttribute('disabled') || input.classList.contains('disabled') || rootElement.classList.contains('disabled')) {
                                    return;
                                }

                                input.checked = !$$$1(this._element).hasClass(ClassName.ACTIVE);
                                $$$1(input).trigger('change');
                            }

                            input.focus();
                            addAriaPressed = false;
                        }
                    }

                    if (addAriaPressed) {
                        this._element.setAttribute('aria-pressed', !$$$1(this._element).hasClass(ClassName.ACTIVE));
                    }

                    if (triggerChangeEvent) {
                        $$$1(this._element).toggleClass(ClassName.ACTIVE);
                    }
                };

                _proto.dispose = function dispose() {
                    $$$1.removeData(this._element, DATA_KEY);
                    this._element = null;
                }; // Static


                Button._jQueryInterface = function _jQueryInterface(config) {
                    return this.each(function () {
                        var data = $$$1(this).data(DATA_KEY);

                        if (!data) {
                            data = new Button(this);
                            $$$1(this).data(DATA_KEY, data);
                        }

                        if (config === 'toggle') {
                            data[config]();
                        }
                    });
                };

                _createClass(Button, null, [{
                    key: "VERSION",
                    get: function get() {
                        return VERSION;
                    }
                }]);
                return Button;
            }();
        /**
         * ------------------------------------------------------------------------
         * Data Api implementation
         * ------------------------------------------------------------------------
         */


        $$$1(document).on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE_CARROT, function (event) {
            event.preventDefault();
            var button = event.target;

            if (!$$$1(button).hasClass(ClassName.BUTTON)) {
                button = $$$1(button).closest(Selector.BUTTON);
            }

            Button._jQueryInterface.call($$$1(button), 'toggle');
        }).on(Event.FOCUS_BLUR_DATA_API, Selector.DATA_TOGGLE_CARROT, function (event) {
            var button = $$$1(event.target).closest(Selector.BUTTON)[0];
            $$$1(button).toggleClass(ClassName.FOCUS, /^focus(in)?$/.test(event.type));
        });
        /**
         * ------------------------------------------------------------------------
         * jQuery
         * ------------------------------------------------------------------------
         */

        $$$1.fn[NAME] = Button._jQueryInterface;
        $$$1.fn[NAME].Constructor = Button;

        $$$1.fn[NAME].noConflict = function () {
            $$$1.fn[NAME] = JQUERY_NO_CONFLICT;
            return Button._jQueryInterface;
        };

        return Button;
    }($);

    /**
     * --------------------------------------------------------------------------
     * Bootstrap (v4.0.0): carousel.js
     * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
     * --------------------------------------------------------------------------
     */

    var Carousel = function ($$$1) {
        /**
         * ------------------------------------------------------------------------
         * Constants
         * ------------------------------------------------------------------------
         */
        var NAME = 'carousel';
        var VERSION = '4.0.0';
        var DATA_KEY = 'bs.carousel';
        var EVENT_KEY = "." + DATA_KEY;
        var DATA_API_KEY = '.data-api';
        var JQUERY_NO_CONFLICT = $$$1.fn[NAME];
        var TRANSITION_DURATION = 600;
        var ARROW_LEFT_KEYCODE = 37; // KeyboardEvent.which value for left arrow key

        var ARROW_RIGHT_KEYCODE = 39; // KeyboardEvent.which value for right arrow key

        var TOUCHEVENT_COMPAT_WAIT = 500; // Time for mouse compat events to fire after touch

        var Default = {
            interval: 5000,
            keyboard: true,
            slide: false,
            pause: 'hover',
            wrap: true
        };
        var DefaultType = {
            interval: '(number|boolean)',
            keyboard: 'boolean',
            slide: '(boolean|string)',
            pause: '(string|boolean)',
            wrap: 'boolean'
        };
        var Direction = {
            NEXT: 'next',
            PREV: 'prev',
            LEFT: 'left',
            RIGHT: 'right'
        };
        var Event = {
            SLIDE: "slide" + EVENT_KEY,
            SLID: "slid" + EVENT_KEY,
            KEYDOWN: "keydown" + EVENT_KEY,
            MOUSEENTER: "mouseenter" + EVENT_KEY,
            MOUSELEAVE: "mouseleave" + EVENT_KEY,
            TOUCHEND: "touchend" + EVENT_KEY,
            LOAD_DATA_API: "load" + EVENT_KEY + DATA_API_KEY,
            CLICK_DATA_API: "click" + EVENT_KEY + DATA_API_KEY
        };
        var ClassName = {
            CAROUSEL: 'carousel',
            ACTIVE: 'active',
            SLIDE: 'slide',
            RIGHT: 'carousel-item-right',
            LEFT: 'carousel-item-left',
            NEXT: 'carousel-item-next',
            PREV: 'carousel-item-prev',
            ITEM: 'carousel-item'
        };
        var Selector = {
            ACTIVE: '.active',
            ACTIVE_ITEM: '.active.carousel-item',
            ITEM: '.carousel-item',
            NEXT_PREV: '.carousel-item-next, .carousel-item-prev',
            INDICATORS: '.carousel-indicators',
            DATA_SLIDE: '[data-slide], [data-slide-to]',
            DATA_RIDE: '[data-ride="carousel"]'
            /**
             * ------------------------------------------------------------------------
             * Class Definition
             * ------------------------------------------------------------------------
             */

        };

        var Carousel =
            /*#__PURE__*/
            function () {
                function Carousel(element, config) {
                    this._items = null;
                    this._interval = null;
                    this._activeElement = null;
                    this._isPaused = false;
                    this._isSliding = false;
                    this.touchTimeout = null;
                    this._config = this._getConfig(config);
                    this._element = $$$1(element)[0];
                    this._indicatorsElement = $$$1(this._element).find(Selector.INDICATORS)[0];

                    this._addEventListeners();
                } // Getters


                var _proto = Carousel.prototype;

                // Public
                _proto.next = function next() {
                    if (!this._isSliding) {
                        this._slide(Direction.NEXT);
                    }
                };

                _proto.nextWhenVisible = function nextWhenVisible() {
                    // Don't call next when the page isn't visible
                    // or the carousel or its parent isn't visible
                    if (!document.hidden && $$$1(this._element).is(':visible') && $$$1(this._element).css('visibility') !== 'hidden') {
                        this.next();
                    }
                };

                _proto.prev = function prev() {
                    if (!this._isSliding) {
                        this._slide(Direction.PREV);
                    }
                };

                _proto.pause = function pause(event) {
                    if (!event) {
                        this._isPaused = true;
                    }

                    if ($$$1(this._element).find(Selector.NEXT_PREV)[0] && Util.supportsTransitionEnd()) {
                        Util.triggerTransitionEnd(this._element);
                        this.cycle(true);
                    }

                    clearInterval(this._interval);
                    this._interval = null;
                };

                _proto.cycle = function cycle(event) {
                    if (!event) {
                        this._isPaused = false;
                    }

                    if (this._interval) {
                        clearInterval(this._interval);
                        this._interval = null;
                    }

                    if (this._config.interval && !this._isPaused) {
                        this._interval = setInterval((document.visibilityState ? this.nextWhenVisible : this.next).bind(this), this._config.interval);
                    }
                };

                _proto.to = function to(index) {
                    var _this = this;

                    this._activeElement = $$$1(this._element).find(Selector.ACTIVE_ITEM)[0];

                    var activeIndex = this._getItemIndex(this._activeElement);

                    if (index > this._items.length - 1 || index < 0) {
                        return;
                    }

                    if (this._isSliding) {
                        $$$1(this._element).one(Event.SLID, function () {
                            return _this.to(index);
                        });
                        return;
                    }

                    if (activeIndex === index) {
                        this.pause();
                        this.cycle();
                        return;
                    }

                    var direction = index > activeIndex ? Direction.NEXT : Direction.PREV;

                    this._slide(direction, this._items[index]);
                };

                _proto.dispose = function dispose() {
                    $$$1(this._element).off(EVENT_KEY);
                    $$$1.removeData(this._element, DATA_KEY);
                    this._items = null;
                    this._config = null;
                    this._element = null;
                    this._interval = null;
                    this._isPaused = null;
                    this._isSliding = null;
                    this._activeElement = null;
                    this._indicatorsElement = null;
                }; // Private


                _proto._getConfig = function _getConfig(config) {
                    config = _extends({}, Default, config);
                    Util.typeCheckConfig(NAME, config, DefaultType);
                    return config;
                };

                _proto._addEventListeners = function _addEventListeners() {
                    var _this2 = this;

                    if (this._config.keyboard) {
                        $$$1(this._element).on(Event.KEYDOWN, function (event) {
                            return _this2._keydown(event);
                        });
                    }

                    if (this._config.pause === 'hover') {
                        $$$1(this._element).on(Event.MOUSEENTER, function (event) {
                            return _this2.pause(event);
                        }).on(Event.MOUSELEAVE, function (event) {
                            return _this2.cycle(event);
                        });

                        if ('ontouchstart' in document.documentElement) {
                            // If it's a touch-enabled device, mouseenter/leave are fired as
                            // part of the mouse compatibility events on first tap - the carousel
                            // would stop cycling until user tapped out of it;
                            // here, we listen for touchend, explicitly pause the carousel
                            // (as if it's the second time we tap on it, mouseenter compat event
                            // is NOT fired) and after a timeout (to allow for mouse compatibility
                            // events to fire) we explicitly restart cycling
                            $$$1(this._element).on(Event.TOUCHEND, function () {
                                _this2.pause();

                                if (_this2.touchTimeout) {
                                    clearTimeout(_this2.touchTimeout);
                                }

                                _this2.touchTimeout = setTimeout(function (event) {
                                    return _this2.cycle(event);
                                }, TOUCHEVENT_COMPAT_WAIT + _this2._config.interval);
                            });
                        }
                    }
                };

                _proto._keydown = function _keydown(event) {
                    if (/input|textarea/i.test(event.target.tagName)) {
                        return;
                    }

                    switch (event.which) {
                        case ARROW_LEFT_KEYCODE:
                            event.preventDefault();
                            this.prev();
                            break;

                        case ARROW_RIGHT_KEYCODE:
                            event.preventDefault();
                            this.next();
                            break;

                        default:
                    }
                };

                _proto._getItemIndex = function _getItemIndex(element) {
                    this._items = $$$1.makeArray($$$1(element).parent().find(Selector.ITEM));
                    return this._items.indexOf(element);
                };

                _proto._getItemByDirection = function _getItemByDirection(direction, activeElement) {
                    var isNextDirection = direction === Direction.NEXT;
                    var isPrevDirection = direction === Direction.PREV;

                    var activeIndex = this._getItemIndex(activeElement);

                    var lastItemIndex = this._items.length - 1;
                    var isGoingToWrap = isPrevDirection && activeIndex === 0 || isNextDirection && activeIndex === lastItemIndex;

                    if (isGoingToWrap && !this._config.wrap) {
                        return activeElement;
                    }

                    var delta = direction === Direction.PREV ? -1 : 1;
                    var itemIndex = (activeIndex + delta) % this._items.length;
                    return itemIndex === -1 ? this._items[this._items.length - 1] : this._items[itemIndex];
                };

                _proto._triggerSlideEvent = function _triggerSlideEvent(relatedTarget, eventDirectionName) {
                    var targetIndex = this._getItemIndex(relatedTarget);

                    var fromIndex = this._getItemIndex($$$1(this._element).find(Selector.ACTIVE_ITEM)[0]);

                    var slideEvent = $$$1.Event(Event.SLIDE, {
                        relatedTarget: relatedTarget,
                        direction: eventDirectionName,
                        from: fromIndex,
                        to: targetIndex
                    });
                    $$$1(this._element).trigger(slideEvent);
                    return slideEvent;
                };

                _proto._setActiveIndicatorElement = function _setActiveIndicatorElement(element) {
                    if (this._indicatorsElement) {
                        $$$1(this._indicatorsElement).find(Selector.ACTIVE).removeClass(ClassName.ACTIVE);

                        var nextIndicator = this._indicatorsElement.children[this._getItemIndex(element)];

                        if (nextIndicator) {
                            $$$1(nextIndicator).addClass(ClassName.ACTIVE);
                        }
                    }
                };

                _proto._slide = function _slide(direction, element) {
                    var _this3 = this;

                    var activeElement = $$$1(this._element).find(Selector.ACTIVE_ITEM)[0];

                    var activeElementIndex = this._getItemIndex(activeElement);

                    var nextElement = element || activeElement && this._getItemByDirection(direction, activeElement);

                    var nextElementIndex = this._getItemIndex(nextElement);

                    var isCycling = Boolean(this._interval);
                    var directionalClassName;
                    var orderClassName;
                    var eventDirectionName;

                    if (direction === Direction.NEXT) {
                        directionalClassName = ClassName.LEFT;
                        orderClassName = ClassName.NEXT;
                        eventDirectionName = Direction.LEFT;
                    } else {
                        directionalClassName = ClassName.RIGHT;
                        orderClassName = ClassName.PREV;
                        eventDirectionName = Direction.RIGHT;
                    }

                    if (nextElement && $$$1(nextElement).hasClass(ClassName.ACTIVE)) {
                        this._isSliding = false;
                        return;
                    }

                    var slideEvent = this._triggerSlideEvent(nextElement, eventDirectionName);

                    if (slideEvent.isDefaultPrevented()) {
                        return;
                    }

                    if (!activeElement || !nextElement) {
                        // Some weirdness is happening, so we bail
                        return;
                    }

                    this._isSliding = true;

                    if (isCycling) {
                        this.pause();
                    }

                    this._setActiveIndicatorElement(nextElement);

                    var slidEvent = $$$1.Event(Event.SLID, {
                        relatedTarget: nextElement,
                        direction: eventDirectionName,
                        from: activeElementIndex,
                        to: nextElementIndex
                    });

                    if (Util.supportsTransitionEnd() && $$$1(this._element).hasClass(ClassName.SLIDE)) {
                        $$$1(nextElement).addClass(orderClassName);
                        Util.reflow(nextElement);
                        $$$1(activeElement).addClass(directionalClassName);
                        $$$1(nextElement).addClass(directionalClassName);
                        $$$1(activeElement).one(Util.TRANSITION_END, function () {
                            $$$1(nextElement).removeClass(directionalClassName + " " + orderClassName).addClass(ClassName.ACTIVE);
                            $$$1(activeElement).removeClass(ClassName.ACTIVE + " " + orderClassName + " " + directionalClassName);
                            _this3._isSliding = false;
                            setTimeout(function () {
                                return $$$1(_this3._element).trigger(slidEvent);
                            }, 0);
                        }).emulateTransitionEnd(TRANSITION_DURATION);
                    } else {
                        $$$1(activeElement).removeClass(ClassName.ACTIVE);
                        $$$1(nextElement).addClass(ClassName.ACTIVE);
                        this._isSliding = false;
                        $$$1(this._element).trigger(slidEvent);
                    }

                    if (isCycling) {
                        this.cycle();
                    }
                }; // Static


                Carousel._jQueryInterface = function _jQueryInterface(config) {
                    return this.each(function () {
                        var data = $$$1(this).data(DATA_KEY);

                        var _config = _extends({}, Default, $$$1(this).data());

                        if (typeof config === 'object') {
                            _config = _extends({}, _config, config);
                        }

                        var action = typeof config === 'string' ? config : _config.slide;

                        if (!data) {
                            data = new Carousel(this, _config);
                            $$$1(this).data(DATA_KEY, data);
                        }

                        if (typeof config === 'number') {
                            data.to(config);
                        } else if (typeof action === 'string') {
                            if (typeof data[action] === 'undefined') {
                                throw new TypeError("No method named \"" + action + "\"");
                            }

                            data[action]();
                        } else if (_config.interval) {
                            data.pause();
                            data.cycle();
                        }
                    });
                };

                Carousel._dataApiClickHandler = function _dataApiClickHandler(event) {
                    var selector = Util.getSelectorFromElement(this);

                    if (!selector) {
                        return;
                    }

                    var target = $$$1(selector)[0];

                    if (!target || !$$$1(target).hasClass(ClassName.CAROUSEL)) {
                        return;
                    }

                    var config = _extends({}, $$$1(target).data(), $$$1(this).data());
                    var slideIndex = this.getAttribute('data-slide-to');

                    if (slideIndex) {
                        config.interval = false;
                    }

                    Carousel._jQueryInterface.call($$$1(target), config);

                    if (slideIndex) {
                        $$$1(target).data(DATA_KEY).to(slideIndex);
                    }

                    event.preventDefault();
                };

                _createClass(Carousel, null, [{
                    key: "VERSION",
                    get: function get() {
                        return VERSION;
                    }
                }, {
                    key: "Default",
                    get: function get() {
                        return Default;
                    }
                }]);
                return Carousel;
            }();
        /**
         * ------------------------------------------------------------------------
         * Data Api implementation
         * ------------------------------------------------------------------------
         */


        $$$1(document).on(Event.CLICK_DATA_API, Selector.DATA_SLIDE, Carousel._dataApiClickHandler);
        $$$1(window).on(Event.LOAD_DATA_API, function () {
            $$$1(Selector.DATA_RIDE).each(function () {
                var $carousel = $$$1(this);

                Carousel._jQueryInterface.call($carousel, $carousel.data());
            });
        });
        /**
         * ------------------------------------------------------------------------
         * jQuery
         * ------------------------------------------------------------------------
         */

        $$$1.fn[NAME] = Carousel._jQueryInterface;
        $$$1.fn[NAME].Constructor = Carousel;

        $$$1.fn[NAME].noConflict = function () {
            $$$1.fn[NAME] = JQUERY_NO_CONFLICT;
            return Carousel._jQueryInterface;
        };

        return Carousel;
    }($);

    /**
     * --------------------------------------------------------------------------
     * Bootstrap (v4.0.0): collapse.js
     * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
     * --------------------------------------------------------------------------
     */

    var Collapse = function ($$$1) {
        /**
         * ------------------------------------------------------------------------
         * Constants
         * ------------------------------------------------------------------------
         */
        var NAME = 'collapse';
        var VERSION = '4.0.0';
        var DATA_KEY = 'bs.collapse';
        var EVENT_KEY = "." + DATA_KEY;
        var DATA_API_KEY = '.data-api';
        var JQUERY_NO_CONFLICT = $$$1.fn[NAME];
        var TRANSITION_DURATION = 600;
        var Default = {
            toggle: true,
            parent: ''
        };
        var DefaultType = {
            toggle: 'boolean',
            parent: '(string|element)'
        };
        var Event = {
            SHOW: "show" + EVENT_KEY,
            SHOWN: "shown" + EVENT_KEY,
            HIDE: "hide" + EVENT_KEY,
            HIDDEN: "hidden" + EVENT_KEY,
            CLICK_DATA_API: "click" + EVENT_KEY + DATA_API_KEY
        };
        var ClassName = {
            SHOW: 'show',
            COLLAPSE: 'collapse',
            COLLAPSING: 'collapsing',
            COLLAPSED: 'collapsed'
        };
        var Dimension = {
            WIDTH: 'width',
            HEIGHT: 'height'
        };
        var Selector = {
            ACTIVES: '.show, .collapsing',
            DATA_TOGGLE: '[data-toggle="collapse"]'
            /**
             * ------------------------------------------------------------------------
             * Class Definition
             * ------------------------------------------------------------------------
             */

        };

        var Collapse =
            /*#__PURE__*/
            function () {
                function Collapse(element, config) {
                    this._isTransitioning = false;
                    this._element = element;
                    this._config = this._getConfig(config);
                    this._triggerArray = $$$1.makeArray($$$1("[data-toggle=\"collapse\"][href=\"#" + element.id + "\"]," + ("[data-toggle=\"collapse\"][data-target=\"#" + element.id + "\"]")));
                    var tabToggles = $$$1(Selector.DATA_TOGGLE);

                    for (var i = 0; i < tabToggles.length; i++) {
                        var elem = tabToggles[i];
                        var selector = Util.getSelectorFromElement(elem);

                        if (selector !== null && $$$1(selector).filter(element).length > 0) {
                            this._selector = selector;

                            this._triggerArray.push(elem);
                        }
                    }

                    this._parent = this._config.parent ? this._getParent() : null;

                    if (!this._config.parent) {
                        this._addAriaAndCollapsedClass(this._element, this._triggerArray);
                    }

                    if (this._config.toggle) {
                        this.toggle();
                    }
                } // Getters


                var _proto = Collapse.prototype;

                // Public
                _proto.toggle = function toggle() {
                    if ($$$1(this._element).hasClass(ClassName.SHOW)) {
                        this.hide();
                    } else {
                        this.show();
                    }
                };

                _proto.show = function show() {
                    var _this = this;

                    if (this._isTransitioning || $$$1(this._element).hasClass(ClassName.SHOW)) {
                        return;
                    }

                    var actives;
                    var activesData;

                    if (this._parent) {
                        actives = $$$1.makeArray($$$1(this._parent).find(Selector.ACTIVES).filter("[data-parent=\"" + this._config.parent + "\"]"));

                        if (actives.length === 0) {
                            actives = null;
                        }
                    }

                    if (actives) {
                        activesData = $$$1(actives).not(this._selector).data(DATA_KEY);

                        if (activesData && activesData._isTransitioning) {
                            return;
                        }
                    }

                    var startEvent = $$$1.Event(Event.SHOW);
                    $$$1(this._element).trigger(startEvent);

                    if (startEvent.isDefaultPrevented()) {
                        return;
                    }

                    if (actives) {
                        Collapse._jQueryInterface.call($$$1(actives).not(this._selector), 'hide');

                        if (!activesData) {
                            $$$1(actives).data(DATA_KEY, null);
                        }
                    }

                    var dimension = this._getDimension();

                    $$$1(this._element).removeClass(ClassName.COLLAPSE).addClass(ClassName.COLLAPSING);
                    this._element.style[dimension] = 0;

                    if (this._triggerArray.length > 0) {
                        $$$1(this._triggerArray).removeClass(ClassName.COLLAPSED).attr('aria-expanded', true);
                    }

                    this.setTransitioning(true);

                    var complete = function complete() {
                        $$$1(_this._element).removeClass(ClassName.COLLAPSING).addClass(ClassName.COLLAPSE).addClass(ClassName.SHOW);
                        _this._element.style[dimension] = '';

                        _this.setTransitioning(false);

                        $$$1(_this._element).trigger(Event.SHOWN);
                    };

                    if (!Util.supportsTransitionEnd()) {
                        complete();
                        return;
                    }

                    var capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1);
                    var scrollSize = "scroll" + capitalizedDimension;
                    $$$1(this._element).one(Util.TRANSITION_END, complete).emulateTransitionEnd(TRANSITION_DURATION);
                    this._element.style[dimension] = this._element[scrollSize] + "px";
                };

                _proto.hide = function hide() {
                    var _this2 = this;

                    if (this._isTransitioning || !$$$1(this._element).hasClass(ClassName.SHOW)) {
                        return;
                    }

                    var startEvent = $$$1.Event(Event.HIDE);
                    $$$1(this._element).trigger(startEvent);

                    if (startEvent.isDefaultPrevented()) {
                        return;
                    }

                    var dimension = this._getDimension();

                    this._element.style[dimension] = this._element.getBoundingClientRect()[dimension] + "px";
                    Util.reflow(this._element);
                    $$$1(this._element).addClass(ClassName.COLLAPSING).removeClass(ClassName.COLLAPSE).removeClass(ClassName.SHOW);

                    if (this._triggerArray.length > 0) {
                        for (var i = 0; i < this._triggerArray.length; i++) {
                            var trigger = this._triggerArray[i];
                            var selector = Util.getSelectorFromElement(trigger);

                            if (selector !== null) {
                                var $elem = $$$1(selector);

                                if (!$elem.hasClass(ClassName.SHOW)) {
                                    $$$1(trigger).addClass(ClassName.COLLAPSED).attr('aria-expanded', false);
                                }
                            }
                        }
                    }

                    this.setTransitioning(true);

                    var complete = function complete() {
                        _this2.setTransitioning(false);

                        $$$1(_this2._element).removeClass(ClassName.COLLAPSING).addClass(ClassName.COLLAPSE).trigger(Event.HIDDEN);
                    };

                    this._element.style[dimension] = '';

                    if (!Util.supportsTransitionEnd()) {
                        complete();
                        return;
                    }

                    $$$1(this._element).one(Util.TRANSITION_END, complete).emulateTransitionEnd(TRANSITION_DURATION);
                };

                _proto.setTransitioning = function setTransitioning(isTransitioning) {
                    this._isTransitioning = isTransitioning;
                };

                _proto.dispose = function dispose() {
                    $$$1.removeData(this._element, DATA_KEY);
                    this._config = null;
                    this._parent = null;
                    this._element = null;
                    this._triggerArray = null;
                    this._isTransitioning = null;
                }; // Private


                _proto._getConfig = function _getConfig(config) {
                    config = _extends({}, Default, config);
                    config.toggle = Boolean(config.toggle); // Coerce string values

                    Util.typeCheckConfig(NAME, config, DefaultType);
                    return config;
                };

                _proto._getDimension = function _getDimension() {
                    var hasWidth = $$$1(this._element).hasClass(Dimension.WIDTH);
                    return hasWidth ? Dimension.WIDTH : Dimension.HEIGHT;
                };

                _proto._getParent = function _getParent() {
                    var _this3 = this;

                    var parent = null;

                    if (Util.isElement(this._config.parent)) {
                        parent = this._config.parent; // It's a jQuery object

                        if (typeof this._config.parent.jquery !== 'undefined') {
                            parent = this._config.parent[0];
                        }
                    } else {
                        parent = $$$1(this._config.parent)[0];
                    }

                    var selector = "[data-toggle=\"collapse\"][data-parent=\"" + this._config.parent + "\"]";
                    $$$1(parent).find(selector).each(function (i, element) {
                        _this3._addAriaAndCollapsedClass(Collapse._getTargetFromElement(element), [element]);
                    });
                    return parent;
                };

                _proto._addAriaAndCollapsedClass = function _addAriaAndCollapsedClass(element, triggerArray) {
                    if (element) {
                        var isOpen = $$$1(element).hasClass(ClassName.SHOW);

                        if (triggerArray.length > 0) {
                            $$$1(triggerArray).toggleClass(ClassName.COLLAPSED, !isOpen).attr('aria-expanded', isOpen);
                        }
                    }
                }; // Static


                Collapse._getTargetFromElement = function _getTargetFromElement(element) {
                    var selector = Util.getSelectorFromElement(element);
                    return selector ? $$$1(selector)[0] : null;
                };

                Collapse._jQueryInterface = function _jQueryInterface(config) {
                    return this.each(function () {
                        var $this = $$$1(this);
                        var data = $this.data(DATA_KEY);

                        var _config = _extends({}, Default, $this.data(), typeof config === 'object' && config);

                        if (!data && _config.toggle && /show|hide/.test(config)) {
                            _config.toggle = false;
                        }

                        if (!data) {
                            data = new Collapse(this, _config);
                            $this.data(DATA_KEY, data);
                        }

                        if (typeof config === 'string') {
                            if (typeof data[config] === 'undefined') {
                                throw new TypeError("No method named \"" + config + "\"");
                            }

                            data[config]();
                        }
                    });
                };

                _createClass(Collapse, null, [{
                    key: "VERSION",
                    get: function get() {
                        return VERSION;
                    }
                }, {
                    key: "Default",
                    get: function get() {
                        return Default;
                    }
                }]);
                return Collapse;
            }();
        /**
         * ------------------------------------------------------------------------
         * Data Api implementation
         * ------------------------------------------------------------------------
         */


        $$$1(document).on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (event) {
            // preventDefault only for <a> elements (which change the URL) not inside the collapsible element
            if (event.currentTarget.tagName === 'A') {
                event.preventDefault();
            }

            var $trigger = $$$1(this);
            var selector = Util.getSelectorFromElement(this);
            $$$1(selector).each(function () {
                var $target = $$$1(this);
                var data = $target.data(DATA_KEY);
                var config = data ? 'toggle' : $trigger.data();

                Collapse._jQueryInterface.call($target, config);
            });
        });
        /**
         * ------------------------------------------------------------------------
         * jQuery
         * ------------------------------------------------------------------------
         */

        $$$1.fn[NAME] = Collapse._jQueryInterface;
        $$$1.fn[NAME].Constructor = Collapse;

        $$$1.fn[NAME].noConflict = function () {
            $$$1.fn[NAME] = JQUERY_NO_CONFLICT;
            return Collapse._jQueryInterface;
        };

        return Collapse;
    }($);

    /**
     * --------------------------------------------------------------------------
     * Bootstrap (v4.0.0): dropdown.js
     * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
     * --------------------------------------------------------------------------
     */

    var Dropdown = function ($$$1) {
        /**
         * ------------------------------------------------------------------------
         * Constants
         * ------------------------------------------------------------------------
         */
        var NAME = 'dropdown';
        var VERSION = '4.0.0';
        var DATA_KEY = 'bs.dropdown';
        var EVENT_KEY = "." + DATA_KEY;
        var DATA_API_KEY = '.data-api';
        var JQUERY_NO_CONFLICT = $$$1.fn[NAME];
        var ESCAPE_KEYCODE = 27; // KeyboardEvent.which value for Escape (Esc) key

        var SPACE_KEYCODE = 32; // KeyboardEvent.which value for space key

        var TAB_KEYCODE = 9; // KeyboardEvent.which value for tab key

        var ARROW_UP_KEYCODE = 38; // KeyboardEvent.which value for up arrow key

        var ARROW_DOWN_KEYCODE = 40; // KeyboardEvent.which value for down arrow key

        var RIGHT_MOUSE_BUTTON_WHICH = 3; // MouseEvent.which value for the right button (assuming a right-handed mouse)

        var REGEXP_KEYDOWN = new RegExp(ARROW_UP_KEYCODE + "|" + ARROW_DOWN_KEYCODE + "|" + ESCAPE_KEYCODE);
        var Event = {
            HIDE: "hide" + EVENT_KEY,
            HIDDEN: "hidden" + EVENT_KEY,
            SHOW: "show" + EVENT_KEY,
            SHOWN: "shown" + EVENT_KEY,
            CLICK: "click" + EVENT_KEY,
            CLICK_DATA_API: "click" + EVENT_KEY + DATA_API_KEY,
            KEYDOWN_DATA_API: "keydown" + EVENT_KEY + DATA_API_KEY,
            KEYUP_DATA_API: "keyup" + EVENT_KEY + DATA_API_KEY
        };
        var ClassName = {
            DISABLED: 'disabled',
            SHOW: 'show',
            DROPUP: 'dropup',
            DROPRIGHT: 'dropright',
            DROPLEFT: 'dropleft',
            MENURIGHT: 'dropdown-menu-right',
            MENULEFT: 'dropdown-menu-left',
            POSITION_STATIC: 'position-static'
        };
        var Selector = {
            DATA_TOGGLE: '[data-toggle="dropdown"]',
            FORM_CHILD: '.dropdown form',
            MENU: '.dropdown-menu',
            NAVBAR_NAV: '.navbar-nav',
            VISIBLE_ITEMS: '.dropdown-menu .dropdown-item:not(.disabled)'
        };
        var AttachmentMap = {
            TOP: 'top-start',
            TOPEND: 'top-end',
            BOTTOM: 'bottom-start',
            BOTTOMEND: 'bottom-end',
            RIGHT: 'right-start',
            RIGHTEND: 'right-end',
            LEFT: 'left-start',
            LEFTEND: 'left-end'
        };
        var Default = {
            offset: 0,
            flip: true,
            boundary: 'scrollParent'
        };
        var DefaultType = {
            offset: '(number|string|function)',
            flip: 'boolean',
            boundary: '(string|element)'
            /**
             * ------------------------------------------------------------------------
             * Class Definition
             * ------------------------------------------------------------------------
             */

        };

        var Dropdown =
            /*#__PURE__*/
            function () {
                function Dropdown(element, config) {
                    this._element = element;
                    this._popper = null;
                    this._config = this._getConfig(config);
                    this._menu = this._getMenuElement();
                    this._inNavbar = this._detectNavbar();

                    this._addEventListeners();
                } // Getters


                var _proto = Dropdown.prototype;

                // Public
                _proto.toggle = function toggle() {
                    if (this._element.disabled || $$$1(this._element).hasClass(ClassName.DISABLED)) {
                        return;
                    }

                    var parent = Dropdown._getParentFromElement(this._element);

                    var isActive = $$$1(this._menu).hasClass(ClassName.SHOW);

                    Dropdown._clearMenus();

                    if (isActive) {
                        return;
                    }

                    var relatedTarget = {
                        relatedTarget: this._element
                    };
                    var showEvent = $$$1.Event(Event.SHOW, relatedTarget);
                    $$$1(parent).trigger(showEvent);

                    if (showEvent.isDefaultPrevented()) {
                        return;
                    } // Disable totally Popper.js for Dropdown in Navbar


                    if (!this._inNavbar) {
                        /**
                         * Check for Popper dependency
                         * Popper - https://popper.js.org
                         */
                        if (typeof Popper === 'undefined') {
                            throw new TypeError('Bootstrap dropdown require Popper.js (https://popper.js.org)');
                        }

                        var element = this._element; // For dropup with alignment we use the parent as popper container

                        if ($$$1(parent).hasClass(ClassName.DROPUP)) {
                            if ($$$1(this._menu).hasClass(ClassName.MENULEFT) || $$$1(this._menu).hasClass(ClassName.MENURIGHT)) {
                                element = parent;
                            }
                        } // If boundary is not `scrollParent`, then set position to `static`
                        // to allow the menu to "escape" the scroll parent's boundaries
                        // https://github.com/twbs/bootstrap/issues/24251


                        if (this._config.boundary !== 'scrollParent') {
                            $$$1(parent).addClass(ClassName.POSITION_STATIC);
                        }

                        this._popper = new Popper(element, this._menu, this._getPopperConfig());
                    } // If this is a touch-enabled device we add extra
                    // empty mouseover listeners to the body's immediate children;
                    // only needed because of broken event delegation on iOS
                    // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html


                    if ('ontouchstart' in document.documentElement && $$$1(parent).closest(Selector.NAVBAR_NAV).length === 0) {
                        $$$1('body').children().on('mouseover', null, $$$1.noop);
                    }

                    this._element.focus();

                    this._element.setAttribute('aria-expanded', true);

                    $$$1(this._menu).toggleClass(ClassName.SHOW);
                    $$$1(parent).toggleClass(ClassName.SHOW).trigger($$$1.Event(Event.SHOWN, relatedTarget));
                };

                _proto.dispose = function dispose() {
                    $$$1.removeData(this._element, DATA_KEY);
                    $$$1(this._element).off(EVENT_KEY);
                    this._element = null;
                    this._menu = null;

                    if (this._popper !== null) {
                        this._popper.destroy();

                        this._popper = null;
                    }
                };

                _proto.update = function update() {
                    this._inNavbar = this._detectNavbar();

                    if (this._popper !== null) {
                        this._popper.scheduleUpdate();
                    }
                }; // Private


                _proto._addEventListeners = function _addEventListeners() {
                    var _this = this;

                    $$$1(this._element).on(Event.CLICK, function (event) {
                        event.preventDefault();
                        event.stopPropagation();

                        _this.toggle();
                    });
                };

                _proto._getConfig = function _getConfig(config) {
                    config = _extends({}, this.constructor.Default, $$$1(this._element).data(), config);
                    Util.typeCheckConfig(NAME, config, this.constructor.DefaultType);
                    return config;
                };

                _proto._getMenuElement = function _getMenuElement() {
                    if (!this._menu) {
                        var parent = Dropdown._getParentFromElement(this._element);

                        this._menu = $$$1(parent).find(Selector.MENU)[0];
                    }

                    return this._menu;
                };

                _proto._getPlacement = function _getPlacement() {
                    var $parentDropdown = $$$1(this._element).parent();
                    var placement = AttachmentMap.BOTTOM; // Handle dropup

                    if ($parentDropdown.hasClass(ClassName.DROPUP)) {
                        placement = AttachmentMap.TOP;

                        if ($$$1(this._menu).hasClass(ClassName.MENURIGHT)) {
                            placement = AttachmentMap.TOPEND;
                        }
                    } else if ($parentDropdown.hasClass(ClassName.DROPRIGHT)) {
                        placement = AttachmentMap.RIGHT;
                    } else if ($parentDropdown.hasClass(ClassName.DROPLEFT)) {
                        placement = AttachmentMap.LEFT;
                    } else if ($$$1(this._menu).hasClass(ClassName.MENURIGHT)) {
                        placement = AttachmentMap.BOTTOMEND;
                    }

                    return placement;
                };

                _proto._detectNavbar = function _detectNavbar() {
                    return $$$1(this._element).closest('.navbar').length > 0;
                };

                _proto._getPopperConfig = function _getPopperConfig() {
                    var _this2 = this;

                    var offsetConf = {};

                    if (typeof this._config.offset === 'function') {
                        offsetConf.fn = function (data) {
                            data.offsets = _extends({}, data.offsets, _this2._config.offset(data.offsets) || {});
                            return data;
                        };
                    } else {
                        offsetConf.offset = this._config.offset;
                    }

                    var popperConfig = {
                        placement: this._getPlacement(),
                        modifiers: {
                            offset: offsetConf,
                            flip: {
                                enabled: this._config.flip
                            },
                            preventOverflow: {
                                boundariesElement: this._config.boundary
                            }
                        }
                    };
                    return popperConfig;
                }; // Static


                Dropdown._jQueryInterface = function _jQueryInterface(config) {
                    return this.each(function () {
                        var data = $$$1(this).data(DATA_KEY);

                        var _config = typeof config === 'object' ? config : null;

                        if (!data) {
                            data = new Dropdown(this, _config);
                            $$$1(this).data(DATA_KEY, data);
                        }

                        if (typeof config === 'string') {
                            if (typeof data[config] === 'undefined') {
                                throw new TypeError("No method named \"" + config + "\"");
                            }

                            data[config]();
                        }
                    });
                };

                Dropdown._clearMenus = function _clearMenus(event) {
                    if (event && (event.which === RIGHT_MOUSE_BUTTON_WHICH || event.type === 'keyup' && event.which !== TAB_KEYCODE)) {
                        return;
                    }

                    var toggles = $$$1.makeArray($$$1(Selector.DATA_TOGGLE));

                    for (var i = 0; i < toggles.length; i++) {
                        var parent = Dropdown._getParentFromElement(toggles[i]);

                        var context = $$$1(toggles[i]).data(DATA_KEY);
                        var relatedTarget = {
                            relatedTarget: toggles[i]
                        };

                        if (!context) {
                            continue;
                        }

                        var dropdownMenu = context._menu;

                        if (!$$$1(parent).hasClass(ClassName.SHOW)) {
                            continue;
                        }

                        if (event && (event.type === 'click' && /input|textarea/i.test(event.target.tagName) || event.type === 'keyup' && event.which === TAB_KEYCODE) && $$$1.contains(parent, event.target)) {
                            continue;
                        }

                        var hideEvent = $$$1.Event(Event.HIDE, relatedTarget);
                        $$$1(parent).trigger(hideEvent);

                        if (hideEvent.isDefaultPrevented()) {
                            continue;
                        } // If this is a touch-enabled device we remove the extra
                        // empty mouseover listeners we added for iOS support


                        if ('ontouchstart' in document.documentElement) {
                            $$$1('body').children().off('mouseover', null, $$$1.noop);
                        }

                        toggles[i].setAttribute('aria-expanded', 'false');
                        $$$1(dropdownMenu).removeClass(ClassName.SHOW);
                        $$$1(parent).removeClass(ClassName.SHOW).trigger($$$1.Event(Event.HIDDEN, relatedTarget));
                    }
                };

                Dropdown._getParentFromElement = function _getParentFromElement(element) {
                    var parent;
                    var selector = Util.getSelectorFromElement(element);

                    if (selector) {
                        parent = $$$1(selector)[0];
                    }

                    return parent || element.parentNode;
                }; // eslint-disable-next-line complexity


                Dropdown._dataApiKeydownHandler = function _dataApiKeydownHandler(event) {
                    // If not input/textarea:
                    //  - And not a key in REGEXP_KEYDOWN => not a dropdown command
                    // If input/textarea:
                    //  - If space key => not a dropdown command
                    //  - If key is other than escape
                    //    - If key is not up or down => not a dropdown command
                    //    - If trigger inside the menu => not a dropdown command
                    if (/input|textarea/i.test(event.target.tagName) ? event.which === SPACE_KEYCODE || event.which !== ESCAPE_KEYCODE && (event.which !== ARROW_DOWN_KEYCODE && event.which !== ARROW_UP_KEYCODE || $$$1(event.target).closest(Selector.MENU).length) : !REGEXP_KEYDOWN.test(event.which)) {
                        return;
                    }

                    event.preventDefault();
                    event.stopPropagation();

                    if (this.disabled || $$$1(this).hasClass(ClassName.DISABLED)) {
                        return;
                    }

                    var parent = Dropdown._getParentFromElement(this);

                    var isActive = $$$1(parent).hasClass(ClassName.SHOW);

                    if (!isActive && (event.which !== ESCAPE_KEYCODE || event.which !== SPACE_KEYCODE) || isActive && (event.which === ESCAPE_KEYCODE || event.which === SPACE_KEYCODE)) {
                        if (event.which === ESCAPE_KEYCODE) {
                            var toggle = $$$1(parent).find(Selector.DATA_TOGGLE)[0];
                            $$$1(toggle).trigger('focus');
                        }

                        $$$1(this).trigger('click');
                        return;
                    }

                    var items = $$$1(parent).find(Selector.VISIBLE_ITEMS).get();

                    if (items.length === 0) {
                        return;
                    }

                    var index = items.indexOf(event.target);

                    if (event.which === ARROW_UP_KEYCODE && index > 0) {
                        // Up
                        index--;
                    }

                    if (event.which === ARROW_DOWN_KEYCODE && index < items.length - 1) {
                        // Down
                        index++;
                    }

                    if (index < 0) {
                        index = 0;
                    }

                    items[index].focus();
                };

                _createClass(Dropdown, null, [{
                    key: "VERSION",
                    get: function get() {
                        return VERSION;
                    }
                }, {
                    key: "Default",
                    get: function get() {
                        return Default;
                    }
                }, {
                    key: "DefaultType",
                    get: function get() {
                        return DefaultType;
                    }
                }]);
                return Dropdown;
            }();
        /**
         * ------------------------------------------------------------------------
         * Data Api implementation
         * ------------------------------------------------------------------------
         */


        $$$1(document).on(Event.KEYDOWN_DATA_API, Selector.DATA_TOGGLE, Dropdown._dataApiKeydownHandler).on(Event.KEYDOWN_DATA_API, Selector.MENU, Dropdown._dataApiKeydownHandler).on(Event.CLICK_DATA_API + " " + Event.KEYUP_DATA_API, Dropdown._clearMenus).on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (event) {
            event.preventDefault();
            event.stopPropagation();

            Dropdown._jQueryInterface.call($$$1(this), 'toggle');
        }).on(Event.CLICK_DATA_API, Selector.FORM_CHILD, function (e) {
            e.stopPropagation();
        });
        /**
         * ------------------------------------------------------------------------
         * jQuery
         * ------------------------------------------------------------------------
         */

        $$$1.fn[NAME] = Dropdown._jQueryInterface;
        $$$1.fn[NAME].Constructor = Dropdown;

        $$$1.fn[NAME].noConflict = function () {
            $$$1.fn[NAME] = JQUERY_NO_CONFLICT;
            return Dropdown._jQueryInterface;
        };

        return Dropdown;
    }($, Popper);

    /**
     * --------------------------------------------------------------------------
     * Bootstrap (v4.0.0): modal.js
     * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
     * --------------------------------------------------------------------------
     */

    var Modal = function ($$$1) {
        /**
         * ------------------------------------------------------------------------
         * Constants
         * ------------------------------------------------------------------------
         */
        var NAME = 'modal';
        var VERSION = '4.0.0';
        var DATA_KEY = 'bs.modal';
        var EVENT_KEY = "." + DATA_KEY;
        var DATA_API_KEY = '.data-api';
        var JQUERY_NO_CONFLICT = $$$1.fn[NAME];
        var TRANSITION_DURATION = 300;
        var BACKDROP_TRANSITION_DURATION = 150;
        var ESCAPE_KEYCODE = 27; // KeyboardEvent.which value for Escape (Esc) key

        var Default = {
            backdrop: true,
            keyboard: true,
            focus: true,
            show: true
        };
        var DefaultType = {
            backdrop: '(boolean|string)',
            keyboard: 'boolean',
            focus: 'boolean',
            show: 'boolean'
        };
        var Event = {
            HIDE: "hide" + EVENT_KEY,
            HIDDEN: "hidden" + EVENT_KEY,
            SHOW: "show" + EVENT_KEY,
            SHOWN: "shown" + EVENT_KEY,
            FOCUSIN: "focusin" + EVENT_KEY,
            RESIZE: "resize" + EVENT_KEY,
            CLICK_DISMISS: "click.dismiss" + EVENT_KEY,
            KEYDOWN_DISMISS: "keydown.dismiss" + EVENT_KEY,
            MOUSEUP_DISMISS: "mouseup.dismiss" + EVENT_KEY,
            MOUSEDOWN_DISMISS: "mousedown.dismiss" + EVENT_KEY,
            CLICK_DATA_API: "click" + EVENT_KEY + DATA_API_KEY
        };
        var ClassName = {
            SCROLLBAR_MEASURER: 'modal-scrollbar-measure',
            BACKDROP: 'modal-backdrop',
            OPEN: 'modal-open',
            FADE: 'fade',
            SHOW: 'show'
        };
        var Selector = {
            DIALOG: '.modal-dialog',
            DATA_TOGGLE: '[data-toggle="modal"]',
            DATA_DISMISS: '[data-dismiss="modal"]',
            FIXED_CONTENT: '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top',
            STICKY_CONTENT: '.sticky-top',
            NAVBAR_TOGGLER: '.navbar-toggler'
            /**
             * ------------------------------------------------------------------------
             * Class Definition
             * ------------------------------------------------------------------------
             */

        };

        var Modal =
            /*#__PURE__*/
            function () {
                function Modal(element, config) {
                    this._config = this._getConfig(config);
                    this._element = element;
                    this._dialog = $$$1(element).find(Selector.DIALOG)[0];
                    this._backdrop = null;
                    this._isShown = false;
                    this._isBodyOverflowing = false;
                    this._ignoreBackdropClick = false;
                    this._originalBodyPadding = 0;
                    this._scrollbarWidth = 0;
                } // Getters


                var _proto = Modal.prototype;

                // Public
                _proto.toggle = function toggle(relatedTarget) {
                    return this._isShown ? this.hide() : this.show(relatedTarget);
                };

                _proto.show = function show(relatedTarget) {
                    var _this = this;

                    if (this._isTransitioning || this._isShown) {
                        return;
                    }

                    if (Util.supportsTransitionEnd() && $$$1(this._element).hasClass(ClassName.FADE)) {
                        this._isTransitioning = true;
                    }

                    var showEvent = $$$1.Event(Event.SHOW, {
                        relatedTarget: relatedTarget
                    });
                    $$$1(this._element).trigger(showEvent);

                    if (this._isShown || showEvent.isDefaultPrevented()) {
                        return;
                    }

                    this._isShown = true;

                    this._checkScrollbar();

                    this._setScrollbar();

                    this._adjustDialog();

                    $$$1(document.body).addClass(ClassName.OPEN);

                    this._setEscapeEvent();

                    this._setResizeEvent();

                    $$$1(this._element).on(Event.CLICK_DISMISS, Selector.DATA_DISMISS, function (event) {
                        return _this.hide(event);
                    });
                    $$$1(this._dialog).on(Event.MOUSEDOWN_DISMISS, function () {
                        $$$1(_this._element).one(Event.MOUSEUP_DISMISS, function (event) {
                            if ($$$1(event.target).is(_this._element)) {
                                _this._ignoreBackdropClick = true;
                            }
                        });
                    });

                    this._showBackdrop(function () {
                        return _this._showElement(relatedTarget);
                    });
                };

                _proto.hide = function hide(event) {
                    var _this2 = this;

                    if (event) {
                        event.preventDefault();
                    }

                    if (this._isTransitioning || !this._isShown) {
                        return;
                    }

                    var hideEvent = $$$1.Event(Event.HIDE);
                    $$$1(this._element).trigger(hideEvent);

                    if (!this._isShown || hideEvent.isDefaultPrevented()) {
                        return;
                    }

                    this._isShown = false;
                    var transition = Util.supportsTransitionEnd() && $$$1(this._element).hasClass(ClassName.FADE);

                    if (transition) {
                        this._isTransitioning = true;
                    }

                    this._setEscapeEvent();

                    this._setResizeEvent();

                    $$$1(document).off(Event.FOCUSIN);
                    $$$1(this._element).removeClass(ClassName.SHOW);
                    $$$1(this._element).off(Event.CLICK_DISMISS);
                    $$$1(this._dialog).off(Event.MOUSEDOWN_DISMISS);

                    if (transition) {
                        $$$1(this._element).one(Util.TRANSITION_END, function (event) {
                            return _this2._hideModal(event);
                        }).emulateTransitionEnd(TRANSITION_DURATION);
                    } else {
                        this._hideModal();
                    }
                };

                _proto.dispose = function dispose() {
                    $$$1.removeData(this._element, DATA_KEY);
                    $$$1(window, document, this._element, this._backdrop).off(EVENT_KEY);
                    this._config = null;
                    this._element = null;
                    this._dialog = null;
                    this._backdrop = null;
                    this._isShown = null;
                    this._isBodyOverflowing = null;
                    this._ignoreBackdropClick = null;
                    this._scrollbarWidth = null;
                };

                _proto.handleUpdate = function handleUpdate() {
                    this._adjustDialog();
                }; // Private


                _proto._getConfig = function _getConfig(config) {
                    config = _extends({}, Default, config);
                    Util.typeCheckConfig(NAME, config, DefaultType);
                    return config;
                };

                _proto._showElement = function _showElement(relatedTarget) {
                    var _this3 = this;

                    var transition = Util.supportsTransitionEnd() && $$$1(this._element).hasClass(ClassName.FADE);

                    if (!this._element.parentNode || this._element.parentNode.nodeType !== Node.ELEMENT_NODE) {
                        // Don't move modal's DOM position
                        document.body.appendChild(this._element);
                    }

                    this._element.style.display = 'block';

                    this._element.removeAttribute('aria-hidden');

                    this._element.scrollTop = 0;

                    if (transition) {
                        Util.reflow(this._element);
                    }

                    $$$1(this._element).addClass(ClassName.SHOW);

                    if (this._config.focus) {
                        this._enforceFocus();
                    }

                    var shownEvent = $$$1.Event(Event.SHOWN, {
                        relatedTarget: relatedTarget
                    });

                    var transitionComplete = function transitionComplete() {
                        if (_this3._config.focus) {
                            _this3._element.focus();
                        }

                        _this3._isTransitioning = false;
                        $$$1(_this3._element).trigger(shownEvent);
                    };

                    if (transition) {
                        $$$1(this._dialog).one(Util.TRANSITION_END, transitionComplete).emulateTransitionEnd(TRANSITION_DURATION);
                    } else {
                        transitionComplete();
                    }
                };

                _proto._enforceFocus = function _enforceFocus() {
                    var _this4 = this;

                    $$$1(document).off(Event.FOCUSIN) // Guard against infinite focus loop
                        .on(Event.FOCUSIN, function (event) {
                            if (document !== event.target && _this4._element !== event.target && $$$1(_this4._element).has(event.target).length === 0) {
                                _this4._element.focus();
                            }
                        });
                };

                _proto._setEscapeEvent = function _setEscapeEvent() {
                    var _this5 = this;

                    if (this._isShown && this._config.keyboard) {
                        $$$1(this._element).on(Event.KEYDOWN_DISMISS, function (event) {
                            if (event.which === ESCAPE_KEYCODE) {
                                event.preventDefault();

                                _this5.hide();
                            }
                        });
                    } else if (!this._isShown) {
                        $$$1(this._element).off(Event.KEYDOWN_DISMISS);
                    }
                };

                _proto._setResizeEvent = function _setResizeEvent() {
                    var _this6 = this;

                    if (this._isShown) {
                        $$$1(window).on(Event.RESIZE, function (event) {
                            return _this6.handleUpdate(event);
                        });
                    } else {
                        $$$1(window).off(Event.RESIZE);
                    }
                };

                _proto._hideModal = function _hideModal() {
                    var _this7 = this;

                    this._element.style.display = 'none';

                    this._element.setAttribute('aria-hidden', true);

                    this._isTransitioning = false;

                    this._showBackdrop(function () {
                        $$$1(document.body).removeClass(ClassName.OPEN);

                        _this7._resetAdjustments();

                        _this7._resetScrollbar();

                        $$$1(_this7._element).trigger(Event.HIDDEN);
                    });
                };

                _proto._removeBackdrop = function _removeBackdrop() {
                    if (this._backdrop) {
                        $$$1(this._backdrop).remove();
                        this._backdrop = null;
                    }
                };

                _proto._showBackdrop = function _showBackdrop(callback) {
                    var _this8 = this;

                    var animate = $$$1(this._element).hasClass(ClassName.FADE) ? ClassName.FADE : '';

                    if (this._isShown && this._config.backdrop) {
                        var doAnimate = Util.supportsTransitionEnd() && animate;
                        this._backdrop = document.createElement('div');
                        this._backdrop.className = ClassName.BACKDROP;

                        if (animate) {
                            $$$1(this._backdrop).addClass(animate);
                        }

                        $$$1(this._backdrop).appendTo(document.body);
                        $$$1(this._element).on(Event.CLICK_DISMISS, function (event) {
                            if (_this8._ignoreBackdropClick) {
                                _this8._ignoreBackdropClick = false;
                                return;
                            }

                            if (event.target !== event.currentTarget) {
                                return;
                            }

                            if (_this8._config.backdrop === 'static') {
                                _this8._element.focus();
                            } else {
                                _this8.hide();
                            }
                        });

                        if (doAnimate) {
                            Util.reflow(this._backdrop);
                        }

                        $$$1(this._backdrop).addClass(ClassName.SHOW);

                        if (!callback) {
                            return;
                        }

                        if (!doAnimate) {
                            callback();
                            return;
                        }

                        $$$1(this._backdrop).one(Util.TRANSITION_END, callback).emulateTransitionEnd(BACKDROP_TRANSITION_DURATION);
                    } else if (!this._isShown && this._backdrop) {
                        $$$1(this._backdrop).removeClass(ClassName.SHOW);

                        var callbackRemove = function callbackRemove() {
                            _this8._removeBackdrop();

                            if (callback) {
                                callback();
                            }
                        };

                        if (Util.supportsTransitionEnd() && $$$1(this._element).hasClass(ClassName.FADE)) {
                            $$$1(this._backdrop).one(Util.TRANSITION_END, callbackRemove).emulateTransitionEnd(BACKDROP_TRANSITION_DURATION);
                        } else {
                            callbackRemove();
                        }
                    } else if (callback) {
                        callback();
                    }
                }; // ----------------------------------------------------------------------
                // the following methods are used to handle overflowing modals
                // todo (fat): these should probably be refactored out of modal.js
                // ----------------------------------------------------------------------


                _proto._adjustDialog = function _adjustDialog() {
                    var isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight;

                    if (!this._isBodyOverflowing && isModalOverflowing) {
                        this._element.style.paddingLeft = this._scrollbarWidth + "px";
                    }

                    if (this._isBodyOverflowing && !isModalOverflowing) {
                        this._element.style.paddingRight = this._scrollbarWidth + "px";
                    }
                };

                _proto._resetAdjustments = function _resetAdjustments() {
                    this._element.style.paddingLeft = '';
                    this._element.style.paddingRight = '';
                };

                _proto._checkScrollbar = function _checkScrollbar() {
                    var rect = document.body.getBoundingClientRect();
                    this._isBodyOverflowing = rect.left + rect.right < window.innerWidth;
                    this._scrollbarWidth = this._getScrollbarWidth();
                };

                _proto._setScrollbar = function _setScrollbar() {
                    var _this9 = this;

                    if (this._isBodyOverflowing) {
                        // Note: DOMNode.style.paddingRight returns the actual value or '' if not set
                        //   while $(DOMNode).css('padding-right') returns the calculated value or 0 if not set
                        // Adjust fixed content padding
                        $$$1(Selector.FIXED_CONTENT).each(function (index, element) {
                            var actualPadding = $$$1(element)[0].style.paddingRight;
                            var calculatedPadding = $$$1(element).css('padding-right');
                            $$$1(element).data('padding-right', actualPadding).css('padding-right', parseFloat(calculatedPadding) + _this9._scrollbarWidth + "px");
                        }); // Adjust sticky content margin

                        $$$1(Selector.STICKY_CONTENT).each(function (index, element) {
                            var actualMargin = $$$1(element)[0].style.marginRight;
                            var calculatedMargin = $$$1(element).css('margin-right');
                            $$$1(element).data('margin-right', actualMargin).css('margin-right', parseFloat(calculatedMargin) - _this9._scrollbarWidth + "px");
                        }); // Adjust navbar-toggler margin

                        $$$1(Selector.NAVBAR_TOGGLER).each(function (index, element) {
                            var actualMargin = $$$1(element)[0].style.marginRight;
                            var calculatedMargin = $$$1(element).css('margin-right');
                            $$$1(element).data('margin-right', actualMargin).css('margin-right', parseFloat(calculatedMargin) + _this9._scrollbarWidth + "px");
                        }); // Adjust body padding

                        var actualPadding = document.body.style.paddingRight;
                        var calculatedPadding = $$$1('body').css('padding-right');
                        $$$1('body').data('padding-right', actualPadding).css('padding-right', parseFloat(calculatedPadding) + this._scrollbarWidth + "px");
                    }
                };

                _proto._resetScrollbar = function _resetScrollbar() {
                    // Restore fixed content padding
                    $$$1(Selector.FIXED_CONTENT).each(function (index, element) {
                        var padding = $$$1(element).data('padding-right');

                        if (typeof padding !== 'undefined') {
                            $$$1(element).css('padding-right', padding).removeData('padding-right');
                        }
                    }); // Restore sticky content and navbar-toggler margin

                    $$$1(Selector.STICKY_CONTENT + ", " + Selector.NAVBAR_TOGGLER).each(function (index, element) {
                        var margin = $$$1(element).data('margin-right');

                        if (typeof margin !== 'undefined') {
                            $$$1(element).css('margin-right', margin).removeData('margin-right');
                        }
                    }); // Restore body padding

                    var padding = $$$1('body').data('padding-right');

                    if (typeof padding !== 'undefined') {
                        $$$1('body').css('padding-right', padding).removeData('padding-right');
                    }
                };

                _proto._getScrollbarWidth = function _getScrollbarWidth() {
                    // thx d.walsh
                    var scrollDiv = document.createElement('div');
                    scrollDiv.className = ClassName.SCROLLBAR_MEASURER;
                    document.body.appendChild(scrollDiv);
                    var scrollbarWidth = scrollDiv.getBoundingClientRect().width - scrollDiv.clientWidth;
                    document.body.removeChild(scrollDiv);
                    return scrollbarWidth;
                }; // Static


                Modal._jQueryInterface = function _jQueryInterface(config, relatedTarget) {
                    return this.each(function () {
                        var data = $$$1(this).data(DATA_KEY);

                        var _config = _extends({}, Modal.Default, $$$1(this).data(), typeof config === 'object' && config);

                        if (!data) {
                            data = new Modal(this, _config);
                            $$$1(this).data(DATA_KEY, data);
                        }

                        if (typeof config === 'string') {
                            if (typeof data[config] === 'undefined') {
                                throw new TypeError("No method named \"" + config + "\"");
                            }

                            data[config](relatedTarget);
                        } else if (_config.show) {
                            data.show(relatedTarget);
                        }
                    });
                };

                _createClass(Modal, null, [{
                    key: "VERSION",
                    get: function get() {
                        return VERSION;
                    }
                }, {
                    key: "Default",
                    get: function get() {
                        return Default;
                    }
                }]);
                return Modal;
            }();
        /**
         * ------------------------------------------------------------------------
         * Data Api implementation
         * ------------------------------------------------------------------------
         */


        $$$1(document).on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (event) {
            var _this10 = this;

            var target;
            var selector = Util.getSelectorFromElement(this);

            if (selector) {
                target = $$$1(selector)[0];
            }

            var config = $$$1(target).data(DATA_KEY) ? 'toggle' : _extends({}, $$$1(target).data(), $$$1(this).data());

            if (this.tagName === 'A' || this.tagName === 'AREA') {
                event.preventDefault();
            }

            var $target = $$$1(target).one(Event.SHOW, function (showEvent) {
                if (showEvent.isDefaultPrevented()) {
                    // Only register focus restorer if modal will actually get shown
                    return;
                }

                $target.one(Event.HIDDEN, function () {
                    if ($$$1(_this10).is(':visible')) {
                        _this10.focus();
                    }
                });
            });

            Modal._jQueryInterface.call($$$1(target), config, this);
        });
        /**
         * ------------------------------------------------------------------------
         * jQuery
         * ------------------------------------------------------------------------
         */

        $$$1.fn[NAME] = Modal._jQueryInterface;
        $$$1.fn[NAME].Constructor = Modal;

        $$$1.fn[NAME].noConflict = function () {
            $$$1.fn[NAME] = JQUERY_NO_CONFLICT;
            return Modal._jQueryInterface;
        };

        return Modal;
    }($);

    /**
     * --------------------------------------------------------------------------
     * Bootstrap (v4.0.0): tooltip.js
     * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
     * --------------------------------------------------------------------------
     */

    var Tooltip = function ($$$1) {
        /**
         * ------------------------------------------------------------------------
         * Constants
         * ------------------------------------------------------------------------
         */
        var NAME = 'tooltip';
        var VERSION = '4.0.0';
        var DATA_KEY = 'bs.tooltip';
        var EVENT_KEY = "." + DATA_KEY;
        var JQUERY_NO_CONFLICT = $$$1.fn[NAME];
        var TRANSITION_DURATION = 150;
        var CLASS_PREFIX = 'bs-tooltip';
        var BSCLS_PREFIX_REGEX = new RegExp("(^|\\s)" + CLASS_PREFIX + "\\S+", 'g');
        var DefaultType = {
            animation: 'boolean',
            template: 'string',
            title: '(string|element|function)',
            trigger: 'string',
            delay: '(number|object)',
            html: 'boolean',
            selector: '(string|boolean)',
            placement: '(string|function)',
            offset: '(number|string)',
            container: '(string|element|boolean)',
            fallbackPlacement: '(string|array)',
            boundary: '(string|element)'
        };
        var AttachmentMap = {
            AUTO: 'auto',
            TOP: 'top',
            RIGHT: 'right',
            BOTTOM: 'bottom',
            LEFT: 'left'
        };
        var Default = {
            animation: true,
            template: '<div class="tooltip" role="tooltip">' + '<div class="arrow"></div>' + '<div class="tooltip-inner"></div></div>',
            trigger: 'hover focus',
            title: '',
            delay: 0,
            html: false,
            selector: false,
            placement: 'top',
            offset: 0,
            container: false,
            fallbackPlacement: 'flip',
            boundary: 'scrollParent'
        };
        var HoverState = {
            SHOW: 'show',
            OUT: 'out'
        };
        var Event = {
            HIDE: "hide" + EVENT_KEY,
            HIDDEN: "hidden" + EVENT_KEY,
            SHOW: "show" + EVENT_KEY,
            SHOWN: "shown" + EVENT_KEY,
            INSERTED: "inserted" + EVENT_KEY,
            CLICK: "click" + EVENT_KEY,
            FOCUSIN: "focusin" + EVENT_KEY,
            FOCUSOUT: "focusout" + EVENT_KEY,
            MOUSEENTER: "mouseenter" + EVENT_KEY,
            MOUSELEAVE: "mouseleave" + EVENT_KEY
        };
        var ClassName = {
            FADE: 'fade',
            SHOW: 'show'
        };
        var Selector = {
            TOOLTIP: '.tooltip',
            TOOLTIP_INNER: '.tooltip-inner',
            ARROW: '.arrow'
        };
        var Trigger = {
            HOVER: 'hover',
            FOCUS: 'focus',
            CLICK: 'click',
            MANUAL: 'manual'
            /**
             * ------------------------------------------------------------------------
             * Class Definition
             * ------------------------------------------------------------------------
             */

        };

        var Tooltip =
            /*#__PURE__*/
            function () {
                function Tooltip(element, config) {
                    /**
                     * Check for Popper dependency
                     * Popper - https://popper.js.org
                     */
                    if (typeof Popper === 'undefined') {
                        throw new TypeError('Bootstrap tooltips require Popper.js (https://popper.js.org)');
                    } // private


                    this._isEnabled = true;
                    this._timeout = 0;
                    this._hoverState = '';
                    this._activeTrigger = {};
                    this._popper = null; // Protected

                    this.element = element;
                    this.config = this._getConfig(config);
                    this.tip = null;

                    this._setListeners();
                } // Getters


                var _proto = Tooltip.prototype;

                // Public
                _proto.enable = function enable() {
                    this._isEnabled = true;
                };

                _proto.disable = function disable() {
                    this._isEnabled = false;
                };

                _proto.toggleEnabled = function toggleEnabled() {
                    this._isEnabled = !this._isEnabled;
                };

                _proto.toggle = function toggle(event) {
                    if (!this._isEnabled) {
                        return;
                    }

                    if (event) {
                        var dataKey = this.constructor.DATA_KEY;
                        var context = $$$1(event.currentTarget).data(dataKey);

                        if (!context) {
                            context = new this.constructor(event.currentTarget, this._getDelegateConfig());
                            $$$1(event.currentTarget).data(dataKey, context);
                        }

                        context._activeTrigger.click = !context._activeTrigger.click;

                        if (context._isWithActiveTrigger()) {
                            context._enter(null, context);
                        } else {
                            context._leave(null, context);
                        }
                    } else {
                        if ($$$1(this.getTipElement()).hasClass(ClassName.SHOW)) {
                            this._leave(null, this);

                            return;
                        }

                        this._enter(null, this);
                    }
                };

                _proto.dispose = function dispose() {
                    clearTimeout(this._timeout);
                    $$$1.removeData(this.element, this.constructor.DATA_KEY);
                    $$$1(this.element).off(this.constructor.EVENT_KEY);
                    $$$1(this.element).closest('.modal').off('hide.bs.modal');

                    if (this.tip) {
                        $$$1(this.tip).remove();
                    }

                    this._isEnabled = null;
                    this._timeout = null;
                    this._hoverState = null;
                    this._activeTrigger = null;

                    if (this._popper !== null) {
                        this._popper.destroy();
                    }

                    this._popper = null;
                    this.element = null;
                    this.config = null;
                    this.tip = null;
                };

                _proto.show = function show() {
                    var _this = this;

                    if ($$$1(this.element).css('display') === 'none') {
                        throw new Error('Please use show on visible elements');
                    }

                    var showEvent = $$$1.Event(this.constructor.Event.SHOW);

                    if (this.isWithContent() && this._isEnabled) {
                        $$$1(this.element).trigger(showEvent);
                        var isInTheDom = $$$1.contains(this.element.ownerDocument.documentElement, this.element);

                        if (showEvent.isDefaultPrevented() || !isInTheDom) {
                            return;
                        }

                        var tip = this.getTipElement();
                        var tipId = Util.getUID(this.constructor.NAME);
                        tip.setAttribute('id', tipId);
                        this.element.setAttribute('aria-describedby', tipId);
                        this.setContent();

                        if (this.config.animation) {
                            $$$1(tip).addClass(ClassName.FADE);
                        }

                        var placement = typeof this.config.placement === 'function' ? this.config.placement.call(this, tip, this.element) : this.config.placement;

                        var attachment = this._getAttachment(placement);

                        this.addAttachmentClass(attachment);
                        var container = this.config.container === false ? document.body : $$$1(this.config.container);
                        $$$1(tip).data(this.constructor.DATA_KEY, this);

                        if (!$$$1.contains(this.element.ownerDocument.documentElement, this.tip)) {
                            $$$1(tip).appendTo(container);
                        }

                        $$$1(this.element).trigger(this.constructor.Event.INSERTED);
                        this._popper = new Popper(this.element, tip, {
                            placement: attachment,
                            modifiers: {
                                offset: {
                                    offset: this.config.offset
                                },
                                flip: {
                                    behavior: this.config.fallbackPlacement
                                },
                                arrow: {
                                    element: Selector.ARROW
                                },
                                preventOverflow: {
                                    boundariesElement: this.config.boundary
                                }
                            },
                            onCreate: function onCreate(data) {
                                if (data.originalPlacement !== data.placement) {
                                    _this._handlePopperPlacementChange(data);
                                }
                            },
                            onUpdate: function onUpdate(data) {
                                _this._handlePopperPlacementChange(data);
                            }
                        });
                        $$$1(tip).addClass(ClassName.SHOW); // If this is a touch-enabled device we add extra
                        // empty mouseover listeners to the body's immediate children;
                        // only needed because of broken event delegation on iOS
                        // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html

                        if ('ontouchstart' in document.documentElement) {
                            $$$1('body').children().on('mouseover', null, $$$1.noop);
                        }

                        var complete = function complete() {
                            if (_this.config.animation) {
                                _this._fixTransition();
                            }

                            var prevHoverState = _this._hoverState;
                            _this._hoverState = null;
                            $$$1(_this.element).trigger(_this.constructor.Event.SHOWN);

                            if (prevHoverState === HoverState.OUT) {
                                _this._leave(null, _this);
                            }
                        };

                        if (Util.supportsTransitionEnd() && $$$1(this.tip).hasClass(ClassName.FADE)) {
                            $$$1(this.tip).one(Util.TRANSITION_END, complete).emulateTransitionEnd(Tooltip._TRANSITION_DURATION);
                        } else {
                            complete();
                        }
                    }
                };

                _proto.hide = function hide(callback) {
                    var _this2 = this;

                    var tip = this.getTipElement();
                    var hideEvent = $$$1.Event(this.constructor.Event.HIDE);

                    var complete = function complete() {
                        if (_this2._hoverState !== HoverState.SHOW && tip.parentNode) {
                            tip.parentNode.removeChild(tip);
                        }

                        _this2._cleanTipClass();

                        _this2.element.removeAttribute('aria-describedby');

                        $$$1(_this2.element).trigger(_this2.constructor.Event.HIDDEN);

                        if (_this2._popper !== null) {
                            _this2._popper.destroy();
                        }

                        if (callback) {
                            callback();
                        }
                    };

                    $$$1(this.element).trigger(hideEvent);

                    if (hideEvent.isDefaultPrevented()) {
                        return;
                    }

                    $$$1(tip).removeClass(ClassName.SHOW); // If this is a touch-enabled device we remove the extra
                    // empty mouseover listeners we added for iOS support

                    if ('ontouchstart' in document.documentElement) {
                        $$$1('body').children().off('mouseover', null, $$$1.noop);
                    }

                    this._activeTrigger[Trigger.CLICK] = false;
                    this._activeTrigger[Trigger.FOCUS] = false;
                    this._activeTrigger[Trigger.HOVER] = false;

                    if (Util.supportsTransitionEnd() && $$$1(this.tip).hasClass(ClassName.FADE)) {
                        $$$1(tip).one(Util.TRANSITION_END, complete).emulateTransitionEnd(TRANSITION_DURATION);
                    } else {
                        complete();
                    }

                    this._hoverState = '';
                };

                _proto.update = function update() {
                    if (this._popper !== null) {
                        this._popper.scheduleUpdate();
                    }
                }; // Protected


                _proto.isWithContent = function isWithContent() {
                    return Boolean(this.getTitle());
                };

                _proto.addAttachmentClass = function addAttachmentClass(attachment) {
                    $$$1(this.getTipElement()).addClass(CLASS_PREFIX + "-" + attachment);
                };

                _proto.getTipElement = function getTipElement() {
                    this.tip = this.tip || $$$1(this.config.template)[0];
                    return this.tip;
                };

                _proto.setContent = function setContent() {
                    var $tip = $$$1(this.getTipElement());
                    this.setElementContent($tip.find(Selector.TOOLTIP_INNER), this.getTitle());
                    $tip.removeClass(ClassName.FADE + " " + ClassName.SHOW);
                };

                _proto.setElementContent = function setElementContent($element, content) {
                    var html = this.config.html;

                    if (typeof content === 'object' && (content.nodeType || content.jquery)) {
                        // Content is a DOM node or a jQuery
                        if (html) {
                            if (!$$$1(content).parent().is($element)) {
                                $element.empty().append(content);
                            }
                        } else {
                            $element.text($$$1(content).text());
                        }
                    } else {
                        $element[html ? 'html' : 'text'](content);
                    }
                };

                _proto.getTitle = function getTitle() {
                    var title = this.element.getAttribute('data-original-title');

                    if (!title) {
                        title = typeof this.config.title === 'function' ? this.config.title.call(this.element) : this.config.title;
                    }

                    return title;
                }; // Private


                _proto._getAttachment = function _getAttachment(placement) {
                    return AttachmentMap[placement.toUpperCase()];
                };

                _proto._setListeners = function _setListeners() {
                    var _this3 = this;

                    var triggers = this.config.trigger.split(' ');
                    triggers.forEach(function (trigger) {
                        if (trigger === 'click') {
                            $$$1(_this3.element).on(_this3.constructor.Event.CLICK, _this3.config.selector, function (event) {
                                return _this3.toggle(event);
                            });
                        } else if (trigger !== Trigger.MANUAL) {
                            var eventIn = trigger === Trigger.HOVER ? _this3.constructor.Event.MOUSEENTER : _this3.constructor.Event.FOCUSIN;
                            var eventOut = trigger === Trigger.HOVER ? _this3.constructor.Event.MOUSELEAVE : _this3.constructor.Event.FOCUSOUT;
                            $$$1(_this3.element).on(eventIn, _this3.config.selector, function (event) {
                                return _this3._enter(event);
                            }).on(eventOut, _this3.config.selector, function (event) {
                                return _this3._leave(event);
                            });
                        }

                        $$$1(_this3.element).closest('.modal').on('hide.bs.modal', function () {
                            return _this3.hide();
                        });
                    });

                    if (this.config.selector) {
                        this.config = _extends({}, this.config, {
                            trigger: 'manual',
                            selector: ''
                        });
                    } else {
                        this._fixTitle();
                    }
                };

                _proto._fixTitle = function _fixTitle() {
                    var titleType = typeof this.element.getAttribute('data-original-title');

                    if (this.element.getAttribute('title') || titleType !== 'string') {
                        this.element.setAttribute('data-original-title', this.element.getAttribute('title') || '');
                        this.element.setAttribute('title', '');
                    }
                };

                _proto._enter = function _enter(event, context) {
                    var dataKey = this.constructor.DATA_KEY;
                    context = context || $$$1(event.currentTarget).data(dataKey);

                    if (!context) {
                        context = new this.constructor(event.currentTarget, this._getDelegateConfig());
                        $$$1(event.currentTarget).data(dataKey, context);
                    }

                    if (event) {
                        context._activeTrigger[event.type === 'focusin' ? Trigger.FOCUS : Trigger.HOVER] = true;
                    }

                    if ($$$1(context.getTipElement()).hasClass(ClassName.SHOW) || context._hoverState === HoverState.SHOW) {
                        context._hoverState = HoverState.SHOW;
                        return;
                    }

                    clearTimeout(context._timeout);
                    context._hoverState = HoverState.SHOW;

                    if (!context.config.delay || !context.config.delay.show) {
                        context.show();
                        return;
                    }

                    context._timeout = setTimeout(function () {
                        if (context._hoverState === HoverState.SHOW) {
                            context.show();
                        }
                    }, context.config.delay.show);
                };

                _proto._leave = function _leave(event, context) {
                    var dataKey = this.constructor.DATA_KEY;
                    context = context || $$$1(event.currentTarget).data(dataKey);

                    if (!context) {
                        context = new this.constructor(event.currentTarget, this._getDelegateConfig());
                        $$$1(event.currentTarget).data(dataKey, context);
                    }

                    if (event) {
                        context._activeTrigger[event.type === 'focusout' ? Trigger.FOCUS : Trigger.HOVER] = false;
                    }

                    if (context._isWithActiveTrigger()) {
                        return;
                    }

                    clearTimeout(context._timeout);
                    context._hoverState = HoverState.OUT;

                    if (!context.config.delay || !context.config.delay.hide) {
                        context.hide();
                        return;
                    }

                    context._timeout = setTimeout(function () {
                        if (context._hoverState === HoverState.OUT) {
                            context.hide();
                        }
                    }, context.config.delay.hide);
                };

                _proto._isWithActiveTrigger = function _isWithActiveTrigger() {
                    for (var trigger in this._activeTrigger) {
                        if (this._activeTrigger[trigger]) {
                            return true;
                        }
                    }

                    return false;
                };

                _proto._getConfig = function _getConfig(config) {
                    config = _extends({}, this.constructor.Default, $$$1(this.element).data(), config);

                    if (typeof config.delay === 'number') {
                        config.delay = {
                            show: config.delay,
                            hide: config.delay
                        };
                    }

                    if (typeof config.title === 'number') {
                        config.title = config.title.toString();
                    }

                    if (typeof config.content === 'number') {
                        config.content = config.content.toString();
                    }

                    Util.typeCheckConfig(NAME, config, this.constructor.DefaultType);
                    return config;
                };

                _proto._getDelegateConfig = function _getDelegateConfig() {
                    var config = {};

                    if (this.config) {
                        for (var key in this.config) {
                            if (this.constructor.Default[key] !== this.config[key]) {
                                config[key] = this.config[key];
                            }
                        }
                    }

                    return config;
                };

                _proto._cleanTipClass = function _cleanTipClass() {
                    var $tip = $$$1(this.getTipElement());
                    var tabClass = $tip.attr('class').match(BSCLS_PREFIX_REGEX);

                    if (tabClass !== null && tabClass.length > 0) {
                        $tip.removeClass(tabClass.join(''));
                    }
                };

                _proto._handlePopperPlacementChange = function _handlePopperPlacementChange(data) {
                    this._cleanTipClass();

                    this.addAttachmentClass(this._getAttachment(data.placement));
                };

                _proto._fixTransition = function _fixTransition() {
                    var tip = this.getTipElement();
                    var initConfigAnimation = this.config.animation;

                    if (tip.getAttribute('x-placement') !== null) {
                        return;
                    }

                    $$$1(tip).removeClass(ClassName.FADE);
                    this.config.animation = false;
                    this.hide();
                    this.show();
                    this.config.animation = initConfigAnimation;
                }; // Static


                Tooltip._jQueryInterface = function _jQueryInterface(config) {
                    return this.each(function () {
                        var data = $$$1(this).data(DATA_KEY);

                        var _config = typeof config === 'object' && config;

                        if (!data && /dispose|hide/.test(config)) {
                            return;
                        }

                        if (!data) {
                            data = new Tooltip(this, _config);
                            $$$1(this).data(DATA_KEY, data);
                        }

                        if (typeof config === 'string') {
                            if (typeof data[config] === 'undefined') {
                                throw new TypeError("No method named \"" + config + "\"");
                            }

                            data[config]();
                        }
                    });
                };

                _createClass(Tooltip, null, [{
                    key: "VERSION",
                    get: function get() {
                        return VERSION;
                    }
                }, {
                    key: "Default",
                    get: function get() {
                        return Default;
                    }
                }, {
                    key: "NAME",
                    get: function get() {
                        return NAME;
                    }
                }, {
                    key: "DATA_KEY",
                    get: function get() {
                        return DATA_KEY;
                    }
                }, {
                    key: "Event",
                    get: function get() {
                        return Event;
                    }
                }, {
                    key: "EVENT_KEY",
                    get: function get() {
                        return EVENT_KEY;
                    }
                }, {
                    key: "DefaultType",
                    get: function get() {
                        return DefaultType;
                    }
                }]);
                return Tooltip;
            }();
        /**
         * ------------------------------------------------------------------------
         * jQuery
         * ------------------------------------------------------------------------
         */


        $$$1.fn[NAME] = Tooltip._jQueryInterface;
        $$$1.fn[NAME].Constructor = Tooltip;

        $$$1.fn[NAME].noConflict = function () {
            $$$1.fn[NAME] = JQUERY_NO_CONFLICT;
            return Tooltip._jQueryInterface;
        };

        return Tooltip;
    }($, Popper);

    /**
     * --------------------------------------------------------------------------
     * Bootstrap (v4.0.0): popover.js
     * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
     * --------------------------------------------------------------------------
     */

    var Popover = function ($$$1) {
        /**
         * ------------------------------------------------------------------------
         * Constants
         * ------------------------------------------------------------------------
         */
        var NAME = 'popover';
        var VERSION = '4.0.0';
        var DATA_KEY = 'bs.popover';
        var EVENT_KEY = "." + DATA_KEY;
        var JQUERY_NO_CONFLICT = $$$1.fn[NAME];
        var CLASS_PREFIX = 'bs-popover';
        var BSCLS_PREFIX_REGEX = new RegExp("(^|\\s)" + CLASS_PREFIX + "\\S+", 'g');
        var Default = _extends({}, Tooltip.Default, {
            placement: 'right',
            trigger: 'click',
            content: '',
            template: '<div class="popover" role="tooltip">' + '<div class="arrow"></div>' + '<h3 class="popover-header"></h3>' + '<div class="popover-body"></div></div>'
        });
        var DefaultType = _extends({}, Tooltip.DefaultType, {
            content: '(string|element|function)'
        });
        var ClassName = {
            FADE: 'fade',
            SHOW: 'show'
        };
        var Selector = {
            TITLE: '.popover-header',
            CONTENT: '.popover-body'
        };
        var Event = {
            HIDE: "hide" + EVENT_KEY,
            HIDDEN: "hidden" + EVENT_KEY,
            SHOW: "show" + EVENT_KEY,
            SHOWN: "shown" + EVENT_KEY,
            INSERTED: "inserted" + EVENT_KEY,
            CLICK: "click" + EVENT_KEY,
            FOCUSIN: "focusin" + EVENT_KEY,
            FOCUSOUT: "focusout" + EVENT_KEY,
            MOUSEENTER: "mouseenter" + EVENT_KEY,
            MOUSELEAVE: "mouseleave" + EVENT_KEY
            /**
             * ------------------------------------------------------------------------
             * Class Definition
             * ------------------------------------------------------------------------
             */

        };

        var Popover =
            /*#__PURE__*/
            function (_Tooltip) {
                _inheritsLoose(Popover, _Tooltip);

                function Popover() {
                    return _Tooltip.apply(this, arguments) || this;
                }

                var _proto = Popover.prototype;

                // Overrides
                _proto.isWithContent = function isWithContent() {
                    return this.getTitle() || this._getContent();
                };

                _proto.addAttachmentClass = function addAttachmentClass(attachment) {
                    $$$1(this.getTipElement()).addClass(CLASS_PREFIX + "-" + attachment);
                };

                _proto.getTipElement = function getTipElement() {
                    this.tip = this.tip || $$$1(this.config.template)[0];
                    return this.tip;
                };

                _proto.setContent = function setContent() {
                    var $tip = $$$1(this.getTipElement()); // We use append for html objects to maintain js events

                    this.setElementContent($tip.find(Selector.TITLE), this.getTitle());

                    var content = this._getContent();

                    if (typeof content === 'function') {
                        content = content.call(this.element);
                    }

                    this.setElementContent($tip.find(Selector.CONTENT), content);
                    $tip.removeClass(ClassName.FADE + " " + ClassName.SHOW);
                }; // Private


                _proto._getContent = function _getContent() {
                    return this.element.getAttribute('data-content') || this.config.content;
                };

                _proto._cleanTipClass = function _cleanTipClass() {
                    var $tip = $$$1(this.getTipElement());
                    var tabClass = $tip.attr('class').match(BSCLS_PREFIX_REGEX);

                    if (tabClass !== null && tabClass.length > 0) {
                        $tip.removeClass(tabClass.join(''));
                    }
                }; // Static


                Popover._jQueryInterface = function _jQueryInterface(config) {
                    return this.each(function () {
                        var data = $$$1(this).data(DATA_KEY);

                        var _config = typeof config === 'object' ? config : null;

                        if (!data && /destroy|hide/.test(config)) {
                            return;
                        }

                        if (!data) {
                            data = new Popover(this, _config);
                            $$$1(this).data(DATA_KEY, data);
                        }

                        if (typeof config === 'string') {
                            if (typeof data[config] === 'undefined') {
                                throw new TypeError("No method named \"" + config + "\"");
                            }

                            data[config]();
                        }
                    });
                };

                _createClass(Popover, null, [{
                    key: "VERSION",
                    // Getters
                    get: function get() {
                        return VERSION;
                    }
                }, {
                    key: "Default",
                    get: function get() {
                        return Default;
                    }
                }, {
                    key: "NAME",
                    get: function get() {
                        return NAME;
                    }
                }, {
                    key: "DATA_KEY",
                    get: function get() {
                        return DATA_KEY;
                    }
                }, {
                    key: "Event",
                    get: function get() {
                        return Event;
                    }
                }, {
                    key: "EVENT_KEY",
                    get: function get() {
                        return EVENT_KEY;
                    }
                }, {
                    key: "DefaultType",
                    get: function get() {
                        return DefaultType;
                    }
                }]);
                return Popover;
            }(Tooltip);
        /**
         * ------------------------------------------------------------------------
         * jQuery
         * ------------------------------------------------------------------------
         */


        $$$1.fn[NAME] = Popover._jQueryInterface;
        $$$1.fn[NAME].Constructor = Popover;

        $$$1.fn[NAME].noConflict = function () {
            $$$1.fn[NAME] = JQUERY_NO_CONFLICT;
            return Popover._jQueryInterface;
        };

        return Popover;
    }($);

    /**
     * --------------------------------------------------------------------------
     * Bootstrap (v4.0.0): scrollspy.js
     * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
     * --------------------------------------------------------------------------
     */

    var ScrollSpy = function ($$$1) {
        /**
         * ------------------------------------------------------------------------
         * Constants
         * ------------------------------------------------------------------------
         */
        var NAME = 'scrollspy';
        var VERSION = '4.0.0';
        var DATA_KEY = 'bs.scrollspy';
        var EVENT_KEY = "." + DATA_KEY;
        var DATA_API_KEY = '.data-api';
        var JQUERY_NO_CONFLICT = $$$1.fn[NAME];
        var Default = {
            offset: 10,
            method: 'auto',
            target: ''
        };
        var DefaultType = {
            offset: 'number',
            method: 'string',
            target: '(string|element)'
        };
        var Event = {
            ACTIVATE: "activate" + EVENT_KEY,
            SCROLL: "scroll" + EVENT_KEY,
            LOAD_DATA_API: "load" + EVENT_KEY + DATA_API_KEY
        };
        var ClassName = {
            DROPDOWN_ITEM: 'dropdown-item',
            DROPDOWN_MENU: 'dropdown-menu',
            ACTIVE: 'active'
        };
        var Selector = {
            DATA_SPY: '[data-spy="scroll"]',
            ACTIVE: '.active',
            NAV_LIST_GROUP: '.nav, .list-group',
            NAV_LINKS: '.nav-link',
            NAV_ITEMS: '.nav-item',
            LIST_ITEMS: '.list-group-item',
            DROPDOWN: '.dropdown',
            DROPDOWN_ITEMS: '.dropdown-item',
            DROPDOWN_TOGGLE: '.dropdown-toggle'
        };
        var OffsetMethod = {
            OFFSET: 'offset',
            POSITION: 'position'
            /**
             * ------------------------------------------------------------------------
             * Class Definition
             * ------------------------------------------------------------------------
             */

        };

        var ScrollSpy =
            /*#__PURE__*/
            function () {
                function ScrollSpy(element, config) {
                    var _this = this;

                    this._element = element;
                    this._scrollElement = element.tagName === 'BODY' ? window : element;
                    this._config = this._getConfig(config);
                    this._selector = this._config.target + " " + Selector.NAV_LINKS + "," + (this._config.target + " " + Selector.LIST_ITEMS + ",") + (this._config.target + " " + Selector.DROPDOWN_ITEMS);
                    this._offsets = [];
                    this._targets = [];
                    this._activeTarget = null;
                    this._scrollHeight = 0;
                    $$$1(this._scrollElement).on(Event.SCROLL, function (event) {
                        return _this._process(event);
                    });
                    this.refresh();

                    this._process();
                } // Getters


                var _proto = ScrollSpy.prototype;

                // Public
                _proto.refresh = function refresh() {
                    var _this2 = this;

                    var autoMethod = this._scrollElement === this._scrollElement.window ? OffsetMethod.OFFSET : OffsetMethod.POSITION;
                    var offsetMethod = this._config.method === 'auto' ? autoMethod : this._config.method;
                    var offsetBase = offsetMethod === OffsetMethod.POSITION ? this._getScrollTop() : 0;
                    this._offsets = [];
                    this._targets = [];
                    this._scrollHeight = this._getScrollHeight();
                    var targets = $$$1.makeArray($$$1(this._selector));
                    targets.map(function (element) {
                        var target;
                        var targetSelector = Util.getSelectorFromElement(element);

                        if (targetSelector) {
                            target = $$$1(targetSelector)[0];
                        }

                        if (target) {
                            var targetBCR = target.getBoundingClientRect();

                            if (targetBCR.width || targetBCR.height) {
                                // TODO (fat): remove sketch reliance on jQuery position/offset
                                return [$$$1(target)[offsetMethod]().top + offsetBase, targetSelector];
                            }
                        }

                        return null;
                    }).filter(function (item) {
                        return item;
                    }).sort(function (a, b) {
                        return a[0] - b[0];
                    }).forEach(function (item) {
                        _this2._offsets.push(item[0]);

                        _this2._targets.push(item[1]);
                    });
                };

                _proto.dispose = function dispose() {
                    $$$1.removeData(this._element, DATA_KEY);
                    $$$1(this._scrollElement).off(EVENT_KEY);
                    this._element = null;
                    this._scrollElement = null;
                    this._config = null;
                    this._selector = null;
                    this._offsets = null;
                    this._targets = null;
                    this._activeTarget = null;
                    this._scrollHeight = null;
                }; // Private


                _proto._getConfig = function _getConfig(config) {
                    config = _extends({}, Default, config);

                    if (typeof config.target !== 'string') {
                        var id = $$$1(config.target).attr('id');

                        if (!id) {
                            id = Util.getUID(NAME);
                            $$$1(config.target).attr('id', id);
                        }

                        config.target = "#" + id;
                    }

                    Util.typeCheckConfig(NAME, config, DefaultType);
                    return config;
                };

                _proto._getScrollTop = function _getScrollTop() {
                    return this._scrollElement === window ? this._scrollElement.pageYOffset : this._scrollElement.scrollTop;
                };

                _proto._getScrollHeight = function _getScrollHeight() {
                    return this._scrollElement.scrollHeight || Math.max(document.body.scrollHeight, document.documentElement.scrollHeight);
                };

                _proto._getOffsetHeight = function _getOffsetHeight() {
                    return this._scrollElement === window ? window.innerHeight : this._scrollElement.getBoundingClientRect().height;
                };

                _proto._process = function _process() {
                    var scrollTop = this._getScrollTop() + this._config.offset;

                    var scrollHeight = this._getScrollHeight();

                    var maxScroll = this._config.offset + scrollHeight - this._getOffsetHeight();

                    if (this._scrollHeight !== scrollHeight) {
                        this.refresh();
                    }

                    if (scrollTop >= maxScroll) {
                        var target = this._targets[this._targets.length - 1];

                        if (this._activeTarget !== target) {
                            this._activate(target);
                        }

                        return;
                    }

                    if (this._activeTarget && scrollTop < this._offsets[0] && this._offsets[0] > 0) {
                        this._activeTarget = null;

                        this._clear();

                        return;
                    }

                    for (var i = this._offsets.length; i--;) {
                        var isActiveTarget = this._activeTarget !== this._targets[i] && scrollTop >= this._offsets[i] && (typeof this._offsets[i + 1] === 'undefined' || scrollTop < this._offsets[i + 1]);

                        if (isActiveTarget) {
                            this._activate(this._targets[i]);
                        }
                    }
                };

                _proto._activate = function _activate(target) {
                    this._activeTarget = target;

                    this._clear();

                    var queries = this._selector.split(','); // eslint-disable-next-line arrow-body-style


                    queries = queries.map(function (selector) {
                        return selector + "[data-target=\"" + target + "\"]," + (selector + "[href=\"" + target + "\"]");
                    });
                    var $link = $$$1(queries.join(','));

                    if ($link.hasClass(ClassName.DROPDOWN_ITEM)) {
                        $link.closest(Selector.DROPDOWN).find(Selector.DROPDOWN_TOGGLE).addClass(ClassName.ACTIVE);
                        $link.addClass(ClassName.ACTIVE);
                    } else {
                        // Set triggered link as active
                        $link.addClass(ClassName.ACTIVE); // Set triggered links parents as active
                        // With both <ul> and <nav> markup a parent is the previous sibling of any nav ancestor

                        $link.parents(Selector.NAV_LIST_GROUP).prev(Selector.NAV_LINKS + ", " + Selector.LIST_ITEMS).addClass(ClassName.ACTIVE); // Handle special case when .nav-link is inside .nav-item

                        $link.parents(Selector.NAV_LIST_GROUP).prev(Selector.NAV_ITEMS).children(Selector.NAV_LINKS).addClass(ClassName.ACTIVE);
                    }

                    $$$1(this._scrollElement).trigger(Event.ACTIVATE, {
                        relatedTarget: target
                    });
                };

                _proto._clear = function _clear() {
                    $$$1(this._selector).filter(Selector.ACTIVE).removeClass(ClassName.ACTIVE);
                }; // Static


                ScrollSpy._jQueryInterface = function _jQueryInterface(config) {
                    return this.each(function () {
                        var data = $$$1(this).data(DATA_KEY);

                        var _config = typeof config === 'object' && config;

                        if (!data) {
                            data = new ScrollSpy(this, _config);
                            $$$1(this).data(DATA_KEY, data);
                        }

                        if (typeof config === 'string') {
                            if (typeof data[config] === 'undefined') {
                                throw new TypeError("No method named \"" + config + "\"");
                            }

                            data[config]();
                        }
                    });
                };

                _createClass(ScrollSpy, null, [{
                    key: "VERSION",
                    get: function get() {
                        return VERSION;
                    }
                }, {
                    key: "Default",
                    get: function get() {
                        return Default;
                    }
                }]);
                return ScrollSpy;
            }();
        /**
         * ------------------------------------------------------------------------
         * Data Api implementation
         * ------------------------------------------------------------------------
         */


        $$$1(window).on(Event.LOAD_DATA_API, function () {
            var scrollSpys = $$$1.makeArray($$$1(Selector.DATA_SPY));

            for (var i = scrollSpys.length; i--;) {
                var $spy = $$$1(scrollSpys[i]);

                ScrollSpy._jQueryInterface.call($spy, $spy.data());
            }
        });
        /**
         * ------------------------------------------------------------------------
         * jQuery
         * ------------------------------------------------------------------------
         */

        $$$1.fn[NAME] = ScrollSpy._jQueryInterface;
        $$$1.fn[NAME].Constructor = ScrollSpy;

        $$$1.fn[NAME].noConflict = function () {
            $$$1.fn[NAME] = JQUERY_NO_CONFLICT;
            return ScrollSpy._jQueryInterface;
        };

        return ScrollSpy;
    }($);

    /**
     * --------------------------------------------------------------------------
     * Bootstrap (v4.0.0): tab.js
     * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
     * --------------------------------------------------------------------------
     */

    var Tab = function ($$$1) {
        /**
         * ------------------------------------------------------------------------
         * Constants
         * ------------------------------------------------------------------------
         */
        var NAME = 'tab';
        var VERSION = '4.0.0';
        var DATA_KEY = 'bs.tab';
        var EVENT_KEY = "." + DATA_KEY;
        var DATA_API_KEY = '.data-api';
        var JQUERY_NO_CONFLICT = $$$1.fn[NAME];
        var TRANSITION_DURATION = 150;
        var Event = {
            HIDE: "hide" + EVENT_KEY,
            HIDDEN: "hidden" + EVENT_KEY,
            SHOW: "show" + EVENT_KEY,
            SHOWN: "shown" + EVENT_KEY,
            CLICK_DATA_API: "click" + EVENT_KEY + DATA_API_KEY
        };
        var ClassName = {
            DROPDOWN_MENU: 'dropdown-menu',
            ACTIVE: 'active',
            DISABLED: 'disabled',
            FADE: 'fade',
            SHOW: 'show'
        };
        var Selector = {
            DROPDOWN: '.dropdown',
            NAV_LIST_GROUP: '.nav, .list-group',
            ACTIVE: '.active',
            ACTIVE_UL: '> li > .active',
            DATA_TOGGLE: '[data-toggle="tab"], [data-toggle="pill"], [data-toggle="list"]',
            DROPDOWN_TOGGLE: '.dropdown-toggle',
            DROPDOWN_ACTIVE_CHILD: '> .dropdown-menu .active'
            /**
             * ------------------------------------------------------------------------
             * Class Definition
             * ------------------------------------------------------------------------
             */

        };

        var Tab =
            /*#__PURE__*/
            function () {
                function Tab(element) {
                    this._element = element;
                } // Getters


                var _proto = Tab.prototype;

                // Public
                _proto.show = function show() {
                    var _this = this;

                    if (this._element.parentNode && this._element.parentNode.nodeType === Node.ELEMENT_NODE && $$$1(this._element).hasClass(ClassName.ACTIVE) || $$$1(this._element).hasClass(ClassName.DISABLED)) {
                        return;
                    }

                    var target;
                    var previous;
                    var listElement = $$$1(this._element).closest(Selector.NAV_LIST_GROUP)[0];
                    var selector = Util.getSelectorFromElement(this._element);

                    if (listElement) {
                        var itemSelector = listElement.nodeName === 'UL' ? Selector.ACTIVE_UL : Selector.ACTIVE;
                        previous = $$$1.makeArray($$$1(listElement).find(itemSelector));
                        previous = previous[previous.length - 1];
                    }

                    var hideEvent = $$$1.Event(Event.HIDE, {
                        relatedTarget: this._element
                    });
                    var showEvent = $$$1.Event(Event.SHOW, {
                        relatedTarget: previous
                    });

                    if (previous) {
                        $$$1(previous).trigger(hideEvent);
                    }

                    $$$1(this._element).trigger(showEvent);

                    if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) {
                        return;
                    }

                    if (selector) {
                        target = $$$1(selector)[0];
                    }

                    this._activate(this._element, listElement);

                    var complete = function complete() {
                        var hiddenEvent = $$$1.Event(Event.HIDDEN, {
                            relatedTarget: _this._element
                        });
                        var shownEvent = $$$1.Event(Event.SHOWN, {
                            relatedTarget: previous
                        });
                        $$$1(previous).trigger(hiddenEvent);
                        $$$1(_this._element).trigger(shownEvent);
                    };

                    if (target) {
                        this._activate(target, target.parentNode, complete);
                    } else {
                        complete();
                    }
                };

                _proto.dispose = function dispose() {
                    $$$1.removeData(this._element, DATA_KEY);
                    this._element = null;
                }; // Private


                _proto._activate = function _activate(element, container, callback) {
                    var _this2 = this;

                    var activeElements;

                    if (container.nodeName === 'UL') {
                        activeElements = $$$1(container).find(Selector.ACTIVE_UL);
                    } else {
                        activeElements = $$$1(container).children(Selector.ACTIVE);
                    }

                    var active = activeElements[0];
                    var isTransitioning = callback && Util.supportsTransitionEnd() && active && $$$1(active).hasClass(ClassName.FADE);

                    var complete = function complete() {
                        return _this2._transitionComplete(element, active, callback);
                    };

                    if (active && isTransitioning) {
                        $$$1(active).one(Util.TRANSITION_END, complete).emulateTransitionEnd(TRANSITION_DURATION);
                    } else {
                        complete();
                    }
                };

                _proto._transitionComplete = function _transitionComplete(element, active, callback) {
                    if (active) {
                        $$$1(active).removeClass(ClassName.SHOW + " " + ClassName.ACTIVE);
                        var dropdownChild = $$$1(active.parentNode).find(Selector.DROPDOWN_ACTIVE_CHILD)[0];

                        if (dropdownChild) {
                            $$$1(dropdownChild).removeClass(ClassName.ACTIVE);
                        }

                        if (active.getAttribute('role') === 'tab') {
                            active.setAttribute('aria-selected', false);
                        }
                    }

                    $$$1(element).addClass(ClassName.ACTIVE);

                    if (element.getAttribute('role') === 'tab') {
                        element.setAttribute('aria-selected', true);
                    }

                    Util.reflow(element);
                    $$$1(element).addClass(ClassName.SHOW);

                    if (element.parentNode && $$$1(element.parentNode).hasClass(ClassName.DROPDOWN_MENU)) {
                        var dropdownElement = $$$1(element).closest(Selector.DROPDOWN)[0];

                        if (dropdownElement) {
                            $$$1(dropdownElement).find(Selector.DROPDOWN_TOGGLE).addClass(ClassName.ACTIVE);
                        }

                        element.setAttribute('aria-expanded', true);
                    }

                    if (callback) {
                        callback();
                    }
                }; // Static


                Tab._jQueryInterface = function _jQueryInterface(config) {
                    return this.each(function () {
                        var $this = $$$1(this);
                        var data = $this.data(DATA_KEY);

                        if (!data) {
                            data = new Tab(this);
                            $this.data(DATA_KEY, data);
                        }

                        if (typeof config === 'string') {
                            if (typeof data[config] === 'undefined') {
                                throw new TypeError("No method named \"" + config + "\"");
                            }

                            data[config]();
                        }
                    });
                };

                _createClass(Tab, null, [{
                    key: "VERSION",
                    get: function get() {
                        return VERSION;
                    }
                }]);
                return Tab;
            }();
        /**
         * ------------------------------------------------------------------------
         * Data Api implementation
         * ------------------------------------------------------------------------
         */


        $$$1(document).on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (event) {
            event.preventDefault();

            Tab._jQueryInterface.call($$$1(this), 'show');
        });
        /**
         * ------------------------------------------------------------------------
         * jQuery
         * ------------------------------------------------------------------------
         */

        $$$1.fn[NAME] = Tab._jQueryInterface;
        $$$1.fn[NAME].Constructor = Tab;

        $$$1.fn[NAME].noConflict = function () {
            $$$1.fn[NAME] = JQUERY_NO_CONFLICT;
            return Tab._jQueryInterface;
        };

        return Tab;
    }($);

    /**
     * --------------------------------------------------------------------------
     * Bootstrap (v4.0.0-alpha.6): index.js
     * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
     * --------------------------------------------------------------------------
     */

    (function ($$$1) {
        if (typeof $$$1 === 'undefined') {
            throw new TypeError('Bootstrap\'s JavaScript requires jQuery. jQuery must be included before Bootstrap\'s JavaScript.');
        }

        var version = $$$1.fn.jquery.split(' ')[0].split('.');
        var minMajor = 1;
        var ltMajor = 2;
        var minMinor = 9;
        var minPatch = 1;
        var maxMajor = 4;

        if (version[0] < ltMajor && version[1] < minMinor || version[0] === minMajor && version[1] === minMinor && version[2] < minPatch || version[0] >= maxMajor) {
            throw new Error('Bootstrap\'s JavaScript requires at least jQuery v1.9.1 but less than v4.0.0');
        }
    })($);

    exports.Util = Util;
    exports.Alert = Alert;
    exports.Button = Button;
    exports.Carousel = Carousel;
    exports.Collapse = Collapse;
    exports.Dropdown = Dropdown;
    exports.Modal = Modal;
    exports.Popover = Popover;
    exports.Scrollspy = ScrollSpy;
    exports.Tab = Tab;
    exports.Tooltip = Tooltip;

    Object.defineProperty(exports, '__esModule', { value: true });

})));
//# sourceMappingURL=bootstrap.js.map
;
/*!
 * Knockout JavaScript library v3.4.1
 * (c) The Knockout.js team - http://knockoutjs.com/
 * License: MIT (http://www.opensource.org/licenses/mit-license.php)
 */
(function () {
    (function (n) {
        var x = this || (0, eval)("this"), s = x.document, M = x.navigator, u = x.jQuery, F = x.JSON;
        (function (n) { "function" === typeof define && define.amd ? define(["exports", "require"], n) : "object" === typeof exports && "object" === typeof module ? n(module.exports || exports) : n(x.ko = {}); })(function (N, O) {
            function J(a, c) { return null === a || typeof a in R ? a === c : !1; }
            function S(b, c) { var d; return function () { d || (d = a.a.setTimeout(function () { d = n; b(); }, c)); }; }
            function T(b, c) { var d; return function () { clearTimeout(d); d = a.a.setTimeout(b, c); }; }
            function U(a, c) { c && c !== I ? "beforeChange" === c ? this.Lb(a) : this.Ha(a, c) : this.Mb(a); }
            function V(a, c) { null !== c && c.k && c.k(); }
            function W(a, c) { var d = this.Ic, e = d[t]; e.S || (this.lb && this.Ma[c] ? (d.Qb(c, a, this.Ma[c]), this.Ma[c] = null, --this.lb) : e.r[c] || d.Qb(c, a, e.s ? { ia: a } : d.wc(a))); }
            function K(b, c, d, e) {
                a.d[b] = { init: function (b, g, h, l, m) {
                        var k, r;
                        a.m(function () {
                            var q = g(), p = a.a.c(q), p = !d !== !p, A = !r;
                            if (A || c || p !== k)
                                A && a.va.Aa() && (r = a.a.ua(a.f.childNodes(b), !0)), p ? (A || a.f.da(b, a.a.ua(r)), a.eb(e ? e(m, q) : m, b)) : a.f.xa(b), k = p;
                        }, null, { i: b });
                        return { controlsDescendantBindings: !0 };
                    } };
                a.h.ta[b] = !1;
                a.f.Z[b] = !0;
            }
            var a = "undefined" !== typeof N ? N : {};
            a.b = function (b, c) {
                for (var d = b.split("."), e = a, f = 0; f < d.length - 1; f++)
                    e = e[d[f]];
                e[d[d.length - 1]] = c;
            };
            a.G = function (a, c, d) { a[c] = d; };
            a.version = "3.4.1";
            a.b("version", a.version);
            a.options = { deferUpdates: !1, useOnlyNativeEvents: !1 };
            a.a = function () {
                function b(a, b) {
                    for (var c in a)
                        a.hasOwnProperty(c) && b(c, a[c]);
                }
                function c(a, b) {
                    if (b)
                        for (var c in b)
                            b.hasOwnProperty(c) && (a[c] = b[c]);
                    return a;
                }
                function d(a, b) { a.__proto__ = b; return a; }
                function e(b, c, d, e) {
                    var k = b[c].match(r) ||
                        [];
                    a.a.q(d.match(r), function (b) { a.a.pa(k, b, e); });
                    b[c] = k.join(" ");
                }
                var f = { __proto__: [] } instanceof Array, g = "function" === typeof Symbol, h = {}, l = {};
                h[M && /Firefox\/2/i.test(M.userAgent) ? "KeyboardEvent" : "UIEvents"] = ["keyup", "keydown", "keypress"];
                h.MouseEvents = "click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave".split(" ");
                b(h, function (a, b) {
                    if (b.length)
                        for (var c = 0, d = b.length; c < d; c++)
                            l[b[c]] = a;
                });
                var m = { propertychange: !0 }, k = s && function () {
                    for (var a = 3, b = s.createElement("div"), c = b.getElementsByTagName("i"); b.innerHTML = "\x3c!--[if gt IE " + ++a + "]><i></i><![endif]--\x3e", c[0];)
                        ;
                    return 4 < a ? a : n;
                }(), r = /\S+/g;
                return { ec: ["authenticity_token", /^__RequestVerificationToken(_.*)?$/], q: function (a, b) {
                        for (var c = 0, d = a.length; c < d; c++)
                            b(a[c], c);
                    }, o: function (a, b) {
                        if ("function" == typeof Array.prototype.indexOf)
                            return Array.prototype.indexOf.call(a, b);
                        for (var c = 0, d = a.length; c < d; c++)
                            if (a[c] === b)
                                return c;
                        return -1;
                    }, Tb: function (a, b, c) {
                        for (var d = 0, e = a.length; d < e; d++)
                            if (b.call(c, a[d], d))
                                return a[d];
                        return null;
                    }, La: function (b, c) { var d = a.a.o(b, c); 0 < d ? b.splice(d, 1) : 0 === d && b.shift(); }, Ub: function (b) {
                        b = b || [];
                        for (var c = [], d = 0, e = b.length; d < e; d++)
                            0 > a.a.o(c, b[d]) && c.push(b[d]);
                        return c;
                    }, fb: function (a, b) {
                        a = a || [];
                        for (var c = [], d = 0, e = a.length; d < e; d++)
                            c.push(b(a[d], d));
                        return c;
                    }, Ka: function (a, b) {
                        a = a || [];
                        for (var c = [], d = 0, e = a.length; d < e; d++)
                            b(a[d], d) && c.push(a[d]);
                        return c;
                    }, ra: function (a, b) {
                        if (b instanceof Array)
                            a.push.apply(a, b);
                        else
                            for (var c = 0, d = b.length; c < d; c++)
                                a.push(b[c]);
                        return a;
                    }, pa: function (b, c, d) {
                        var e = a.a.o(a.a.zb(b), c);
                        0 > e ? d && b.push(c) : d || b.splice(e, 1);
                    }, ka: f, extend: c, Xa: d, Ya: f ? d : c, D: b, Ca: function (a, b) {
                        if (!a)
                            return a;
                        var c = {}, d;
                        for (d in a)
                            a.hasOwnProperty(d) && (c[d] = b(a[d], d, a));
                        return c;
                    }, ob: function (b) {
                        for (; b.firstChild;)
                            a.removeNode(b.firstChild);
                    }, lc: function (b) {
                        b = a.a.V(b);
                        for (var c = (b[0] && b[0].ownerDocument || s).createElement("div"), d = 0, e = b.length; d < e; d++)
                            c.appendChild(a.$(b[d]));
                        return c;
                    }, ua: function (b, c) {
                        for (var d = 0, e = b.length, k = []; d < e; d++) {
                            var m = b[d].cloneNode(!0);
                            k.push(c ? a.$(m) : m);
                        }
                        return k;
                    },
                    da: function (b, c) {
                        a.a.ob(b);
                        if (c)
                            for (var d = 0, e = c.length; d < e; d++)
                                b.appendChild(c[d]);
                    }, sc: function (b, c) {
                        var d = b.nodeType ? [b] : b;
                        if (0 < d.length) {
                            for (var e = d[0], k = e.parentNode, m = 0, f = c.length; m < f; m++)
                                k.insertBefore(c[m], e);
                            m = 0;
                            for (f = d.length; m < f; m++)
                                a.removeNode(d[m]);
                        }
                    }, za: function (a, b) {
                        if (a.length) {
                            for (b = 8 === b.nodeType && b.parentNode || b; a.length && a[0].parentNode !== b;)
                                a.splice(0, 1);
                            for (; 1 < a.length && a[a.length - 1].parentNode !== b;)
                                a.length--;
                            if (1 < a.length) {
                                var c = a[0], d = a[a.length - 1];
                                for (a.length = 0; c !== d;)
                                    a.push(c),
                                        c = c.nextSibling;
                                a.push(d);
                            }
                        }
                        return a;
                    }, uc: function (a, b) { 7 > k ? a.setAttribute("selected", b) : a.selected = b; }, $a: function (a) { return null === a || a === n ? "" : a.trim ? a.trim() : a.toString().replace(/^[\s\xa0]+|[\s\xa0]+$/g, ""); }, od: function (a, b) { a = a || ""; return b.length > a.length ? !1 : a.substring(0, b.length) === b; }, Nc: function (a, b) {
                        if (a === b)
                            return !0;
                        if (11 === a.nodeType)
                            return !1;
                        if (b.contains)
                            return b.contains(3 === a.nodeType ? a.parentNode : a);
                        if (b.compareDocumentPosition)
                            return 16 == (b.compareDocumentPosition(a) & 16);
                        for (; a && a !=
                            b;)
                            a = a.parentNode;
                        return !!a;
                    }, nb: function (b) { return a.a.Nc(b, b.ownerDocument.documentElement); }, Rb: function (b) { return !!a.a.Tb(b, a.a.nb); }, A: function (a) { return a && a.tagName && a.tagName.toLowerCase(); }, Xb: function (b) {
                        return a.onError ? function () {
                            try {
                                return b.apply(this, arguments);
                            }
                            catch (c) {
                                throw a.onError && a.onError(c), c;
                            }
                        } : b;
                    }, setTimeout: function (b, c) { return setTimeout(a.a.Xb(b), c); }, bc: function (b) { setTimeout(function () { a.onError && a.onError(b); throw b; }, 0); }, p: function (b, c, d) {
                        var e = a.a.Xb(d);
                        d = k && m[c];
                        if (a.options.useOnlyNativeEvents ||
                            d || !u)
                            if (d || "function" != typeof b.addEventListener)
                                if ("undefined" != typeof b.attachEvent) {
                                    var f = function (a) { e.call(b, a); }, l = "on" + c;
                                    b.attachEvent(l, f);
                                    a.a.F.oa(b, function () { b.detachEvent(l, f); });
                                }
                                else
                                    throw Error("Browser doesn't support addEventListener or attachEvent");
                            else
                                b.addEventListener(c, e, !1);
                        else
                            u(b).bind(c, e);
                    }, Da: function (b, c) {
                        if (!b || !b.nodeType)
                            throw Error("element must be a DOM node when calling triggerEvent");
                        var d;
                        "input" === a.a.A(b) && b.type && "click" == c.toLowerCase() ? (d = b.type, d = "checkbox" ==
                            d || "radio" == d) : d = !1;
                        if (a.options.useOnlyNativeEvents || !u || d)
                            if ("function" == typeof s.createEvent)
                                if ("function" == typeof b.dispatchEvent)
                                    d = s.createEvent(l[c] || "HTMLEvents"), d.initEvent(c, !0, !0, x, 0, 0, 0, 0, 0, !1, !1, !1, !1, 0, b), b.dispatchEvent(d);
                                else
                                    throw Error("The supplied element doesn't support dispatchEvent");
                            else if (d && b.click)
                                b.click();
                            else if ("undefined" != typeof b.fireEvent)
                                b.fireEvent("on" + c);
                            else
                                throw Error("Browser doesn't support triggering events");
                        else
                            u(b).trigger(c);
                    }, c: function (b) {
                        return a.H(b) ?
                            b() : b;
                    }, zb: function (b) { return a.H(b) ? b.t() : b; }, bb: function (b, c, d) { var k; c && ("object" === typeof b.classList ? (k = b.classList[d ? "add" : "remove"], a.a.q(c.match(r), function (a) { k.call(b.classList, a); })) : "string" === typeof b.className.baseVal ? e(b.className, "baseVal", c, d) : e(b, "className", c, d)); }, Za: function (b, c) {
                        var d = a.a.c(c);
                        if (null === d || d === n)
                            d = "";
                        var e = a.f.firstChild(b);
                        !e || 3 != e.nodeType || a.f.nextSibling(e) ? a.f.da(b, [b.ownerDocument.createTextNode(d)]) : e.data = d;
                        a.a.Sc(b);
                    }, tc: function (a, b) {
                        a.name = b;
                        if (7 >= k)
                            try {
                                a.mergeAttributes(s.createElement("<input name='" +
                                    a.name + "'/>"), !1);
                            }
                            catch (c) { }
                    }, Sc: function (a) { 9 <= k && (a = 1 == a.nodeType ? a : a.parentNode, a.style && (a.style.zoom = a.style.zoom)); }, Oc: function (a) {
                        if (k) {
                            var b = a.style.width;
                            a.style.width = 0;
                            a.style.width = b;
                        }
                    }, jd: function (b, c) {
                        b = a.a.c(b);
                        c = a.a.c(c);
                        for (var d = [], e = b; e <= c; e++)
                            d.push(e);
                        return d;
                    }, V: function (a) {
                        for (var b = [], c = 0, d = a.length; c < d; c++)
                            b.push(a[c]);
                        return b;
                    }, $b: function (a) { return g ? Symbol(a) : a; }, sd: 6 === k, ud: 7 === k, C: k, gc: function (b, c) {
                        for (var d = a.a.V(b.getElementsByTagName("input")).concat(a.a.V(b.getElementsByTagName("textarea"))), e = "string" == typeof c ? function (a) { return a.name === c; } : function (a) { return c.test(a.name); }, k = [], m = d.length - 1; 0 <= m; m--)
                            e(d[m]) && k.push(d[m]);
                        return k;
                    }, fd: function (b) { return "string" == typeof b && (b = a.a.$a(b)) ? F && F.parse ? F.parse(b) : (new Function("return " + b))() : null; }, Eb: function (b, c, d) {
                        if (!F || !F.stringify)
                            throw Error("Cannot find JSON.stringify(). Some browsers (e.g., IE < 8) don't support it natively, but you can overcome this by adding a script reference to json2.js, downloadable from http://www.json.org/json2.js");
                        return F.stringify(a.a.c(b), c, d);
                    }, gd: function (c, d, e) {
                        e = e || {};
                        var k = e.params || {}, m = e.includeFields || this.ec, f = c;
                        if ("object" == typeof c && "form" === a.a.A(c))
                            for (var f = c.action, l = m.length - 1; 0 <= l; l--)
                                for (var g = a.a.gc(c, m[l]), h = g.length - 1; 0 <= h; h--)
                                    k[g[h].name] = g[h].value;
                        d = a.a.c(d);
                        var r = s.createElement("form");
                        r.style.display = "none";
                        r.action = f;
                        r.method = "post";
                        for (var n in d)
                            c = s.createElement("input"), c.type = "hidden", c.name = n, c.value = a.a.Eb(a.a.c(d[n])), r.appendChild(c);
                        b(k, function (a, b) {
                            var c = s.createElement("input");
                            c.type = "hidden";
                            c.name = a;
                            c.value = b;
                            r.appendChild(c);
                        });
                        s.body.appendChild(r);
                        e.submitter ? e.submitter(r) : r.submit();
                        setTimeout(function () { r.parentNode.removeChild(r); }, 0);
                    } };
            }();
            a.b("utils", a.a);
            a.b("utils.arrayForEach", a.a.q);
            a.b("utils.arrayFirst", a.a.Tb);
            a.b("utils.arrayFilter", a.a.Ka);
            a.b("utils.arrayGetDistinctValues", a.a.Ub);
            a.b("utils.arrayIndexOf", a.a.o);
            a.b("utils.arrayMap", a.a.fb);
            a.b("utils.arrayPushAll", a.a.ra);
            a.b("utils.arrayRemoveItem", a.a.La);
            a.b("utils.extend", a.a.extend);
            a.b("utils.fieldsIncludedWithJsonPost", a.a.ec);
            a.b("utils.getFormFields", a.a.gc);
            a.b("utils.peekObservable", a.a.zb);
            a.b("utils.postJson", a.a.gd);
            a.b("utils.parseJson", a.a.fd);
            a.b("utils.registerEventHandler", a.a.p);
            a.b("utils.stringifyJson", a.a.Eb);
            a.b("utils.range", a.a.jd);
            a.b("utils.toggleDomNodeCssClass", a.a.bb);
            a.b("utils.triggerEvent", a.a.Da);
            a.b("utils.unwrapObservable", a.a.c);
            a.b("utils.objectForEach", a.a.D);
            a.b("utils.addOrRemoveItem", a.a.pa);
            a.b("utils.setTextContent", a.a.Za);
            a.b("unwrap", a.a.c);
            Function.prototype.bind || (Function.prototype.bind =
                function (a) {
                    var c = this;
                    if (1 === arguments.length)
                        return function () { return c.apply(a, arguments); };
                    var d = Array.prototype.slice.call(arguments, 1);
                    return function () { var e = d.slice(0); e.push.apply(e, arguments); return c.apply(a, e); };
                });
            a.a.e = new function () {
                function a(b, g) {
                    var h = b[d];
                    if (!h || "null" === h || !e[h]) {
                        if (!g)
                            return n;
                        h = b[d] = "ko" + c++;
                        e[h] = {};
                    }
                    return e[h];
                }
                var c = 0, d = "__ko__" + (new Date).getTime(), e = {};
                return { get: function (c, d) { var e = a(c, !1); return e === n ? n : e[d]; }, set: function (c, d, e) {
                        if (e !== n || a(c, !1) !== n)
                            a(c, !0)[d] =
                                e;
                    }, clear: function (a) { var b = a[d]; return b ? (delete e[b], a[d] = null, !0) : !1; }, I: function () { return c++ + d; } };
            };
            a.b("utils.domData", a.a.e);
            a.b("utils.domData.clear", a.a.e.clear);
            a.a.F = new function () {
                function b(b, c) { var e = a.a.e.get(b, d); e === n && c && (e = [], a.a.e.set(b, d, e)); return e; }
                function c(d) {
                    var e = b(d, !1);
                    if (e)
                        for (var e = e.slice(0), l = 0; l < e.length; l++)
                            e[l](d);
                    a.a.e.clear(d);
                    a.a.F.cleanExternalData(d);
                    if (f[d.nodeType])
                        for (e = d.firstChild; d = e;)
                            e = d.nextSibling, 8 === d.nodeType && c(d);
                }
                var d = a.a.e.I(), e = { 1: !0, 8: !0, 9: !0 }, f = { 1: !0, 9: !0 };
                return { oa: function (a, c) {
                        if ("function" != typeof c)
                            throw Error("Callback must be a function");
                        b(a, !0).push(c);
                    }, rc: function (c, e) { var l = b(c, !1); l && (a.a.La(l, e), 0 == l.length && a.a.e.set(c, d, n)); }, $: function (b) {
                        if (e[b.nodeType] && (c(b), f[b.nodeType])) {
                            var d = [];
                            a.a.ra(d, b.getElementsByTagName("*"));
                            for (var l = 0, m = d.length; l < m; l++)
                                c(d[l]);
                        }
                        return b;
                    }, removeNode: function (b) { a.$(b); b.parentNode && b.parentNode.removeChild(b); }, cleanExternalData: function (a) { u && "function" == typeof u.cleanData && u.cleanData([a]); } };
            };
            a.$ = a.a.F.$;
            a.removeNode = a.a.F.removeNode;
            a.b("cleanNode", a.$);
            a.b("removeNode", a.removeNode);
            a.b("utils.domNodeDisposal", a.a.F);
            a.b("utils.domNodeDisposal.addDisposeCallback", a.a.F.oa);
            a.b("utils.domNodeDisposal.removeDisposeCallback", a.a.F.rc);
            (function () {
                var b = [0, "", ""], c = [1, "<table>", "</table>"], d = [3, "<table><tbody><tr>", "</tr></tbody></table>"], e = [1, "<select multiple='multiple'>", "</select>"], f = { thead: c, tbody: c, tfoot: c, tr: [2, "<table><tbody>", "</tbody></table>"], td: d, th: d, option: e, optgroup: e }, g = 8 >= a.a.C;
                a.a.ma = function (c, d) {
                    var e;
                    if (u)
                        if (u.parseHTML)
                            e = u.parseHTML(c, d) || [];
                        else {
                            if ((e = u.clean([c], d)) && e[0]) {
                                for (var k = e[0]; k.parentNode && 11 !== k.parentNode.nodeType;)
                                    k = k.parentNode;
                                k.parentNode && k.parentNode.removeChild(k);
                            }
                        }
                    else {
                        (e = d) || (e = s);
                        var k = e.parentWindow || e.defaultView || x, r = a.a.$a(c).toLowerCase(), q = e.createElement("div"), p;
                        p = (r = r.match(/^<([a-z]+)[ >]/)) && f[r[1]] || b;
                        r = p[0];
                        p = "ignored<div>" + p[1] + c + p[2] + "</div>";
                        "function" == typeof k.innerShiv ? q.appendChild(k.innerShiv(p)) : (g && e.appendChild(q),
                            q.innerHTML = p, g && q.parentNode.removeChild(q));
                        for (; r--;)
                            q = q.lastChild;
                        e = a.a.V(q.lastChild.childNodes);
                    }
                    return e;
                };
                a.a.Cb = function (b, c) {
                    a.a.ob(b);
                    c = a.a.c(c);
                    if (null !== c && c !== n)
                        if ("string" != typeof c && (c = c.toString()), u)
                            u(b).html(c);
                        else
                            for (var d = a.a.ma(c, b.ownerDocument), e = 0; e < d.length; e++)
                                b.appendChild(d[e]);
                };
            })();
            a.b("utils.parseHtmlFragment", a.a.ma);
            a.b("utils.setHtml", a.a.Cb);
            a.M = function () {
                function b(c, e) {
                    if (c)
                        if (8 == c.nodeType) {
                            var f = a.M.nc(c.nodeValue);
                            null != f && e.push({ Mc: c, dd: f });
                        }
                        else if (1 == c.nodeType)
                            for (var f = 0, g = c.childNodes, h = g.length; f < h; f++)
                                b(g[f], e);
                }
                var c = {};
                return { wb: function (a) {
                        if ("function" != typeof a)
                            throw Error("You can only pass a function to ko.memoization.memoize()");
                        var b = (4294967296 * (1 + Math.random()) | 0).toString(16).substring(1) + (4294967296 * (1 + Math.random()) | 0).toString(16).substring(1);
                        c[b] = a;
                        return "\x3c!--[ko_memo:" + b + "]--\x3e";
                    }, zc: function (a, b) {
                        var f = c[a];
                        if (f === n)
                            throw Error("Couldn't find any memo with ID " + a + ". Perhaps it's already been unmemoized.");
                        try {
                            return f.apply(null, b || []),
                                !0;
                        }
                        finally {
                            delete c[a];
                        }
                    }, Ac: function (c, e) {
                        var f = [];
                        b(c, f);
                        for (var g = 0, h = f.length; g < h; g++) {
                            var l = f[g].Mc, m = [l];
                            e && a.a.ra(m, e);
                            a.M.zc(f[g].dd, m);
                            l.nodeValue = "";
                            l.parentNode && l.parentNode.removeChild(l);
                        }
                    }, nc: function (a) { return (a = a.match(/^\[ko_memo\:(.*?)\]$/)) ? a[1] : null; } };
            }();
            a.b("memoization", a.M);
            a.b("memoization.memoize", a.M.wb);
            a.b("memoization.unmemoize", a.M.zc);
            a.b("memoization.parseMemoText", a.M.nc);
            a.b("memoization.unmemoizeDomNodeAndDescendants", a.M.Ac);
            a.Y = function () {
                function b() {
                    if (e)
                        for (var b = e, c = 0, m; g < e;)
                            if (m = d[g++]) {
                                if (g > b) {
                                    if (5E3 <= ++c) {
                                        g = e;
                                        a.a.bc(Error("'Too much recursion' after processing " + c + " task groups."));
                                        break;
                                    }
                                    b = e;
                                }
                                try {
                                    m();
                                }
                                catch (k) {
                                    a.a.bc(k);
                                }
                            }
                }
                function c() { b(); g = e = d.length = 0; }
                var d = [], e = 0, f = 1, g = 0;
                return { scheduler: x.MutationObserver ? function (a) { var b = s.createElement("div"); (new MutationObserver(a)).observe(b, { attributes: !0 }); return function () { b.classList.toggle("foo"); }; }(c) : s && "onreadystatechange" in s.createElement("script") ? function (a) {
                        var b = s.createElement("script");
                        b.onreadystatechange =
                            function () { b.onreadystatechange = null; s.documentElement.removeChild(b); b = null; a(); };
                        s.documentElement.appendChild(b);
                    } : function (a) { setTimeout(a, 0); }, Wa: function (b) { e || a.Y.scheduler(c); d[e++] = b; return f++; }, cancel: function (a) { a -= f - e; a >= g && a < e && (d[a] = null); }, resetForTesting: function () { var a = e - g; g = e = d.length = 0; return a; }, nd: b };
            }();
            a.b("tasks", a.Y);
            a.b("tasks.schedule", a.Y.Wa);
            a.b("tasks.runEarly", a.Y.nd);
            a.ya = { throttle: function (b, c) {
                    b.throttleEvaluation = c;
                    var d = null;
                    return a.B({ read: b, write: function (e) {
                            clearTimeout(d);
                            d = a.a.setTimeout(function () { b(e); }, c);
                        } });
                }, rateLimit: function (a, c) { var d, e, f; "number" == typeof c ? d = c : (d = c.timeout, e = c.method); a.cb = !1; f = "notifyWhenChangesStop" == e ? T : S; a.Ta(function (a) { return f(a, d); }); }, deferred: function (b, c) {
                    if (!0 !== c)
                        throw Error("The 'deferred' extender only accepts the value 'true', because it is not supported to turn deferral off once enabled.");
                    b.cb || (b.cb = !0, b.Ta(function (c) { var e; return function () { a.Y.cancel(e); e = a.Y.Wa(c); b.notifySubscribers(n, "dirty"); }; }));
                }, notify: function (a, c) {
                    a.equalityComparer =
                        "always" == c ? null : J;
                } };
            var R = { undefined: 1, "boolean": 1, number: 1, string: 1 };
            a.b("extenders", a.ya);
            a.xc = function (b, c, d) { this.ia = b; this.gb = c; this.Lc = d; this.S = !1; a.G(this, "dispose", this.k); };
            a.xc.prototype.k = function () { this.S = !0; this.Lc(); };
            a.J = function () { a.a.Ya(this, D); D.rb(this); };
            var I = "change", D = { rb: function (a) { a.K = {}; a.Ob = 1; }, X: function (b, c, d) { var e = this; d = d || I; var f = new a.xc(e, c ? b.bind(c) : b, function () { a.a.La(e.K[d], f); e.Ia && e.Ia(d); }); e.sa && e.sa(d); e.K[d] || (e.K[d] = []); e.K[d].push(f); return f; }, notifySubscribers: function (b, c) {
                    c = c || I;
                    c === I && this.Ib();
                    if (this.Pa(c))
                        try {
                            a.l.Vb();
                            for (var d = this.K[c].slice(0), e = 0, f; f = d[e]; ++e)
                                f.S || f.gb(b);
                        }
                        finally {
                            a.l.end();
                        }
                }, Na: function () { return this.Ob; }, Vc: function (a) { return this.Na() !== a; }, Ib: function () { ++this.Ob; }, Ta: function (b) { var c = this, d = a.H(c), e, f, g; c.Ha || (c.Ha = c.notifySubscribers, c.notifySubscribers = U); var h = b(function () { c.Nb = !1; d && g === c && (g = c()); e = !1; c.tb(f, g) && c.Ha(f = g); }); c.Mb = function (a) { c.Nb = e = !0; g = a; h(); }; c.Lb = function (a) { e || (f = a, c.Ha(a, "beforeChange")); }; }, Pa: function (a) {
                    return this.K[a] &&
                        this.K[a].length;
                }, Tc: function (b) {
                    if (b)
                        return this.K[b] && this.K[b].length || 0;
                    var c = 0;
                    a.a.D(this.K, function (a, b) { "dirty" !== a && (c += b.length); });
                    return c;
                }, tb: function (a, c) { return !this.equalityComparer || !this.equalityComparer(a, c); }, extend: function (b) { var c = this; b && a.a.D(b, function (b, e) { var f = a.ya[b]; "function" == typeof f && (c = f(c, e) || c); }); return c; } };
            a.G(D, "subscribe", D.X);
            a.G(D, "extend", D.extend);
            a.G(D, "getSubscriptionsCount", D.Tc);
            a.a.ka && a.a.Xa(D, Function.prototype);
            a.J.fn = D;
            a.jc = function (a) {
                return null !=
                    a && "function" == typeof a.X && "function" == typeof a.notifySubscribers;
            };
            a.b("subscribable", a.J);
            a.b("isSubscribable", a.jc);
            a.va = a.l = function () {
                function b(a) { d.push(e); e = a; }
                function c() { e = d.pop(); }
                var d = [], e, f = 0;
                return { Vb: b, end: c, qc: function (b) {
                        if (e) {
                            if (!a.jc(b))
                                throw Error("Only subscribable things can act as dependencies");
                            e.gb.call(e.Hc, b, b.Dc || (b.Dc = ++f));
                        }
                    }, w: function (a, d, e) {
                        try {
                            return b(), a.apply(d, e || []);
                        }
                        finally {
                            c();
                        }
                    }, Aa: function () {
                        if (e)
                            return e.m.Aa();
                    }, Sa: function () {
                        if (e)
                            return e.Sa;
                    } };
            }();
            a.b("computedContext", a.va);
            a.b("computedContext.getDependenciesCount", a.va.Aa);
            a.b("computedContext.isInitial", a.va.Sa);
            a.b("ignoreDependencies", a.rd = a.l.w);
            var E = a.a.$b("_latestValue");
            a.N = function (b) {
                function c() {
                    if (0 < arguments.length)
                        return c.tb(c[E], arguments[0]) && (c.ga(), c[E] = arguments[0], c.fa()), this;
                    a.l.qc(c);
                    return c[E];
                }
                c[E] = b;
                a.a.ka || a.a.extend(c, a.J.fn);
                a.J.fn.rb(c);
                a.a.Ya(c, B);
                a.options.deferUpdates && a.ya.deferred(c, !0);
                return c;
            };
            var B = { equalityComparer: J, t: function () { return this[E]; }, fa: function () { this.notifySubscribers(this[E]); },
                ga: function () { this.notifySubscribers(this[E], "beforeChange"); } };
            a.a.ka && a.a.Xa(B, a.J.fn);
            var H = a.N.hd = "__ko_proto__";
            B[H] = a.N;
            a.Oa = function (b, c) { return null === b || b === n || b[H] === n ? !1 : b[H] === c ? !0 : a.Oa(b[H], c); };
            a.H = function (b) { return a.Oa(b, a.N); };
            a.Ba = function (b) { return "function" == typeof b && b[H] === a.N || "function" == typeof b && b[H] === a.B && b.Wc ? !0 : !1; };
            a.b("observable", a.N);
            a.b("isObservable", a.H);
            a.b("isWriteableObservable", a.Ba);
            a.b("isWritableObservable", a.Ba);
            a.b("observable.fn", B);
            a.G(B, "peek", B.t);
            a.G(B, "valueHasMutated", B.fa);
            a.G(B, "valueWillMutate", B.ga);
            a.la = function (b) {
                b = b || [];
                if ("object" != typeof b || !("length" in b))
                    throw Error("The argument passed when initializing an observable array must be an array, or null, or undefined.");
                b = a.N(b);
                a.a.Ya(b, a.la.fn);
                return b.extend({ trackArrayChanges: !0 });
            };
            a.la.fn = { remove: function (b) {
                    for (var c = this.t(), d = [], e = "function" != typeof b || a.H(b) ? function (a) { return a === b; } : b, f = 0; f < c.length; f++) {
                        var g = c[f];
                        e(g) && (0 === d.length && this.ga(), d.push(g), c.splice(f, 1), f--);
                    }
                    d.length &&
                        this.fa();
                    return d;
                }, removeAll: function (b) {
                    if (b === n) {
                        var c = this.t(), d = c.slice(0);
                        this.ga();
                        c.splice(0, c.length);
                        this.fa();
                        return d;
                    }
                    return b ? this.remove(function (c) { return 0 <= a.a.o(b, c); }) : [];
                }, destroy: function (b) {
                    var c = this.t(), d = "function" != typeof b || a.H(b) ? function (a) { return a === b; } : b;
                    this.ga();
                    for (var e = c.length - 1; 0 <= e; e--)
                        d(c[e]) && (c[e]._destroy = !0);
                    this.fa();
                }, destroyAll: function (b) { return b === n ? this.destroy(function () { return !0; }) : b ? this.destroy(function (c) { return 0 <= a.a.o(b, c); }) : []; }, indexOf: function (b) {
                    var c = this();
                    return a.a.o(c, b);
                }, replace: function (a, c) { var d = this.indexOf(a); 0 <= d && (this.ga(), this.t()[d] = c, this.fa()); } };
            a.a.ka && a.a.Xa(a.la.fn, a.N.fn);
            a.a.q("pop push reverse shift sort splice unshift".split(" "), function (b) { a.la.fn[b] = function () { var a = this.t(); this.ga(); this.Wb(a, b, arguments); var d = a[b].apply(a, arguments); this.fa(); return d === a ? this : d; }; });
            a.a.q(["slice"], function (b) { a.la.fn[b] = function () { var a = this(); return a[b].apply(a, arguments); }; });
            a.b("observableArray", a.la);
            a.ya.trackArrayChanges = function (b, c) {
                function d() {
                    if (!e) {
                        e = !0;
                        l = b.notifySubscribers;
                        b.notifySubscribers = function (a, b) { b && b !== I || ++h; return l.apply(this, arguments); };
                        var c = [].concat(b.t() || []);
                        f = null;
                        g = b.X(function (d) {
                            d = [].concat(d || []);
                            if (b.Pa("arrayChange")) {
                                var e;
                                if (!f || 1 < h)
                                    f = a.a.ib(c, d, b.hb);
                                e = f;
                            }
                            c = d;
                            f = null;
                            h = 0;
                            e && e.length && b.notifySubscribers(e, "arrayChange");
                        });
                    }
                }
                b.hb = {};
                c && "object" == typeof c && a.a.extend(b.hb, c);
                b.hb.sparse = !0;
                if (!b.Wb) {
                    var e = !1, f = null, g, h = 0, l, m = b.sa, k = b.Ia;
                    b.sa = function (a) { m && m.call(b, a); "arrayChange" === a && d(); };
                    b.Ia = function (a) { k && k.call(b, a); "arrayChange" !== a || b.Pa("arrayChange") || (l && (b.notifySubscribers = l, l = n), g.k(), e = !1); };
                    b.Wb = function (b, c, d) {
                        function k(a, b, c) { return m[m.length] = { status: a, value: b, index: c }; }
                        if (e && !h) {
                            var m = [], l = b.length, g = d.length, G = 0;
                            switch (c) {
                                case "push": G = l;
                                case "unshift":
                                    for (c = 0; c < g; c++)
                                        k("added", d[c], G + c);
                                    break;
                                case "pop": G = l - 1;
                                case "shift":
                                    l && k("deleted", b[G], G);
                                    break;
                                case "splice":
                                    c = Math.min(Math.max(0, 0 > d[0] ? l + d[0] : d[0]), l);
                                    for (var l = 1 === g ? l : Math.min(c + (d[1] || 0), l), g = c + g - 2, G = Math.max(l, g), n = [], s = [], w = 2; c < G; ++c, ++w)
                                        c < l && s.push(k("deleted", b[c], c)), c < g && n.push(k("added", d[w], c));
                                    a.a.fc(s, n);
                                    break;
                                default: return;
                            }
                            f = m;
                        }
                    };
                }
            };
            var t = a.a.$b("_state");
            a.m = a.B = function (b, c, d) {
                function e() {
                    if (0 < arguments.length) {
                        if ("function" === typeof f)
                            f.apply(g.pb, arguments);
                        else
                            throw Error("Cannot write a value to a ko.computed unless you specify a 'write' option. If you wish to read the current value, don't pass any parameters.");
                        return this;
                    }
                    a.l.qc(e);
                    (g.T || g.s && e.Qa()) && e.aa();
                    return g.U;
                }
                "object" === typeof b ?
                    d = b : (d = d || {}, b && (d.read = b));
                if ("function" != typeof d.read)
                    throw Error("Pass a function that returns the value of the ko.computed");
                var f = d.write, g = { U: n, T: !0, Ra: !1, Fb: !1, S: !1, Va: !1, s: !1, kd: d.read, pb: c || d.owner, i: d.disposeWhenNodeIsRemoved || d.i || null, wa: d.disposeWhen || d.wa, mb: null, r: {}, L: 0, dc: null };
                e[t] = g;
                e.Wc = "function" === typeof f;
                a.a.ka || a.a.extend(e, a.J.fn);
                a.J.fn.rb(e);
                a.a.Ya(e, z);
                d.pure ? (g.Va = !0, g.s = !0, a.a.extend(e, Y)) : d.deferEvaluation && a.a.extend(e, Z);
                a.options.deferUpdates && a.ya.deferred(e, !0);
                g.i && (g.Fb = !0, g.i.nodeType || (g.i = null));
                g.s || d.deferEvaluation || e.aa();
                g.i && e.ba() && a.a.F.oa(g.i, g.mb = function () { e.k(); });
                return e;
            };
            var z = { equalityComparer: J, Aa: function () { return this[t].L; }, Qb: function (a, c, d) {
                    if (this[t].Va && c === this)
                        throw Error("A 'pure' computed must not be called recursively");
                    this[t].r[a] = d;
                    d.Ga = this[t].L++;
                    d.na = c.Na();
                }, Qa: function () {
                    var a, c, d = this[t].r;
                    for (a in d)
                        if (d.hasOwnProperty(a) && (c = d[a], c.ia.Vc(c.na)))
                            return !0;
                }, cd: function () { this.Fa && !this[t].Ra && this.Fa(); }, ba: function () {
                    return this[t].T ||
                        0 < this[t].L;
                }, md: function () { this.Nb || this.cc(); }, wc: function (a) {
                    if (a.cb && !this[t].i) {
                        var c = a.X(this.cd, this, "dirty"), d = a.X(this.md, this);
                        return { ia: a, k: function () { c.k(); d.k(); } };
                    }
                    return a.X(this.cc, this);
                }, cc: function () { var b = this, c = b.throttleEvaluation; c && 0 <= c ? (clearTimeout(this[t].dc), this[t].dc = a.a.setTimeout(function () { b.aa(!0); }, c)) : b.Fa ? b.Fa() : b.aa(!0); }, aa: function (b) {
                    var c = this[t], d = c.wa, e = !1;
                    if (!c.Ra && !c.S) {
                        if (c.i && !a.a.nb(c.i) || d && d()) {
                            if (!c.Fb) {
                                this.k();
                                return;
                            }
                        }
                        else
                            c.Fb = !1;
                        c.Ra = !0;
                        try {
                            e = this.Rc(b);
                        }
                        finally {
                            c.Ra =
                                !1;
                        }
                        c.L || this.k();
                        return e;
                    }
                }, Rc: function (b) { var c = this[t], d = !1, e = c.Va ? n : !c.L, f = { Ic: this, Ma: c.r, lb: c.L }; a.l.Vb({ Hc: f, gb: W, m: this, Sa: e }); c.r = {}; c.L = 0; f = this.Qc(c, f); this.tb(c.U, f) && (c.s || this.notifySubscribers(c.U, "beforeChange"), c.U = f, c.s ? this.Ib() : b && this.notifySubscribers(c.U), d = !0); e && this.notifySubscribers(c.U, "awake"); return d; }, Qc: function (b, c) {
                    try {
                        var d = b.kd;
                        return b.pb ? d.call(b.pb) : d();
                    }
                    finally {
                        a.l.end(), c.lb && !b.s && a.a.D(c.Ma, V), b.T = !1;
                    }
                }, t: function () {
                    var a = this[t];
                    (a.T && !a.L || a.s && this.Qa()) &&
                        this.aa();
                    return a.U;
                }, Ta: function (b) { a.J.fn.Ta.call(this, b); this.Fa = function () { this.Lb(this[t].U); this[t].T = !0; this.Mb(this); }; }, k: function () { var b = this[t]; !b.s && b.r && a.a.D(b.r, function (a, b) { b.k && b.k(); }); b.i && b.mb && a.a.F.rc(b.i, b.mb); b.r = null; b.L = 0; b.S = !0; b.T = !1; b.s = !1; b.i = null; } }, Y = { sa: function (b) {
                    var c = this, d = c[t];
                    if (!d.S && d.s && "change" == b) {
                        d.s = !1;
                        if (d.T || c.Qa())
                            d.r = null, d.L = 0, d.T = !0, c.aa() && c.Ib();
                        else {
                            var e = [];
                            a.a.D(d.r, function (a, b) { e[b.Ga] = a; });
                            a.a.q(e, function (a, b) {
                                var e = d.r[a], l = c.wc(e.ia);
                                l.Ga =
                                    b;
                                l.na = e.na;
                                d.r[a] = l;
                            });
                        }
                        d.S || c.notifySubscribers(d.U, "awake");
                    }
                }, Ia: function (b) { var c = this[t]; c.S || "change" != b || this.Pa("change") || (a.a.D(c.r, function (a, b) { b.k && (c.r[a] = { ia: b.ia, Ga: b.Ga, na: b.na }, b.k()); }), c.s = !0, this.notifySubscribers(n, "asleep")); }, Na: function () { var b = this[t]; b.s && (b.T || this.Qa()) && this.aa(); return a.J.fn.Na.call(this); } }, Z = { sa: function (a) { "change" != a && "beforeChange" != a || this.t(); } };
            a.a.ka && a.a.Xa(z, a.J.fn);
            var P = a.N.hd;
            a.m[P] = a.N;
            z[P] = a.m;
            a.Yc = function (b) { return a.Oa(b, a.m); };
            a.Zc = function (b) {
                return a.Oa(b, a.m) && b[t] && b[t].Va;
            };
            a.b("computed", a.m);
            a.b("dependentObservable", a.m);
            a.b("isComputed", a.Yc);
            a.b("isPureComputed", a.Zc);
            a.b("computed.fn", z);
            a.G(z, "peek", z.t);
            a.G(z, "dispose", z.k);
            a.G(z, "isActive", z.ba);
            a.G(z, "getDependenciesCount", z.Aa);
            a.pc = function (b, c) {
                if ("function" === typeof b)
                    return a.m(b, c, { pure: !0 });
                b = a.a.extend({}, b);
                b.pure = !0;
                return a.m(b, c);
            };
            a.b("pureComputed", a.pc);
            (function () {
                function b(a, f, g) {
                    g = g || new d;
                    a = f(a);
                    if ("object" != typeof a || null === a || a === n || a instanceof RegExp || a instanceof
                        Date || a instanceof String || a instanceof Number || a instanceof Boolean)
                        return a;
                    var h = a instanceof Array ? [] : {};
                    g.save(a, h);
                    c(a, function (c) {
                        var d = f(a[c]);
                        switch (typeof d) {
                            case "boolean":
                            case "number":
                            case "string":
                            case "function":
                                h[c] = d;
                                break;
                            case "object":
                            case "undefined":
                                var k = g.get(d);
                                h[c] = k !== n ? k : b(d, f, g);
                        }
                    });
                    return h;
                }
                function c(a, b) {
                    if (a instanceof Array) {
                        for (var c = 0; c < a.length; c++)
                            b(c);
                        "function" == typeof a.toJSON && b("toJSON");
                    }
                    else
                        for (c in a)
                            b(c);
                }
                function d() { this.keys = []; this.Jb = []; }
                a.yc = function (c) {
                    if (0 ==
                        arguments.length)
                        throw Error("When calling ko.toJS, pass the object you want to convert.");
                    return b(c, function (b) {
                        for (var c = 0; a.H(b) && 10 > c; c++)
                            b = b();
                        return b;
                    });
                };
                a.toJSON = function (b, c, d) { b = a.yc(b); return a.a.Eb(b, c, d); };
                d.prototype = { save: function (b, c) { var d = a.a.o(this.keys, b); 0 <= d ? this.Jb[d] = c : (this.keys.push(b), this.Jb.push(c)); }, get: function (b) { b = a.a.o(this.keys, b); return 0 <= b ? this.Jb[b] : n; } };
            })();
            a.b("toJS", a.yc);
            a.b("toJSON", a.toJSON);
            (function () {
                a.j = { u: function (b) {
                        switch (a.a.A(b)) {
                            case "option": return !0 ===
                                b.__ko__hasDomDataOptionValue__ ? a.a.e.get(b, a.d.options.xb) : 7 >= a.a.C ? b.getAttributeNode("value") && b.getAttributeNode("value").specified ? b.value : b.text : b.value;
                            case "select": return 0 <= b.selectedIndex ? a.j.u(b.options[b.selectedIndex]) : n;
                            default: return b.value;
                        }
                    }, ha: function (b, c, d) {
                        switch (a.a.A(b)) {
                            case "option":
                                switch (typeof c) {
                                    case "string":
                                        a.a.e.set(b, a.d.options.xb, n);
                                        "__ko__hasDomDataOptionValue__" in b && delete b.__ko__hasDomDataOptionValue__;
                                        b.value = c;
                                        break;
                                    default: a.a.e.set(b, a.d.options.xb, c),
                                        b.__ko__hasDomDataOptionValue__ = !0, b.value = "number" === typeof c ? c : "";
                                }
                                break;
                            case "select":
                                if ("" === c || null === c)
                                    c = n;
                                for (var e = -1, f = 0, g = b.options.length, h; f < g; ++f)
                                    if (h = a.j.u(b.options[f]), h == c || "" == h && c === n) {
                                        e = f;
                                        break;
                                    }
                                if (d || 0 <= e || c === n && 1 < b.size)
                                    b.selectedIndex = e;
                                break;
                            default:
                                if (null === c || c === n)
                                    c = "";
                                b.value = c;
                        }
                    } };
            })();
            a.b("selectExtensions", a.j);
            a.b("selectExtensions.readValue", a.j.u);
            a.b("selectExtensions.writeValue", a.j.ha);
            a.h = function () {
                function b(b) {
                    b = a.a.$a(b);
                    123 === b.charCodeAt(0) && (b = b.slice(1, -1));
                    var c = [], d = b.match(e), r, h = [], p = 0;
                    if (d) {
                        d.push(",");
                        for (var A = 0, y; y = d[A]; ++A) {
                            var v = y.charCodeAt(0);
                            if (44 === v) {
                                if (0 >= p) {
                                    c.push(r && h.length ? { key: r, value: h.join("") } : { unknown: r || h.join("") });
                                    r = p = 0;
                                    h = [];
                                    continue;
                                }
                            }
                            else if (58 === v) {
                                if (!p && !r && 1 === h.length) {
                                    r = h.pop();
                                    continue;
                                }
                            }
                            else
                                47 === v && A && 1 < y.length ? (v = d[A - 1].match(f)) && !g[v[0]] && (b = b.substr(b.indexOf(y) + 1), d = b.match(e), d.push(","), A = -1, y = "/") : 40 === v || 123 === v || 91 === v ? ++p : 41 === v || 125 === v || 93 === v ? --p : r || h.length || 34 !== v && 39 !== v || (y = y.slice(1, -1));
                            h.push(y);
                        }
                    }
                    return c;
                }
                var c = ["true", "false", "null", "undefined"], d = /^(?:[$_a-z][$\w]*|(.+)(\.\s*[$_a-z][$\w]*|\[.+\]))$/i, e = RegExp("\"(?:[^\"\\\\]|\\\\.)*\"|'(?:[^'\\\\]|\\\\.)*'|/(?:[^/\\\\]|\\\\.)*/w*|[^\\s:,/][^,\"'{}()/:[\\]]*[^\\s,\"'{}()/:[\\]]|[^\\s]", "g"), f = /[\])"'A-Za-z0-9_$]+$/, g = { "in": 1, "return": 1, "typeof": 1 }, h = {};
                return { ta: [], ea: h, yb: b, Ua: function (e, m) {
                        function k(b, e) {
                            var m;
                            if (!A) {
                                var l = a.getBindingHandler(b);
                                if (l && l.preprocess && !(e = l.preprocess(e, b, k)))
                                    return;
                                if (l = h[b])
                                    m = e, 0 <= a.a.o(c, m) ?
                                        m = !1 : (l = m.match(d), m = null === l ? !1 : l[1] ? "Object(" + l[1] + ")" + l[2] : m), l = m;
                                l && g.push("'" + b + "':function(_z){" + m + "=_z}");
                            }
                            p && (e = "function(){return " + e + " }");
                            f.push("'" + b + "':" + e);
                        }
                        m = m || {};
                        var f = [], g = [], p = m.valueAccessors, A = m.bindingParams, y = "string" === typeof e ? b(e) : e;
                        a.a.q(y, function (a) { k(a.key || a.unknown, a.value); });
                        g.length && k("_ko_property_writers", "{" + g.join(",") + " }");
                        return f.join(",");
                    }, bd: function (a, b) {
                        for (var c = 0; c < a.length; c++)
                            if (a[c].key == b)
                                return !0;
                        return !1;
                    }, Ea: function (b, c, d, e, f) {
                        if (b && a.H(b))
                            !a.Ba(b) ||
                                f && b.t() === e || b(e);
                        else if ((b = c.get("_ko_property_writers")) && b[d])
                            b[d](e);
                    } };
            }();
            a.b("expressionRewriting", a.h);
            a.b("expressionRewriting.bindingRewriteValidators", a.h.ta);
            a.b("expressionRewriting.parseObjectLiteral", a.h.yb);
            a.b("expressionRewriting.preProcessBindings", a.h.Ua);
            a.b("expressionRewriting._twoWayBindings", a.h.ea);
            a.b("jsonExpressionRewriting", a.h);
            a.b("jsonExpressionRewriting.insertPropertyAccessorsIntoJson", a.h.Ua);
            (function () {
                function b(a) { return 8 == a.nodeType && g.test(f ? a.text : a.nodeValue); }
                function c(a) { return 8 == a.nodeType && h.test(f ? a.text : a.nodeValue); }
                function d(a, d) {
                    for (var e = a, f = 1, l = []; e = e.nextSibling;) {
                        if (c(e) && (f--, 0 === f))
                            return l;
                        l.push(e);
                        b(e) && f++;
                    }
                    if (!d)
                        throw Error("Cannot find closing comment tag to match: " + a.nodeValue);
                    return null;
                }
                function e(a, b) { var c = d(a, b); return c ? 0 < c.length ? c[c.length - 1].nextSibling : a.nextSibling : null; }
                var f = s && "\x3c!--test--\x3e" === s.createComment("test").text, g = f ? /^\x3c!--\s*ko(?:\s+([\s\S]+))?\s*--\x3e$/ : /^\s*ko(?:\s+([\s\S]+))?\s*$/, h = f ? /^\x3c!--\s*\/ko\s*--\x3e$/ :
                    /^\s*\/ko\s*$/, l = { ul: !0, ol: !0 };
                a.f = { Z: {}, childNodes: function (a) { return b(a) ? d(a) : a.childNodes; }, xa: function (c) {
                        if (b(c)) {
                            c = a.f.childNodes(c);
                            for (var d = 0, e = c.length; d < e; d++)
                                a.removeNode(c[d]);
                        }
                        else
                            a.a.ob(c);
                    }, da: function (c, d) {
                        if (b(c)) {
                            a.f.xa(c);
                            for (var e = c.nextSibling, f = 0, l = d.length; f < l; f++)
                                e.parentNode.insertBefore(d[f], e);
                        }
                        else
                            a.a.da(c, d);
                    }, oc: function (a, c) { b(a) ? a.parentNode.insertBefore(c, a.nextSibling) : a.firstChild ? a.insertBefore(c, a.firstChild) : a.appendChild(c); }, ic: function (c, d, e) {
                        e ? b(c) ? c.parentNode.insertBefore(d, e.nextSibling) : e.nextSibling ? c.insertBefore(d, e.nextSibling) : c.appendChild(d) : a.f.oc(c, d);
                    }, firstChild: function (a) { return b(a) ? !a.nextSibling || c(a.nextSibling) ? null : a.nextSibling : a.firstChild; }, nextSibling: function (a) { b(a) && (a = e(a)); return a.nextSibling && c(a.nextSibling) ? null : a.nextSibling; }, Uc: b, qd: function (a) { return (a = (f ? a.text : a.nodeValue).match(g)) ? a[1] : null; }, mc: function (d) {
                        if (l[a.a.A(d)]) {
                            var k = d.firstChild;
                            if (k) {
                                do
                                    if (1 === k.nodeType) {
                                        var f;
                                        f = k.firstChild;
                                        var g = null;
                                        if (f) {
                                            do
                                                if (g)
                                                    g.push(f);
                                                else if (b(f)) {
                                                    var h = e(f, !0);
                                                    h ? f = h : g = [f];
                                                }
                                                else
                                                    c(f) && (g = [f]);
                                            while (f = f.nextSibling);
                                        }
                                        if (f = g)
                                            for (g = k.nextSibling, h = 0; h < f.length; h++)
                                                g ? d.insertBefore(f[h], g) : d.appendChild(f[h]);
                                    }
                                while (k = k.nextSibling);
                            }
                        }
                    } };
            })();
            a.b("virtualElements", a.f);
            a.b("virtualElements.allowedBindings", a.f.Z);
            a.b("virtualElements.emptyNode", a.f.xa);
            a.b("virtualElements.insertAfter", a.f.ic);
            a.b("virtualElements.prepend", a.f.oc);
            a.b("virtualElements.setDomNodeChildren", a.f.da);
            (function () {
                a.R = function () { this.Gc = {}; };
                a.a.extend(a.R.prototype, { nodeHasBindings: function (b) {
                        switch (b.nodeType) {
                            case 1: return null !=
                                b.getAttribute("data-bind") || a.g.getComponentNameForNode(b);
                            case 8: return a.f.Uc(b);
                            default: return !1;
                        }
                    }, getBindings: function (b, c) { var d = this.getBindingsString(b, c), d = d ? this.parseBindingsString(d, c, b) : null; return a.g.Pb(d, b, c, !1); }, getBindingAccessors: function (b, c) { var d = this.getBindingsString(b, c), d = d ? this.parseBindingsString(d, c, b, { valueAccessors: !0 }) : null; return a.g.Pb(d, b, c, !0); }, getBindingsString: function (b) {
                        switch (b.nodeType) {
                            case 1: return b.getAttribute("data-bind");
                            case 8: return a.f.qd(b);
                            default: return null;
                        }
                    },
                    parseBindingsString: function (b, c, d, e) {
                        try {
                            var f = this.Gc, g = b + (e && e.valueAccessors || ""), h;
                            if (!(h = f[g])) {
                                var l, m = "with($context){with($data||{}){return{" + a.h.Ua(b, e) + "}}}";
                                l = new Function("$context", "$element", m);
                                h = f[g] = l;
                            }
                            return h(c, d);
                        }
                        catch (k) {
                            throw k.message = "Unable to parse bindings.\nBindings value: " + b + "\nMessage: " + k.message, k;
                        }
                    } });
                a.R.instance = new a.R;
            })();
            a.b("bindingProvider", a.R);
            (function () {
                function b(a) { return function () { return a; }; }
                function c(a) { return a(); }
                function d(b) {
                    return a.a.Ca(a.l.w(b), function (a, c) { return function () { return b()[c]; }; });
                }
                function e(c, e, k) { return "function" === typeof c ? d(c.bind(null, e, k)) : a.a.Ca(c, b); }
                function f(a, b) { return d(this.getBindings.bind(this, a, b)); }
                function g(b, c, d) {
                    var e, k = a.f.firstChild(c), f = a.R.instance, m = f.preprocessNode;
                    if (m) {
                        for (; e = k;)
                            k = a.f.nextSibling(e), m.call(f, e);
                        k = a.f.firstChild(c);
                    }
                    for (; e = k;)
                        k = a.f.nextSibling(e), h(b, e, d);
                }
                function h(b, c, d) {
                    var e = !0, k = 1 === c.nodeType;
                    k && a.f.mc(c);
                    if (k && d || a.R.instance.nodeHasBindings(c))
                        e = m(c, null, b, d).shouldBindDescendants;
                    e && !r[a.a.A(c)] && g(b, c, !k);
                }
                function l(b) {
                    var c = [], d = {}, e = [];
                    a.a.D(b, function X(k) {
                        if (!d[k]) {
                            var f = a.getBindingHandler(k);
                            f && (f.after && (e.push(k), a.a.q(f.after, function (c) {
                                if (b[c]) {
                                    if (-1 !== a.a.o(e, c))
                                        throw Error("Cannot combine the following bindings, because they have a cyclic dependency: " + e.join(", "));
                                    X(c);
                                }
                            }), e.length--), c.push({ key: k, hc: f }));
                            d[k] = !0;
                        }
                    });
                    return c;
                }
                function m(b, d, e, k) {
                    var m = a.a.e.get(b, q);
                    if (!d) {
                        if (m)
                            throw Error("You cannot apply bindings multiple times to the same element.");
                        a.a.e.set(b, q, !0);
                    }
                    !m && k && a.vc(b, e);
                    var g;
                    if (d && "function" !== typeof d)
                        g = d;
                    else {
                        var h = a.R.instance, r = h.getBindingAccessors || f, p = a.B(function () { (g = d ? d(e, b) : r.call(h, b, e)) && e.P && e.P(); return g; }, null, { i: b });
                        g && p.ba() || (p = null);
                    }
                    var s;
                    if (g) {
                        var u = p ? function (a) { return function () { return c(p()[a]); }; } : function (a) { return g[a]; }, t = function () { return a.a.Ca(p ? p() : g, c); };
                        t.get = function (a) { return g[a] && c(u(a)); };
                        t.has = function (a) { return a in g; };
                        k = l(g);
                        a.a.q(k, function (c) {
                            var d = c.hc.init, k = c.hc.update, f = c.key;
                            if (8 === b.nodeType && !a.f.Z[f])
                                throw Error("The binding '" +
                                    f + "' cannot be used with virtual elements");
                            try {
                                "function" == typeof d && a.l.w(function () {
                                    var a = d(b, u(f), t, e.$data, e);
                                    if (a && a.controlsDescendantBindings) {
                                        if (s !== n)
                                            throw Error("Multiple bindings (" + s + " and " + f + ") are trying to control descendant bindings of the same element. You cannot use these bindings together on the same element.");
                                        s = f;
                                    }
                                }), "function" == typeof k && a.B(function () { k(b, u(f), t, e.$data, e); }, null, { i: b });
                            }
                            catch (m) {
                                throw m.message = 'Unable to process binding "' + f + ": " + g[f] + '"\nMessage: ' + m.message,
                                    m;
                            }
                        });
                    }
                    return { shouldBindDescendants: s === n };
                }
                function k(b) { return b && b instanceof a.Q ? b : new a.Q(b); }
                a.d = {};
                var r = { script: !0, textarea: !0, template: !0 };
                a.getBindingHandler = function (b) { return a.d[b]; };
                a.Q = function (b, c, d, e, k) {
                    function f() { var k = g ? b() : b, m = a.a.c(k); c ? (c.P && c.P(), a.a.extend(l, c), l.P = r) : (l.$parents = [], l.$root = m, l.ko = a); l.$rawData = k; l.$data = m; d && (l[d] = m); e && e(l, c, m); return l.$data; }
                    function m() { return h && !a.a.Rb(h); }
                    var l = this, g = "function" == typeof b && !a.H(b), h, r;
                    k && k.exportDependencies ? f() : (r = a.B(f, null, { wa: m, i: !0 }), r.ba() && (l.P = r, r.equalityComparer = null, h = [], r.Bc = function (b) { h.push(b); a.a.F.oa(b, function (b) { a.a.La(h, b); h.length || (r.k(), l.P = r = n); }); }));
                };
                a.Q.prototype.createChildContext = function (b, c, d, e) { return new a.Q(b, this, c, function (a, b) { a.$parentContext = b; a.$parent = b.$data; a.$parents = (b.$parents || []).slice(0); a.$parents.unshift(a.$parent); d && d(a); }, e); };
                a.Q.prototype.extend = function (b) {
                    return new a.Q(this.P || this.$data, this, null, function (c, d) {
                        c.$rawData = d.$rawData;
                        a.a.extend(c, "function" == typeof b ?
                            b() : b);
                    });
                };
                a.Q.prototype.Zb = function (a, b) { return this.createChildContext(a, b, null, { exportDependencies: !0 }); };
                var q = a.a.e.I(), p = a.a.e.I();
                a.vc = function (b, c) {
                    if (2 == arguments.length)
                        a.a.e.set(b, p, c), c.P && c.P.Bc(b);
                    else
                        return a.a.e.get(b, p);
                };
                a.Ja = function (b, c, d) { 1 === b.nodeType && a.f.mc(b); return m(b, c, k(d), !0); };
                a.Ec = function (b, c, d) { d = k(d); return a.Ja(b, e(c, d, b), d); };
                a.eb = function (a, b) { 1 !== b.nodeType && 8 !== b.nodeType || g(k(a), b, !0); };
                a.Sb = function (a, b) {
                    !u && x.jQuery && (u = x.jQuery);
                    if (b && 1 !== b.nodeType && 8 !== b.nodeType)
                        throw Error("ko.applyBindings: first parameter should be your view model; second parameter should be a DOM node");
                    b = b || x.document.body;
                    h(k(a), b, !0);
                };
                a.kb = function (b) {
                    switch (b.nodeType) {
                        case 1:
                        case 8:
                            var c = a.vc(b);
                            if (c)
                                return c;
                            if (b.parentNode)
                                return a.kb(b.parentNode);
                    }
                    return n;
                };
                a.Kc = function (b) { return (b = a.kb(b)) ? b.$data : n; };
                a.b("bindingHandlers", a.d);
                a.b("applyBindings", a.Sb);
                a.b("applyBindingsToDescendants", a.eb);
                a.b("applyBindingAccessorsToNode", a.Ja);
                a.b("applyBindingsToNode", a.Ec);
                a.b("contextFor", a.kb);
                a.b("dataFor", a.Kc);
            })();
            (function (b) {
                function c(c, e) {
                    var m = f.hasOwnProperty(c) ? f[c] : b, k;
                    m ? m.X(e) : (m = f[c] =
                        new a.J, m.X(e), d(c, function (b, d) { var e = !(!d || !d.synchronous); g[c] = { definition: b, $c: e }; delete f[c]; k || e ? m.notifySubscribers(b) : a.Y.Wa(function () { m.notifySubscribers(b); }); }), k = !0);
                }
                function d(a, b) { e("getConfig", [a], function (c) { c ? e("loadComponent", [a, c], function (a) { b(a, c); }) : b(null, null); }); }
                function e(c, d, f, k) {
                    k || (k = a.g.loaders.slice(0));
                    var g = k.shift();
                    if (g) {
                        var q = g[c];
                        if (q) {
                            var p = !1;
                            if (q.apply(g, d.concat(function (a) { p ? f(null) : null !== a ? f(a) : e(c, d, f, k); })) !== b && (p = !0, !g.suppressLoaderExceptions))
                                throw Error("Component loaders must supply values by invoking the callback, not by returning values synchronously.");
                        }
                        else
                            e(c, d, f, k);
                    }
                    else
                        f(null);
                }
                var f = {}, g = {};
                a.g = { get: function (d, e) { var f = g.hasOwnProperty(d) ? g[d] : b; f ? f.$c ? a.l.w(function () { e(f.definition); }) : a.Y.Wa(function () { e(f.definition); }) : c(d, e); }, Yb: function (a) { delete g[a]; }, Kb: e };
                a.g.loaders = [];
                a.b("components", a.g);
                a.b("components.get", a.g.get);
                a.b("components.clearCachedDefinition", a.g.Yb);
            })();
            (function () {
                function b(b, c, d, e) {
                    function g() { 0 === --y && e(h); }
                    var h = {}, y = 2, v = d.template;
                    d = d.viewModel;
                    v ? f(c, v, function (c) {
                        a.g.Kb("loadTemplate", [b, c], function (a) {
                            h.template =
                                a;
                            g();
                        });
                    }) : g();
                    d ? f(c, d, function (c) { a.g.Kb("loadViewModel", [b, c], function (a) { h[l] = a; g(); }); }) : g();
                }
                function c(a, b, d) {
                    if ("function" === typeof b)
                        d(function (a) { return new b(a); });
                    else if ("function" === typeof b[l])
                        d(b[l]);
                    else if ("instance" in b) {
                        var e = b.instance;
                        d(function () { return e; });
                    }
                    else
                        "viewModel" in b ? c(a, b.viewModel, d) : a("Unknown viewModel value: " + b);
                }
                function d(b) {
                    switch (a.a.A(b)) {
                        case "script": return a.a.ma(b.text);
                        case "textarea": return a.a.ma(b.value);
                        case "template": if (e(b.content))
                            return a.a.ua(b.content.childNodes);
                    }
                    return a.a.ua(b.childNodes);
                }
                function e(a) { return x.DocumentFragment ? a instanceof DocumentFragment : a && 11 === a.nodeType; }
                function f(a, b, c) { "string" === typeof b.require ? O || x.require ? (O || x.require)([b.require], c) : a("Uses require, but no AMD loader is present") : c(b); }
                function g(a) { return function (b) { throw Error("Component '" + a + "': " + b); }; }
                var h = {};
                a.g.register = function (b, c) {
                    if (!c)
                        throw Error("Invalid configuration for " + b);
                    if (a.g.ub(b))
                        throw Error("Component " + b + " is already registered");
                    h[b] = c;
                };
                a.g.ub = function (a) { return h.hasOwnProperty(a); };
                a.g.pd = function (b) { delete h[b]; a.g.Yb(b); };
                a.g.ac = { getConfig: function (a, b) { b(h.hasOwnProperty(a) ? h[a] : null); }, loadComponent: function (a, c, d) { var e = g(a); f(e, c, function (c) { b(a, e, c, d); }); }, loadTemplate: function (b, c, f) {
                        b = g(b);
                        if ("string" === typeof c)
                            f(a.a.ma(c));
                        else if (c instanceof Array)
                            f(c);
                        else if (e(c))
                            f(a.a.V(c.childNodes));
                        else if (c.element)
                            if (c = c.element, x.HTMLElement ? c instanceof HTMLElement : c && c.tagName && 1 === c.nodeType)
                                f(d(c));
                            else if ("string" === typeof c) {
                                var l = s.getElementById(c);
                                l ? f(d(l)) : b("Cannot find element with ID " +
                                    c);
                            }
                            else
                                b("Unknown element type: " + c);
                        else
                            b("Unknown template value: " + c);
                    }, loadViewModel: function (a, b, d) { c(g(a), b, d); } };
                var l = "createViewModel";
                a.b("components.register", a.g.register);
                a.b("components.isRegistered", a.g.ub);
                a.b("components.unregister", a.g.pd);
                a.b("components.defaultLoader", a.g.ac);
                a.g.loaders.push(a.g.ac);
                a.g.Cc = h;
            })();
            (function () {
                function b(b, e) {
                    var f = b.getAttribute("params");
                    if (f) {
                        var f = c.parseBindingsString(f, e, b, { valueAccessors: !0, bindingParams: !0 }), f = a.a.Ca(f, function (c) {
                            return a.m(c, null, { i: b });
                        }), g = a.a.Ca(f, function (c) { var e = c.t(); return c.ba() ? a.m({ read: function () { return a.a.c(c()); }, write: a.Ba(e) && function (a) { c()(a); }, i: b }) : e; });
                        g.hasOwnProperty("$raw") || (g.$raw = f);
                        return g;
                    }
                    return { $raw: {} };
                }
                a.g.getComponentNameForNode = function (b) {
                    var c = a.a.A(b);
                    if (a.g.ub(c) && (-1 != c.indexOf("-") || "[object HTMLUnknownElement]" == "" + b || 8 >= a.a.C && b.tagName === c))
                        return c;
                };
                a.g.Pb = function (c, e, f, g) {
                    if (1 === e.nodeType) {
                        var h = a.g.getComponentNameForNode(e);
                        if (h) {
                            c = c || {};
                            if (c.component)
                                throw Error('Cannot use the "component" binding on a custom element matching a component');
                            var l = { name: h, params: b(e, f) };
                            c.component = g ? function () { return l; } : l;
                        }
                    }
                    return c;
                };
                var c = new a.R;
                9 > a.a.C && (a.g.register = function (a) { return function (b) { s.createElement(b); return a.apply(this, arguments); }; }(a.g.register), s.createDocumentFragment = function (b) {
                    return function () {
                        var c = b(), f = a.g.Cc, g;
                        for (g in f)
                            f.hasOwnProperty(g) && c.createElement(g);
                        return c;
                    };
                }(s.createDocumentFragment));
            })();
            (function (b) {
                function c(b, c, d) {
                    c = c.template;
                    if (!c)
                        throw Error("Component '" + b + "' has no template");
                    b = a.a.ua(c);
                    a.f.da(d, b);
                }
                function d(a, b, c, d) { var e = a.createViewModel; return e ? e.call(a, d, { element: b, templateNodes: c }) : d; }
                var e = 0;
                a.d.component = { init: function (f, g, h, l, m) {
                        function k() { var a = r && r.dispose; "function" === typeof a && a.call(r); q = r = null; }
                        var r, q, p = a.a.V(a.f.childNodes(f));
                        a.a.F.oa(f, k);
                        a.m(function () {
                            var l = a.a.c(g()), h, v;
                            "string" === typeof l ? h = l : (h = a.a.c(l.name), v = a.a.c(l.params));
                            if (!h)
                                throw Error("No component name specified");
                            var n = q = ++e;
                            a.g.get(h, function (e) {
                                if (q === n) {
                                    k();
                                    if (!e)
                                        throw Error("Unknown component '" + h +
                                            "'");
                                    c(h, e, f);
                                    var l = d(e, f, p, v);
                                    e = m.createChildContext(l, b, function (a) { a.$component = l; a.$componentTemplateNodes = p; });
                                    r = l;
                                    a.eb(e, f);
                                }
                            });
                        }, null, { i: f });
                        return { controlsDescendantBindings: !0 };
                    } };
                a.f.Z.component = !0;
            })();
            var Q = { "class": "className", "for": "htmlFor" };
            a.d.attr = { update: function (b, c) {
                    var d = a.a.c(c()) || {};
                    a.a.D(d, function (c, d) {
                        d = a.a.c(d);
                        var g = !1 === d || null === d || d === n;
                        g && b.removeAttribute(c);
                        8 >= a.a.C && c in Q ? (c = Q[c], g ? b.removeAttribute(c) : b[c] = d) : g || b.setAttribute(c, d.toString());
                        "name" === c && a.a.tc(b, g ? "" : d.toString());
                    });
                } };
            (function () {
                a.d.checked = { after: ["value", "attr"], init: function (b, c, d) {
                        function e() {
                            var e = b.checked, f = p ? g() : e;
                            if (!a.va.Sa() && (!l || e)) {
                                var h = a.l.w(c);
                                if (k) {
                                    var m = r ? h.t() : h;
                                    q !== f ? (e && (a.a.pa(m, f, !0), a.a.pa(m, q, !1)), q = f) : a.a.pa(m, f, e);
                                    r && a.Ba(h) && h(m);
                                }
                                else
                                    a.h.Ea(h, d, "checked", f, !0);
                            }
                        }
                        function f() { var d = a.a.c(c()); b.checked = k ? 0 <= a.a.o(d, g()) : h ? d : g() === d; }
                        var g = a.pc(function () { return d.has("checkedValue") ? a.a.c(d.get("checkedValue")) : d.has("value") ? a.a.c(d.get("value")) : b.value; }), h = "checkbox" == b.type, l = "radio" == b.type;
                        if (h || l) {
                            var m = c(), k = h && a.a.c(m) instanceof Array, r = !(k && m.push && m.splice), q = k ? g() : n, p = l || k;
                            l && !b.name && a.d.uniqueName.init(b, function () { return !0; });
                            a.m(e, null, { i: b });
                            a.a.p(b, "click", e);
                            a.m(f, null, { i: b });
                            m = n;
                        }
                    } };
                a.h.ea.checked = !0;
                a.d.checkedValue = { update: function (b, c) { b.value = a.a.c(c()); } };
            })();
            a.d.css = { update: function (b, c) {
                    var d = a.a.c(c());
                    null !== d && "object" == typeof d ? a.a.D(d, function (c, d) { d = a.a.c(d); a.a.bb(b, c, d); }) : (d = a.a.$a(String(d || "")), a.a.bb(b, b.__ko__cssValue, !1), b.__ko__cssValue = d, a.a.bb(b, d, !0));
                } };
            a.d.enable = { update: function (b, c) { var d = a.a.c(c()); d && b.disabled ? b.removeAttribute("disabled") : d || b.disabled || (b.disabled = !0); } };
            a.d.disable = { update: function (b, c) { a.d.enable.update(b, function () { return !a.a.c(c()); }); } };
            a.d.event = { init: function (b, c, d, e, f) {
                    var g = c() || {};
                    a.a.D(g, function (g) {
                        "string" == typeof g && a.a.p(b, g, function (b) {
                            var m, k = c()[g];
                            if (k) {
                                try {
                                    var r = a.a.V(arguments);
                                    e = f.$data;
                                    r.unshift(e);
                                    m = k.apply(e, r);
                                }
                                finally {
                                    !0 !== m && (b.preventDefault ? b.preventDefault() :
                                        b.returnValue = !1);
                                }
                                !1 === d.get(g + "Bubble") && (b.cancelBubble = !0, b.stopPropagation && b.stopPropagation());
                            }
                        });
                    });
                } };
            a.d.foreach = { kc: function (b) {
                    return function () {
                        var c = b(), d = a.a.zb(c);
                        if (!d || "number" == typeof d.length)
                            return { foreach: c, templateEngine: a.W.sb };
                        a.a.c(c);
                        return { foreach: d.data, as: d.as, includeDestroyed: d.includeDestroyed, afterAdd: d.afterAdd, beforeRemove: d.beforeRemove, afterRender: d.afterRender, beforeMove: d.beforeMove, afterMove: d.afterMove, templateEngine: a.W.sb };
                    };
                }, init: function (b, c) {
                    return a.d.template.init(b, a.d.foreach.kc(c));
                }, update: function (b, c, d, e, f) { return a.d.template.update(b, a.d.foreach.kc(c), d, e, f); } };
            a.h.ta.foreach = !1;
            a.f.Z.foreach = !0;
            a.d.hasfocus = { init: function (b, c, d) {
                    function e(e) {
                        b.__ko_hasfocusUpdating = !0;
                        var f = b.ownerDocument;
                        if ("activeElement" in f) {
                            var g;
                            try {
                                g = f.activeElement;
                            }
                            catch (k) {
                                g = f.body;
                            }
                            e = g === b;
                        }
                        f = c();
                        a.h.Ea(f, d, "hasfocus", e, !0);
                        b.__ko_hasfocusLastValue = e;
                        b.__ko_hasfocusUpdating = !1;
                    }
                    var f = e.bind(null, !0), g = e.bind(null, !1);
                    a.a.p(b, "focus", f);
                    a.a.p(b, "focusin", f);
                    a.a.p(b, "blur", g);
                    a.a.p(b, "focusout", g);
                }, update: function (b, c) { var d = !!a.a.c(c()); b.__ko_hasfocusUpdating || b.__ko_hasfocusLastValue === d || (d ? b.focus() : b.blur(), !d && b.__ko_hasfocusLastValue && b.ownerDocument.body.focus(), a.l.w(a.a.Da, null, [b, d ? "focusin" : "focusout"])); } };
            a.h.ea.hasfocus = !0;
            a.d.hasFocus = a.d.hasfocus;
            a.h.ea.hasFocus = !0;
            a.d.html = { init: function () { return { controlsDescendantBindings: !0 }; }, update: function (b, c) { a.a.Cb(b, c()); } };
            K("if");
            K("ifnot", !1, !0);
            K("with", !0, !1, function (a, c) { return a.Zb(c); });
            var L = {};
            a.d.options = { init: function (b) {
                    if ("select" !==
                        a.a.A(b))
                        throw Error("options binding applies only to SELECT elements");
                    for (; 0 < b.length;)
                        b.remove(0);
                    return { controlsDescendantBindings: !0 };
                }, update: function (b, c, d) {
                    function e() { return a.a.Ka(b.options, function (a) { return a.selected; }); }
                    function f(a, b, c) { var d = typeof b; return "function" == d ? b(a) : "string" == d ? a[b] : c; }
                    function g(c, e) {
                        if (A && k)
                            a.j.ha(b, a.a.c(d.get("value")), !0);
                        else if (p.length) {
                            var f = 0 <= a.a.o(p, a.j.u(e[0]));
                            a.a.uc(e[0], f);
                            A && !f && a.l.w(a.a.Da, null, [b, "change"]);
                        }
                    }
                    var h = b.multiple, l = 0 != b.length &&
                        h ? b.scrollTop : null, m = a.a.c(c()), k = d.get("valueAllowUnset") && d.has("value"), r = d.get("optionsIncludeDestroyed");
                    c = {};
                    var q, p = [];
                    k || (h ? p = a.a.fb(e(), a.j.u) : 0 <= b.selectedIndex && p.push(a.j.u(b.options[b.selectedIndex])));
                    m && ("undefined" == typeof m.length && (m = [m]), q = a.a.Ka(m, function (b) { return r || b === n || null === b || !a.a.c(b._destroy); }), d.has("optionsCaption") && (m = a.a.c(d.get("optionsCaption")), null !== m && m !== n && q.unshift(L)));
                    var A = !1;
                    c.beforeRemove = function (a) { b.removeChild(a); };
                    m = g;
                    d.has("optionsAfterRender") &&
                        "function" == typeof d.get("optionsAfterRender") && (m = function (b, c) { g(0, c); a.l.w(d.get("optionsAfterRender"), null, [c[0], b !== L ? b : n]); });
                    a.a.Bb(b, q, function (c, e, g) { g.length && (p = !k && g[0].selected ? [a.j.u(g[0])] : [], A = !0); e = b.ownerDocument.createElement("option"); c === L ? (a.a.Za(e, d.get("optionsCaption")), a.j.ha(e, n)) : (g = f(c, d.get("optionsValue"), c), a.j.ha(e, a.a.c(g)), c = f(c, d.get("optionsText"), g), a.a.Za(e, c)); return [e]; }, c, m);
                    a.l.w(function () {
                        k ? a.j.ha(b, a.a.c(d.get("value")), !0) : (h ? p.length && e().length < p.length :
                            p.length && 0 <= b.selectedIndex ? a.j.u(b.options[b.selectedIndex]) !== p[0] : p.length || 0 <= b.selectedIndex) && a.a.Da(b, "change");
                    });
                    a.a.Oc(b);
                    l && 20 < Math.abs(l - b.scrollTop) && (b.scrollTop = l);
                } };
            a.d.options.xb = a.a.e.I();
            a.d.selectedOptions = { after: ["options", "foreach"], init: function (b, c, d) { a.a.p(b, "change", function () { var e = c(), f = []; a.a.q(b.getElementsByTagName("option"), function (b) { b.selected && f.push(a.j.u(b)); }); a.h.Ea(e, d, "selectedOptions", f); }); }, update: function (b, c) {
                    if ("select" != a.a.A(b))
                        throw Error("values binding applies only to SELECT elements");
                    var d = a.a.c(c()), e = b.scrollTop;
                    d && "number" == typeof d.length && a.a.q(b.getElementsByTagName("option"), function (b) { var c = 0 <= a.a.o(d, a.j.u(b)); b.selected != c && a.a.uc(b, c); });
                    b.scrollTop = e;
                } };
            a.h.ea.selectedOptions = !0;
            a.d.style = { update: function (b, c) {
                    var d = a.a.c(c() || {});
                    a.a.D(d, function (c, d) {
                        d = a.a.c(d);
                        if (null === d || d === n || !1 === d)
                            d = "";
                        b.style[c] = d;
                    });
                } };
            a.d.submit = { init: function (b, c, d, e, f) {
                    if ("function" != typeof c())
                        throw Error("The value for a submit binding must be a function");
                    a.a.p(b, "submit", function (a) {
                        var d, e = c();
                        try {
                            d = e.call(f.$data, b);
                        }
                        finally {
                            !0 !== d && (a.preventDefault ? a.preventDefault() : a.returnValue = !1);
                        }
                    });
                } };
            a.d.text = { init: function () { return { controlsDescendantBindings: !0 }; }, update: function (b, c) { a.a.Za(b, c()); } };
            a.f.Z.text = !0;
            (function () {
                if (x && x.navigator)
                    var b = function (a) {
                        if (a)
                            return parseFloat(a[1]);
                    }, c = x.opera && x.opera.version && parseInt(x.opera.version()), d = x.navigator.userAgent, e = b(d.match(/^(?:(?!chrome).)*version\/([^ ]*) safari/i)), f = b(d.match(/Firefox\/([^ ]*)/));
                if (10 > a.a.C)
                    var g = a.a.e.I(), h = a.a.e.I(), l = function (b) { var c = this.activeElement; (c = c && a.a.e.get(c, h)) && c(b); }, m = function (b, c) { var d = b.ownerDocument; a.a.e.get(d, g) || (a.a.e.set(d, g, !0), a.a.p(d, "selectionchange", l)); a.a.e.set(b, h, c); };
                a.d.textInput = { init: function (b, d, g) {
                        function l(c, d) { a.a.p(b, c, d); }
                        function h() {
                            var c = a.a.c(d());
                            if (null === c || c === n)
                                c = "";
                            u !== n && c === u ? a.a.setTimeout(h, 4) : b.value !== c && (s = c, b.value = c);
                        }
                        function y() { t || (u = b.value, t = a.a.setTimeout(v, 4)); }
                        function v() {
                            clearTimeout(t);
                            u = t = n;
                            var c = b.value;
                            s !== c && (s = c, a.h.Ea(d(), g, "textInput", c));
                        }
                        var s = b.value, t, u, x = 9 == a.a.C ? y : v;
                        10 > a.a.C ? (l("propertychange", function (a) { "value" === a.propertyName && x(a); }), 8 == a.a.C && (l("keyup", v), l("keydown", v)), 8 <= a.a.C && (m(b, x), l("dragend", y))) : (l("input", v), 5 > e && "textarea" === a.a.A(b) ? (l("keydown", y), l("paste", y), l("cut", y)) : 11 > c ? l("keydown", y) : 4 > f && (l("DOMAutoComplete", v), l("dragdrop", v), l("drop", v)));
                        l("change", v);
                        a.m(h, null, { i: b });
                    } };
                a.h.ea.textInput = !0;
                a.d.textinput = { preprocess: function (a, b, c) { c("textInput", a); } };
            })();
            a.d.uniqueName = { init: function (b, c) {
                    if (c()) {
                        var d = "ko_unique_" + ++a.d.uniqueName.Jc;
                        a.a.tc(b, d);
                    }
                } };
            a.d.uniqueName.Jc = 0;
            a.d.value = { after: ["options", "foreach"], init: function (b, c, d) {
                    if ("input" != b.tagName.toLowerCase() || "checkbox" != b.type && "radio" != b.type) {
                        var e = ["change"], f = d.get("valueUpdate"), g = !1, h = null;
                        f && ("string" == typeof f && (f = [f]), a.a.ra(e, f), e = a.a.Ub(e));
                        var l = function () { h = null; g = !1; var e = c(), f = a.j.u(b); a.h.Ea(e, d, "value", f); };
                        !a.a.C || "input" != b.tagName.toLowerCase() || "text" != b.type || "off" == b.autocomplete || b.form && "off" == b.form.autocomplete ||
                            -1 != a.a.o(e, "propertychange") || (a.a.p(b, "propertychange", function () { g = !0; }), a.a.p(b, "focus", function () { g = !1; }), a.a.p(b, "blur", function () { g && l(); }));
                        a.a.q(e, function (c) { var d = l; a.a.od(c, "after") && (d = function () { h = a.j.u(b); a.a.setTimeout(l, 0); }, c = c.substring(5)); a.a.p(b, c, d); });
                        var m = function () {
                            var e = a.a.c(c()), f = a.j.u(b);
                            if (null !== h && e === h)
                                a.a.setTimeout(m, 0);
                            else if (e !== f)
                                if ("select" === a.a.A(b)) {
                                    var g = d.get("valueAllowUnset"), f = function () { a.j.ha(b, e, g); };
                                    f();
                                    g || e === a.j.u(b) ? a.a.setTimeout(f, 0) : a.l.w(a.a.Da, null, [b, "change"]);
                                }
                                else
                                    a.j.ha(b, e);
                        };
                        a.m(m, null, { i: b });
                    }
                    else
                        a.Ja(b, { checkedValue: c });
                }, update: function () { } };
            a.h.ea.value = !0;
            a.d.visible = { update: function (b, c) { var d = a.a.c(c()), e = "none" != b.style.display; d && !e ? b.style.display = "" : !d && e && (b.style.display = "none"); } };
            (function (b) { a.d[b] = { init: function (c, d, e, f, g) { return a.d.event.init.call(this, c, function () { var a = {}; a[b] = d(); return a; }, e, f, g); } }; })("click");
            a.O = function () { };
            a.O.prototype.renderTemplateSource = function () {
                throw Error("Override renderTemplateSource");
            };
            a.O.prototype.createJavaScriptEvaluatorBlock = function () { throw Error("Override createJavaScriptEvaluatorBlock"); };
            a.O.prototype.makeTemplateSource = function (b, c) {
                if ("string" == typeof b) {
                    c = c || s;
                    var d = c.getElementById(b);
                    if (!d)
                        throw Error("Cannot find template with ID " + b);
                    return new a.v.n(d);
                }
                if (1 == b.nodeType || 8 == b.nodeType)
                    return new a.v.qa(b);
                throw Error("Unknown template type: " + b);
            };
            a.O.prototype.renderTemplate = function (a, c, d, e) {
                a = this.makeTemplateSource(a, e);
                return this.renderTemplateSource(a, c, d, e);
            };
            a.O.prototype.isTemplateRewritten = function (a, c) { return !1 === this.allowTemplateRewriting ? !0 : this.makeTemplateSource(a, c).data("isRewritten"); };
            a.O.prototype.rewriteTemplate = function (a, c, d) { a = this.makeTemplateSource(a, d); c = c(a.text()); a.text(c); a.data("isRewritten", !0); };
            a.b("templateEngine", a.O);
            a.Gb = function () {
                function b(b, c, d, h) {
                    b = a.h.yb(b);
                    for (var l = a.h.ta, m = 0; m < b.length; m++) {
                        var k = b[m].key;
                        if (l.hasOwnProperty(k)) {
                            var r = l[k];
                            if ("function" === typeof r) {
                                if (k = r(b[m].value))
                                    throw Error(k);
                            }
                            else if (!r)
                                throw Error("This template engine does not support the '" +
                                    k + "' binding within its templates");
                        }
                    }
                    d = "ko.__tr_ambtns(function($context,$element){return(function(){return{ " + a.h.Ua(b, { valueAccessors: !0 }) + " } })()},'" + d.toLowerCase() + "')";
                    return h.createJavaScriptEvaluatorBlock(d) + c;
                }
                var c = /(<([a-z]+\d*)(?:\s+(?!data-bind\s*=\s*)[a-z0-9\-]+(?:=(?:\"[^\"]*\"|\'[^\']*\'|[^>]*))?)*\s+)data-bind\s*=\s*(["'])([\s\S]*?)\3/gi, d = /\x3c!--\s*ko\b\s*([\s\S]*?)\s*--\x3e/g;
                return { Pc: function (b, c, d) {
                        c.isTemplateRewritten(b, d) || c.rewriteTemplate(b, function (b) {
                            return a.Gb.ed(b, c);
                        }, d);
                    }, ed: function (a, f) { return a.replace(c, function (a, c, d, e, k) { return b(k, c, d, f); }).replace(d, function (a, c) { return b(c, "\x3c!-- ko --\x3e", "#comment", f); }); }, Fc: function (b, c) { return a.M.wb(function (d, h) { var l = d.nextSibling; l && l.nodeName.toLowerCase() === c && a.Ja(l, b, h); }); } };
            }();
            a.b("__tr_ambtns", a.Gb.Fc);
            (function () {
                a.v = {};
                a.v.n = function (b) {
                    if (this.n = b) {
                        var c = a.a.A(b);
                        this.ab = "script" === c ? 1 : "textarea" === c ? 2 : "template" == c && b.content && 11 === b.content.nodeType ? 3 : 4;
                    }
                };
                a.v.n.prototype.text = function () {
                    var b = 1 ===
                        this.ab ? "text" : 2 === this.ab ? "value" : "innerHTML";
                    if (0 == arguments.length)
                        return this.n[b];
                    var c = arguments[0];
                    "innerHTML" === b ? a.a.Cb(this.n, c) : this.n[b] = c;
                };
                var b = a.a.e.I() + "_";
                a.v.n.prototype.data = function (c) {
                    if (1 === arguments.length)
                        return a.a.e.get(this.n, b + c);
                    a.a.e.set(this.n, b + c, arguments[1]);
                };
                var c = a.a.e.I();
                a.v.n.prototype.nodes = function () {
                    var b = this.n;
                    if (0 == arguments.length)
                        return (a.a.e.get(b, c) || {}).jb || (3 === this.ab ? b.content : 4 === this.ab ? b : n);
                    a.a.e.set(b, c, { jb: arguments[0] });
                };
                a.v.qa = function (a) {
                    this.n =
                        a;
                };
                a.v.qa.prototype = new a.v.n;
                a.v.qa.prototype.text = function () {
                    if (0 == arguments.length) {
                        var b = a.a.e.get(this.n, c) || {};
                        b.Hb === n && b.jb && (b.Hb = b.jb.innerHTML);
                        return b.Hb;
                    }
                    a.a.e.set(this.n, c, { Hb: arguments[0] });
                };
                a.b("templateSources", a.v);
                a.b("templateSources.domElement", a.v.n);
                a.b("templateSources.anonymousTemplate", a.v.qa);
            })();
            (function () {
                function b(b, c, d) {
                    var e;
                    for (c = a.f.nextSibling(c); b && (e = b) !== c;)
                        b = a.f.nextSibling(e), d(e, b);
                }
                function c(c, d) {
                    if (c.length) {
                        var e = c[0], f = c[c.length - 1], g = e.parentNode, h = a.R.instance, n = h.preprocessNode;
                        if (n) {
                            b(e, f, function (a, b) { var c = a.previousSibling, d = n.call(h, a); d && (a === e && (e = d[0] || b), a === f && (f = d[d.length - 1] || c)); });
                            c.length = 0;
                            if (!e)
                                return;
                            e === f ? c.push(e) : (c.push(e, f), a.a.za(c, g));
                        }
                        b(e, f, function (b) { 1 !== b.nodeType && 8 !== b.nodeType || a.Sb(d, b); });
                        b(e, f, function (b) { 1 !== b.nodeType && 8 !== b.nodeType || a.M.Ac(b, [d]); });
                        a.a.za(c, g);
                    }
                }
                function d(a) { return a.nodeType ? a : 0 < a.length ? a[0] : null; }
                function e(b, e, f, h, q) {
                    q = q || {};
                    var p = (b && d(b) || f || {}).ownerDocument, n = q.templateEngine || g;
                    a.Gb.Pc(f, n, p);
                    f = n.renderTemplate(f, h, q, p);
                    if ("number" != typeof f.length || 0 < f.length && "number" != typeof f[0].nodeType)
                        throw Error("Template engine must return an array of DOM nodes");
                    p = !1;
                    switch (e) {
                        case "replaceChildren":
                            a.f.da(b, f);
                            p = !0;
                            break;
                        case "replaceNode":
                            a.a.sc(b, f);
                            p = !0;
                            break;
                        case "ignoreTargetNode": break;
                        default: throw Error("Unknown renderMode: " + e);
                    }
                    p && (c(f, h), q.afterRender && a.l.w(q.afterRender, null, [f, h.$data]));
                    return f;
                }
                function f(b, c, d) { return a.H(b) ? b() : "function" === typeof b ? b(c, d) : b; }
                var g;
                a.Db = function (b) {
                    if (b != n && !(b instanceof a.O))
                        throw Error("templateEngine must inherit from ko.templateEngine");
                    g = b;
                };
                a.Ab = function (b, c, k, h, q) {
                    k = k || {};
                    if ((k.templateEngine || g) == n)
                        throw Error("Set a template engine before calling renderTemplate");
                    q = q || "replaceChildren";
                    if (h) {
                        var p = d(h);
                        return a.B(function () { var g = c && c instanceof a.Q ? c : new a.Q(c, null, null, null, { exportDependencies: !0 }), n = f(b, g.$data, g), g = e(h, q, n, g, k); "replaceNode" == q && (h = g, p = d(h)); }, null, { wa: function () { return !p || !a.a.nb(p); }, i: p &&
                                "replaceNode" == q ? p.parentNode : p });
                    }
                    return a.M.wb(function (d) { a.Ab(b, c, k, d, "replaceNode"); });
                };
                a.ld = function (b, d, g, h, q) {
                    function p(a, b) { c(b, t); g.afterRender && g.afterRender(b, a); t = null; }
                    function s(a, c) { t = q.createChildContext(a, g.as, function (a) { a.$index = c; }); var d = f(b, a, t); return e(null, "ignoreTargetNode", d, t, g); }
                    var t;
                    return a.B(function () {
                        var b = a.a.c(d) || [];
                        "undefined" == typeof b.length && (b = [b]);
                        b = a.a.Ka(b, function (b) { return g.includeDestroyed || b === n || null === b || !a.a.c(b._destroy); });
                        a.l.w(a.a.Bb, null, [h, b,
                            s, g, p]);
                    }, null, { i: h });
                };
                var h = a.a.e.I();
                a.d.template = { init: function (b, c) {
                        var d = a.a.c(c());
                        if ("string" == typeof d || d.name)
                            a.f.xa(b);
                        else {
                            if ("nodes" in d) {
                                if (d = d.nodes || [], a.H(d))
                                    throw Error('The "nodes" option must be a plain, non-observable array.');
                            }
                            else
                                d = a.f.childNodes(b);
                            d = a.a.lc(d);
                            (new a.v.qa(b)).nodes(d);
                        }
                        return { controlsDescendantBindings: !0 };
                    }, update: function (b, c, d, e, f) {
                        var g = c();
                        c = a.a.c(g);
                        d = !0;
                        e = null;
                        "string" == typeof c ? c = {} : (g = c.name, "if" in c && (d = a.a.c(c["if"])), d && "ifnot" in c && (d = !a.a.c(c.ifnot)));
                        "foreach" in c ? e = a.ld(g || b, d && c.foreach || [], c, b, f) : d ? (f = "data" in c ? f.Zb(c.data, c.as) : f, e = a.Ab(g || b, f, c, b)) : a.f.xa(b);
                        f = e;
                        (c = a.a.e.get(b, h)) && "function" == typeof c.k && c.k();
                        a.a.e.set(b, h, f && f.ba() ? f : n);
                    } };
                a.h.ta.template = function (b) { b = a.h.yb(b); return 1 == b.length && b[0].unknown || a.h.bd(b, "name") ? null : "This template engine does not support anonymous templates nested within its templates"; };
                a.f.Z.template = !0;
            })();
            a.b("setTemplateEngine", a.Db);
            a.b("renderTemplate", a.Ab);
            a.a.fc = function (a, c, d) {
                if (a.length &&
                    c.length) {
                    var e, f, g, h, l;
                    for (e = f = 0; (!d || e < d) && (h = a[f]); ++f) {
                        for (g = 0; l = c[g]; ++g)
                            if (h.value === l.value) {
                                h.moved = l.index;
                                l.moved = h.index;
                                c.splice(g, 1);
                                e = g = 0;
                                break;
                            }
                        e += g;
                    }
                }
            };
            a.a.ib = function () {
                function b(b, d, e, f, g) {
                    var h = Math.min, l = Math.max, m = [], k, n = b.length, q, p = d.length, s = p - n || 1, t = n + p + 1, v, u, x;
                    for (k = 0; k <= n; k++)
                        for (u = v, m.push(v = []), x = h(p, k + s), q = l(0, k - 1); q <= x; q++)
                            v[q] = q ? k ? b[k - 1] === d[q - 1] ? u[q - 1] : h(u[q] || t, v[q - 1] || t) + 1 : q + 1 : k + 1;
                    h = [];
                    l = [];
                    s = [];
                    k = n;
                    for (q = p; k || q;)
                        p = m[k][q] - 1, q && p === m[k][q - 1] ? l.push(h[h.length] = { status: e,
                            value: d[--q], index: q }) : k && p === m[k - 1][q] ? s.push(h[h.length] = { status: f, value: b[--k], index: k }) : (--q, --k, g.sparse || h.push({ status: "retained", value: d[q] }));
                    a.a.fc(s, l, !g.dontLimitMoves && 10 * n);
                    return h.reverse();
                }
                return function (a, d, e) { e = "boolean" === typeof e ? { dontLimitMoves: e } : e || {}; a = a || []; d = d || []; return a.length < d.length ? b(a, d, "added", "deleted", e) : b(d, a, "deleted", "added", e); };
            }();
            a.b("utils.compareArrays", a.a.ib);
            (function () {
                function b(b, c, d, h, l) {
                    var m = [], k = a.B(function () {
                        var k = c(d, l, a.a.za(m, b)) || [];
                        0 <
                            m.length && (a.a.sc(m, k), h && a.l.w(h, null, [d, k, l]));
                        m.length = 0;
                        a.a.ra(m, k);
                    }, null, { i: b, wa: function () { return !a.a.Rb(m); } });
                    return { ca: m, B: k.ba() ? k : n };
                }
                var c = a.a.e.I(), d = a.a.e.I();
                a.a.Bb = function (e, f, g, h, l) {
                    function m(b, c) { w = q[c]; u !== c && (D[b] = w); w.qb(u++); a.a.za(w.ca, e); t.push(w); z.push(w); }
                    function k(b, c) {
                        if (b)
                            for (var d = 0, e = c.length; d < e; d++)
                                c[d] && a.a.q(c[d].ca, function (a) { b(a, d, c[d].ja); });
                    }
                    f = f || [];
                    h = h || {};
                    var r = a.a.e.get(e, c) === n, q = a.a.e.get(e, c) || [], p = a.a.fb(q, function (a) { return a.ja; }), s = a.a.ib(p, f, h.dontLimitMoves), t = [], v = 0, u = 0, x = [], z = [];
                    f = [];
                    for (var D = [], p = [], w, C = 0, B, E; B = s[C]; C++)
                        switch (E = B.moved, B.status) {
                            case "deleted":
                                E === n && (w = q[v], w.B && (w.B.k(), w.B = n), a.a.za(w.ca, e).length && (h.beforeRemove && (t.push(w), z.push(w), w.ja === d ? w = null : f[C] = w), w && x.push.apply(x, w.ca)));
                                v++;
                                break;
                            case "retained":
                                m(C, v++);
                                break;
                            case "added": E !== n ? m(C, E) : (w = { ja: B.value, qb: a.N(u++) }, t.push(w), z.push(w), r || (p[C] = w));
                        }
                    a.a.e.set(e, c, t);
                    k(h.beforeMove, D);
                    a.a.q(x, h.beforeRemove ? a.$ : a.removeNode);
                    for (var C = 0, r = a.f.firstChild(e), F; w = z[C]; C++) {
                        w.ca ||
                            a.a.extend(w, b(e, g, w.ja, l, w.qb));
                        for (v = 0; s = w.ca[v]; r = s.nextSibling, F = s, v++)
                            s !== r && a.f.ic(e, s, F);
                        !w.Xc && l && (l(w.ja, w.ca, w.qb), w.Xc = !0);
                    }
                    k(h.beforeRemove, f);
                    for (C = 0; C < f.length; ++C)
                        f[C] && (f[C].ja = d);
                    k(h.afterMove, D);
                    k(h.afterAdd, p);
                };
            })();
            a.b("utils.setDomNodeChildrenFromArrayMapping", a.a.Bb);
            a.W = function () { this.allowTemplateRewriting = !1; };
            a.W.prototype = new a.O;
            a.W.prototype.renderTemplateSource = function (b, c, d, e) {
                if (c = (9 > a.a.C ? 0 : b.nodes) ? b.nodes() : null)
                    return a.a.V(c.cloneNode(!0).childNodes);
                b = b.text();
                return a.a.ma(b, e);
            };
            a.W.sb = new a.W;
            a.Db(a.W.sb);
            a.b("nativeTemplateEngine", a.W);
            (function () {
                a.vb = function () {
                    var a = this.ad = function () {
                        if (!u || !u.tmpl)
                            return 0;
                        try {
                            if (0 <= u.tmpl.tag.tmpl.open.toString().indexOf("__"))
                                return 2;
                        }
                        catch (a) { }
                        return 1;
                    }();
                    this.renderTemplateSource = function (b, e, f, g) {
                        g = g || s;
                        f = f || {};
                        if (2 > a)
                            throw Error("Your version of jQuery.tmpl is too old. Please upgrade to jQuery.tmpl 1.0.0pre or later.");
                        var h = b.data("precompiled");
                        h || (h = b.text() || "", h = u.template(null, "{{ko_with $item.koBindingContext}}" +
                            h + "{{/ko_with}}"), b.data("precompiled", h));
                        b = [e.$data];
                        e = u.extend({ koBindingContext: e }, f.templateOptions);
                        e = u.tmpl(h, b, e);
                        e.appendTo(g.createElement("div"));
                        u.fragments = {};
                        return e;
                    };
                    this.createJavaScriptEvaluatorBlock = function (a) { return "{{ko_code ((function() { return " + a + " })()) }}"; };
                    this.addTemplate = function (a, b) { s.write("<script type='text/html' id='" + a + "'>" + b + "\x3c/script>"); };
                    0 < a && (u.tmpl.tag.ko_code = { open: "__.push($1 || '');" }, u.tmpl.tag.ko_with = { open: "with($1) {", close: "} " });
                };
                a.vb.prototype =
                    new a.O;
                var b = new a.vb;
                0 < b.ad && a.Db(b);
                a.b("jqueryTmplTemplateEngine", a.vb);
            })();
        });
    })();
})();
//# sourceMappingURL=04. knockout.js.map 
//# sourceMappingURL=04. knockout.js.map 
//# sourceMappingURL=04. knockout.js.map 
//# sourceMappingURL=04. knockout.js.map 
//# sourceMappingURL=04. knockout.js.map 
//# sourceMappingURL=04. knockout.js.map 
//# sourceMappingURL=04. knockout.js.map 
//# sourceMappingURL=04. knockout.js.map 
//# sourceMappingURL=04. knockout.js.map 
//# sourceMappingURL=04. knockout.js.map 
//# sourceMappingURL=04. knockout.js.map 
//# sourceMappingURL=04. knockout.js.map 
//# sourceMappingURL=04. knockout.js.map;
//! moment.js
//! version : 2.14.1
//! authors : Tim Wood, Iskren Chernev, Moment.js contributors
//! license : MIT
//! momentjs.com
;
(function (global, factory) {
    typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
        typeof define === 'function' && define.amd ? define(factory) :
            global.moment = factory();
}(this, function () {
    'use strict';
    var hookCallback;
    function utils_hooks__hooks() {
        return hookCallback.apply(null, arguments);
    }
    // This is done to register the method called with moment()
    // without creating circular dependencies.
    function setHookCallback(callback) {
        hookCallback = callback;
    }
    function isArray(input) {
        return input instanceof Array || Object.prototype.toString.call(input) === '[object Array]';
    }
    function isObject(input) {
        return Object.prototype.toString.call(input) === '[object Object]';
    }
    function isObjectEmpty(obj) {
        var k;
        for (k in obj) {
            // even if its not own property I'd still call it non-empty
            return false;
        }
        return true;
    }
    function isDate(input) {
        return input instanceof Date || Object.prototype.toString.call(input) === '[object Date]';
    }
    function map(arr, fn) {
        var res = [], i;
        for (i = 0; i < arr.length; ++i) {
            res.push(fn(arr[i], i));
        }
        return res;
    }
    function hasOwnProp(a, b) {
        return Object.prototype.hasOwnProperty.call(a, b);
    }
    function extend(a, b) {
        for (var i in b) {
            if (hasOwnProp(b, i)) {
                a[i] = b[i];
            }
        }
        if (hasOwnProp(b, 'toString')) {
            a.toString = b.toString;
        }
        if (hasOwnProp(b, 'valueOf')) {
            a.valueOf = b.valueOf;
        }
        return a;
    }
    function create_utc__createUTC(input, format, locale, strict) {
        return createLocalOrUTC(input, format, locale, strict, true).utc();
    }
    function defaultParsingFlags() {
        // We need to deep clone this object.
        return {
            empty: false,
            unusedTokens: [],
            unusedInput: [],
            overflow: -2,
            charsLeftOver: 0,
            nullInput: false,
            invalidMonth: null,
            invalidFormat: false,
            userInvalidated: false,
            iso: false,
            parsedDateParts: [],
            meridiem: null
        };
    }
    function getParsingFlags(m) {
        if (m._pf == null) {
            m._pf = defaultParsingFlags();
        }
        return m._pf;
    }
    var some;
    if (Array.prototype.some) {
        some = Array.prototype.some;
    }
    else {
        some = function (fun) {
            var t = Object(this);
            var len = t.length >>> 0;
            for (var i = 0; i < len; i++) {
                if (i in t && fun.call(this, t[i], i, t)) {
                    return true;
                }
            }
            return false;
        };
    }
    function valid__isValid(m) {
        if (m._isValid == null) {
            var flags = getParsingFlags(m);
            var parsedParts = some.call(flags.parsedDateParts, function (i) {
                return i != null;
            });
            m._isValid = !isNaN(m._d.getTime()) &&
                flags.overflow < 0 &&
                !flags.empty &&
                !flags.invalidMonth &&
                !flags.invalidWeekday &&
                !flags.nullInput &&
                !flags.invalidFormat &&
                !flags.userInvalidated &&
                (!flags.meridiem || (flags.meridiem && parsedParts));
            if (m._strict) {
                m._isValid = m._isValid &&
                    flags.charsLeftOver === 0 &&
                    flags.unusedTokens.length === 0 &&
                    flags.bigHour === undefined;
            }
        }
        return m._isValid;
    }
    function valid__createInvalid(flags) {
        var m = create_utc__createUTC(NaN);
        if (flags != null) {
            extend(getParsingFlags(m), flags);
        }
        else {
            getParsingFlags(m).userInvalidated = true;
        }
        return m;
    }
    function isUndefined(input) {
        return input === void 0;
    }
    // Plugins that add properties should also add the key here (null value),
    // so we can properly clone ourselves.
    var momentProperties = utils_hooks__hooks.momentProperties = [];
    function copyConfig(to, from) {
        var i, prop, val;
        if (!isUndefined(from._isAMomentObject)) {
            to._isAMomentObject = from._isAMomentObject;
        }
        if (!isUndefined(from._i)) {
            to._i = from._i;
        }
        if (!isUndefined(from._f)) {
            to._f = from._f;
        }
        if (!isUndefined(from._l)) {
            to._l = from._l;
        }
        if (!isUndefined(from._strict)) {
            to._strict = from._strict;
        }
        if (!isUndefined(from._tzm)) {
            to._tzm = from._tzm;
        }
        if (!isUndefined(from._isUTC)) {
            to._isUTC = from._isUTC;
        }
        if (!isUndefined(from._offset)) {
            to._offset = from._offset;
        }
        if (!isUndefined(from._pf)) {
            to._pf = getParsingFlags(from);
        }
        if (!isUndefined(from._locale)) {
            to._locale = from._locale;
        }
        if (momentProperties.length > 0) {
            for (i in momentProperties) {
                prop = momentProperties[i];
                val = from[prop];
                if (!isUndefined(val)) {
                    to[prop] = val;
                }
            }
        }
        return to;
    }
    var updateInProgress = false;
    // Moment prototype object
    function Moment(config) {
        copyConfig(this, config);
        this._d = new Date(config._d != null ? config._d.getTime() : NaN);
        // Prevent infinite loop in case updateOffset creates new moment
        // objects.
        if (updateInProgress === false) {
            updateInProgress = true;
            utils_hooks__hooks.updateOffset(this);
            updateInProgress = false;
        }
    }
    function isMoment(obj) {
        return obj instanceof Moment || (obj != null && obj._isAMomentObject != null);
    }
    function absFloor(number) {
        if (number < 0) {
            // -0 -> 0
            return Math.ceil(number) || 0;
        }
        else {
            return Math.floor(number);
        }
    }
    function toInt(argumentForCoercion) {
        var coercedNumber = +argumentForCoercion, value = 0;
        if (coercedNumber !== 0 && isFinite(coercedNumber)) {
            value = absFloor(coercedNumber);
        }
        return value;
    }
    // compare two arrays, return the number of differences
    function compareArrays(array1, array2, dontConvert) {
        var len = Math.min(array1.length, array2.length), lengthDiff = Math.abs(array1.length - array2.length), diffs = 0, i;
        for (i = 0; i < len; i++) {
            if ((dontConvert && array1[i] !== array2[i]) ||
                (!dontConvert && toInt(array1[i]) !== toInt(array2[i]))) {
                diffs++;
            }
        }
        return diffs + lengthDiff;
    }
    function warn(msg) {
        if (utils_hooks__hooks.suppressDeprecationWarnings === false &&
            (typeof console !== 'undefined') && console.warn) {
            console.warn('Deprecation warning: ' + msg);
        }
    }
    function deprecate(msg, fn) {
        var firstTime = true;
        return extend(function () {
            if (utils_hooks__hooks.deprecationHandler != null) {
                utils_hooks__hooks.deprecationHandler(null, msg);
            }
            if (firstTime) {
                warn(msg + '\nArguments: ' + Array.prototype.slice.call(arguments).join(', ') + '\n' + (new Error()).stack);
                firstTime = false;
            }
            return fn.apply(this, arguments);
        }, fn);
    }
    var deprecations = {};
    function deprecateSimple(name, msg) {
        if (utils_hooks__hooks.deprecationHandler != null) {
            utils_hooks__hooks.deprecationHandler(name, msg);
        }
        if (!deprecations[name]) {
            warn(msg);
            deprecations[name] = true;
        }
    }
    utils_hooks__hooks.suppressDeprecationWarnings = false;
    utils_hooks__hooks.deprecationHandler = null;
    function isFunction(input) {
        return input instanceof Function || Object.prototype.toString.call(input) === '[object Function]';
    }
    function locale_set__set(config) {
        var prop, i;
        for (i in config) {
            prop = config[i];
            if (isFunction(prop)) {
                this[i] = prop;
            }
            else {
                this['_' + i] = prop;
            }
        }
        this._config = config;
        // Lenient ordinal parsing accepts just a number in addition to
        // number + (possibly) stuff coming from _ordinalParseLenient.
        this._ordinalParseLenient = new RegExp(this._ordinalParse.source + '|' + (/\d{1,2}/).source);
    }
    function mergeConfigs(parentConfig, childConfig) {
        var res = extend({}, parentConfig), prop;
        for (prop in childConfig) {
            if (hasOwnProp(childConfig, prop)) {
                if (isObject(parentConfig[prop]) && isObject(childConfig[prop])) {
                    res[prop] = {};
                    extend(res[prop], parentConfig[prop]);
                    extend(res[prop], childConfig[prop]);
                }
                else if (childConfig[prop] != null) {
                    res[prop] = childConfig[prop];
                }
                else {
                    delete res[prop];
                }
            }
        }
        for (prop in parentConfig) {
            if (hasOwnProp(parentConfig, prop) &&
                !hasOwnProp(childConfig, prop) &&
                isObject(parentConfig[prop])) {
                // make sure changes to properties don't modify parent config
                res[prop] = extend({}, res[prop]);
            }
        }
        return res;
    }
    function Locale(config) {
        if (config != null) {
            this.set(config);
        }
    }
    var keys;
    if (Object.keys) {
        keys = Object.keys;
    }
    else {
        keys = function (obj) {
            var i, res = [];
            for (i in obj) {
                if (hasOwnProp(obj, i)) {
                    res.push(i);
                }
            }
            return res;
        };
    }
    var defaultCalendar = {
        sameDay: '[Today at] LT',
        nextDay: '[Tomorrow at] LT',
        nextWeek: 'dddd [at] LT',
        lastDay: '[Yesterday at] LT',
        lastWeek: '[Last] dddd [at] LT',
        sameElse: 'L'
    };
    function locale_calendar__calendar(key, mom, now) {
        var output = this._calendar[key] || this._calendar['sameElse'];
        return isFunction(output) ? output.call(mom, now) : output;
    }
    var defaultLongDateFormat = {
        LTS: 'h:mm:ss A',
        LT: 'h:mm A',
        L: 'MM/DD/YYYY',
        LL: 'MMMM D, YYYY',
        LLL: 'MMMM D, YYYY h:mm A',
        LLLL: 'dddd, MMMM D, YYYY h:mm A'
    };
    function longDateFormat(key) {
        var format = this._longDateFormat[key], formatUpper = this._longDateFormat[key.toUpperCase()];
        if (format || !formatUpper) {
            return format;
        }
        this._longDateFormat[key] = formatUpper.replace(/MMMM|MM|DD|dddd/g, function (val) {
            return val.slice(1);
        });
        return this._longDateFormat[key];
    }
    var defaultInvalidDate = 'Invalid date';
    function invalidDate() {
        return this._invalidDate;
    }
    var defaultOrdinal = '%d';
    var defaultOrdinalParse = /\d{1,2}/;
    function ordinal(number) {
        return this._ordinal.replace('%d', number);
    }
    var defaultRelativeTime = {
        future: 'in %s',
        past: '%s ago',
        s: 'a few seconds',
        m: 'a minute',
        mm: '%d minutes',
        h: 'an hour',
        hh: '%d hours',
        d: 'a day',
        dd: '%d days',
        M: 'a month',
        MM: '%d months',
        y: 'a year',
        yy: '%d years'
    };
    function relative__relativeTime(number, withoutSuffix, string, isFuture) {
        var output = this._relativeTime[string];
        return (isFunction(output)) ?
            output(number, withoutSuffix, string, isFuture) :
            output.replace(/%d/i, number);
    }
    function pastFuture(diff, output) {
        var format = this._relativeTime[diff > 0 ? 'future' : 'past'];
        return isFunction(format) ? format(output) : format.replace(/%s/i, output);
    }
    var aliases = {};
    function addUnitAlias(unit, shorthand) {
        var lowerCase = unit.toLowerCase();
        aliases[lowerCase] = aliases[lowerCase + 's'] = aliases[shorthand] = unit;
    }
    function normalizeUnits(units) {
        return typeof units === 'string' ? aliases[units] || aliases[units.toLowerCase()] : undefined;
    }
    function normalizeObjectUnits(inputObject) {
        var normalizedInput = {}, normalizedProp, prop;
        for (prop in inputObject) {
            if (hasOwnProp(inputObject, prop)) {
                normalizedProp = normalizeUnits(prop);
                if (normalizedProp) {
                    normalizedInput[normalizedProp] = inputObject[prop];
                }
            }
        }
        return normalizedInput;
    }
    var priorities = {};
    function addUnitPriority(unit, priority) {
        priorities[unit] = priority;
    }
    function getPrioritizedUnits(unitsObj) {
        var units = [];
        for (var u in unitsObj) {
            units.push({ unit: u, priority: priorities[u] });
        }
        units.sort(function (a, b) {
            return a.priority - b.priority;
        });
        return units;
    }
    function makeGetSet(unit, keepTime) {
        return function (value) {
            if (value != null) {
                get_set__set(this, unit, value);
                utils_hooks__hooks.updateOffset(this, keepTime);
                return this;
            }
            else {
                return get_set__get(this, unit);
            }
        };
    }
    function get_set__get(mom, unit) {
        return mom.isValid() ?
            mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit]() : NaN;
    }
    function get_set__set(mom, unit, value) {
        if (mom.isValid()) {
            mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value);
        }
    }
    // MOMENTS
    function stringGet(units) {
        units = normalizeUnits(units);
        if (isFunction(this[units])) {
            return this[units]();
        }
        return this;
    }
    function stringSet(units, value) {
        if (typeof units === 'object') {
            units = normalizeObjectUnits(units);
            var prioritized = getPrioritizedUnits(units);
            for (var i = 0; i < prioritized.length; i++) {
                this[prioritized[i].unit](units[prioritized[i].unit]);
            }
        }
        else {
            units = normalizeUnits(units);
            if (isFunction(this[units])) {
                return this[units](value);
            }
        }
        return this;
    }
    function zeroFill(number, targetLength, forceSign) {
        var absNumber = '' + Math.abs(number), zerosToFill = targetLength - absNumber.length, sign = number >= 0;
        return (sign ? (forceSign ? '+' : '') : '-') +
            Math.pow(10, Math.max(0, zerosToFill)).toString().substr(1) + absNumber;
    }
    var formattingTokens = /(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g;
    var localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g;
    var formatFunctions = {};
    var formatTokenFunctions = {};
    // token:    'M'
    // padded:   ['MM', 2]
    // ordinal:  'Mo'
    // callback: function () { this.month() + 1 }
    function addFormatToken(token, padded, ordinal, callback) {
        var func = callback;
        if (typeof callback === 'string') {
            func = function () {
                return this[callback]();
            };
        }
        if (token) {
            formatTokenFunctions[token] = func;
        }
        if (padded) {
            formatTokenFunctions[padded[0]] = function () {
                return zeroFill(func.apply(this, arguments), padded[1], padded[2]);
            };
        }
        if (ordinal) {
            formatTokenFunctions[ordinal] = function () {
                return this.localeData().ordinal(func.apply(this, arguments), token);
            };
        }
    }
    function removeFormattingTokens(input) {
        if (input.match(/\[[\s\S]/)) {
            return input.replace(/^\[|\]$/g, '');
        }
        return input.replace(/\\/g, '');
    }
    function makeFormatFunction(format) {
        var array = format.match(formattingTokens), i, length;
        for (i = 0, length = array.length; i < length; i++) {
            if (formatTokenFunctions[array[i]]) {
                array[i] = formatTokenFunctions[array[i]];
            }
            else {
                array[i] = removeFormattingTokens(array[i]);
            }
        }
        return function (mom) {
            var output = '', i;
            for (i = 0; i < length; i++) {
                output += array[i] instanceof Function ? array[i].call(mom, format) : array[i];
            }
            return output;
        };
    }
    // format date using native date object
    function formatMoment(m, format) {
        if (!m.isValid()) {
            return m.localeData().invalidDate();
        }
        format = expandFormat(format, m.localeData());
        formatFunctions[format] = formatFunctions[format] || makeFormatFunction(format);
        return formatFunctions[format](m);
    }
    function expandFormat(format, locale) {
        var i = 5;
        function replaceLongDateFormatTokens(input) {
            return locale.longDateFormat(input) || input;
        }
        localFormattingTokens.lastIndex = 0;
        while (i >= 0 && localFormattingTokens.test(format)) {
            format = format.replace(localFormattingTokens, replaceLongDateFormatTokens);
            localFormattingTokens.lastIndex = 0;
            i -= 1;
        }
        return format;
    }
    var match1 = /\d/; //       0 - 9
    var match2 = /\d\d/; //      00 - 99
    var match3 = /\d{3}/; //     000 - 999
    var match4 = /\d{4}/; //    0000 - 9999
    var match6 = /[+-]?\d{6}/; // -999999 - 999999
    var match1to2 = /\d\d?/; //       0 - 99
    var match3to4 = /\d\d\d\d?/; //     999 - 9999
    var match5to6 = /\d\d\d\d\d\d?/; //   99999 - 999999
    var match1to3 = /\d{1,3}/; //       0 - 999
    var match1to4 = /\d{1,4}/; //       0 - 9999
    var match1to6 = /[+-]?\d{1,6}/; // -999999 - 999999
    var matchUnsigned = /\d+/; //       0 - inf
    var matchSigned = /[+-]?\d+/; //    -inf - inf
    var matchOffset = /Z|[+-]\d\d:?\d\d/gi; // +00:00 -00:00 +0000 -0000 or Z
    var matchShortOffset = /Z|[+-]\d\d(?::?\d\d)?/gi; // +00 -00 +00:00 -00:00 +0000 -0000 or Z
    var matchTimestamp = /[+-]?\d+(\.\d{1,3})?/; // 123456789 123456789.123
    // any word (or two) characters or numbers including two/three word month in arabic.
    // includes scottish gaelic two word and hyphenated months
    var matchWord = /[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i;
    var regexes = {};
    function addRegexToken(token, regex, strictRegex) {
        regexes[token] = isFunction(regex) ? regex : function (isStrict, localeData) {
            return (isStrict && strictRegex) ? strictRegex : regex;
        };
    }
    function getParseRegexForToken(token, config) {
        if (!hasOwnProp(regexes, token)) {
            return new RegExp(unescapeFormat(token));
        }
        return regexes[token](config._strict, config._locale);
    }
    // Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript
    function unescapeFormat(s) {
        return regexEscape(s.replace('\\', '').replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) {
            return p1 || p2 || p3 || p4;
        }));
    }
    function regexEscape(s) {
        return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
    }
    var tokens = {};
    function addParseToken(token, callback) {
        var i, func = callback;
        if (typeof token === 'string') {
            token = [token];
        }
        if (typeof callback === 'number') {
            func = function (input, array) {
                array[callback] = toInt(input);
            };
        }
        for (i = 0; i < token.length; i++) {
            tokens[token[i]] = func;
        }
    }
    function addWeekParseToken(token, callback) {
        addParseToken(token, function (input, array, config, token) {
            config._w = config._w || {};
            callback(input, config._w, config, token);
        });
    }
    function addTimeToArrayFromToken(token, input, config) {
        if (input != null && hasOwnProp(tokens, token)) {
            tokens[token](input, config._a, config, token);
        }
    }
    var YEAR = 0;
    var MONTH = 1;
    var DATE = 2;
    var HOUR = 3;
    var MINUTE = 4;
    var SECOND = 5;
    var MILLISECOND = 6;
    var WEEK = 7;
    var WEEKDAY = 8;
    var indexOf;
    if (Array.prototype.indexOf) {
        indexOf = Array.prototype.indexOf;
    }
    else {
        indexOf = function (o) {
            // I know
            var i;
            for (i = 0; i < this.length; ++i) {
                if (this[i] === o) {
                    return i;
                }
            }
            return -1;
        };
    }
    function daysInMonth(year, month) {
        return new Date(Date.UTC(year, month + 1, 0)).getUTCDate();
    }
    // FORMATTING
    addFormatToken('M', ['MM', 2], 'Mo', function () {
        return this.month() + 1;
    });
    addFormatToken('MMM', 0, 0, function (format) {
        return this.localeData().monthsShort(this, format);
    });
    addFormatToken('MMMM', 0, 0, function (format) {
        return this.localeData().months(this, format);
    });
    // ALIASES
    addUnitAlias('month', 'M');
    // PRIORITY
    addUnitPriority('month', 8);
    // PARSING
    addRegexToken('M', match1to2);
    addRegexToken('MM', match1to2, match2);
    addRegexToken('MMM', function (isStrict, locale) {
        return locale.monthsShortRegex(isStrict);
    });
    addRegexToken('MMMM', function (isStrict, locale) {
        return locale.monthsRegex(isStrict);
    });
    addParseToken(['M', 'MM'], function (input, array) {
        array[MONTH] = toInt(input) - 1;
    });
    addParseToken(['MMM', 'MMMM'], function (input, array, config, token) {
        var month = config._locale.monthsParse(input, token, config._strict);
        // if we didn't find a month name, mark the date as invalid.
        if (month != null) {
            array[MONTH] = month;
        }
        else {
            getParsingFlags(config).invalidMonth = input;
        }
    });
    // LOCALES
    var MONTHS_IN_FORMAT = /D[oD]?(\[[^\[\]]*\]|\s+)+MMMM?/;
    var defaultLocaleMonths = 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_');
    function localeMonths(m, format) {
        return isArray(this._months) ? this._months[m.month()] :
            this._months[(this._months.isFormat || MONTHS_IN_FORMAT).test(format) ? 'format' : 'standalone'][m.month()];
    }
    var defaultLocaleMonthsShort = 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_');
    function localeMonthsShort(m, format) {
        return isArray(this._monthsShort) ? this._monthsShort[m.month()] :
            this._monthsShort[MONTHS_IN_FORMAT.test(format) ? 'format' : 'standalone'][m.month()];
    }
    function units_month__handleStrictParse(monthName, format, strict) {
        var i, ii, mom, llc = monthName.toLocaleLowerCase();
        if (!this._monthsParse) {
            // this is not used
            this._monthsParse = [];
            this._longMonthsParse = [];
            this._shortMonthsParse = [];
            for (i = 0; i < 12; ++i) {
                mom = create_utc__createUTC([2000, i]);
                this._shortMonthsParse[i] = this.monthsShort(mom, '').toLocaleLowerCase();
                this._longMonthsParse[i] = this.months(mom, '').toLocaleLowerCase();
            }
        }
        if (strict) {
            if (format === 'MMM') {
                ii = indexOf.call(this._shortMonthsParse, llc);
                return ii !== -1 ? ii : null;
            }
            else {
                ii = indexOf.call(this._longMonthsParse, llc);
                return ii !== -1 ? ii : null;
            }
        }
        else {
            if (format === 'MMM') {
                ii = indexOf.call(this._shortMonthsParse, llc);
                if (ii !== -1) {
                    return ii;
                }
                ii = indexOf.call(this._longMonthsParse, llc);
                return ii !== -1 ? ii : null;
            }
            else {
                ii = indexOf.call(this._longMonthsParse, llc);
                if (ii !== -1) {
                    return ii;
                }
                ii = indexOf.call(this._shortMonthsParse, llc);
                return ii !== -1 ? ii : null;
            }
        }
    }
    function localeMonthsParse(monthName, format, strict) {
        var i, mom, regex;
        if (this._monthsParseExact) {
            return units_month__handleStrictParse.call(this, monthName, format, strict);
        }
        if (!this._monthsParse) {
            this._monthsParse = [];
            this._longMonthsParse = [];
            this._shortMonthsParse = [];
        }
        // TODO: add sorting
        // Sorting makes sure if one month (or abbr) is a prefix of another
        // see sorting in computeMonthsParse
        for (i = 0; i < 12; i++) {
            // make the regex if we don't have it already
            mom = create_utc__createUTC([2000, i]);
            if (strict && !this._longMonthsParse[i]) {
                this._longMonthsParse[i] = new RegExp('^' + this.months(mom, '').replace('.', '') + '$', 'i');
                this._shortMonthsParse[i] = new RegExp('^' + this.monthsShort(mom, '').replace('.', '') + '$', 'i');
            }
            if (!strict && !this._monthsParse[i]) {
                regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, '');
                this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i');
            }
            // test the regex
            if (strict && format === 'MMMM' && this._longMonthsParse[i].test(monthName)) {
                return i;
            }
            else if (strict && format === 'MMM' && this._shortMonthsParse[i].test(monthName)) {
                return i;
            }
            else if (!strict && this._monthsParse[i].test(monthName)) {
                return i;
            }
        }
    }
    // MOMENTS
    function setMonth(mom, value) {
        var dayOfMonth;
        if (!mom.isValid()) {
            // No op
            return mom;
        }
        if (typeof value === 'string') {
            if (/^\d+$/.test(value)) {
                value = toInt(value);
            }
            else {
                value = mom.localeData().monthsParse(value);
                // TODO: Another silent failure?
                if (typeof value !== 'number') {
                    return mom;
                }
            }
        }
        dayOfMonth = Math.min(mom.date(), daysInMonth(mom.year(), value));
        mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth);
        return mom;
    }
    function getSetMonth(value) {
        if (value != null) {
            setMonth(this, value);
            utils_hooks__hooks.updateOffset(this, true);
            return this;
        }
        else {
            return get_set__get(this, 'Month');
        }
    }
    function getDaysInMonth() {
        return daysInMonth(this.year(), this.month());
    }
    var defaultMonthsShortRegex = matchWord;
    function monthsShortRegex(isStrict) {
        if (this._monthsParseExact) {
            if (!hasOwnProp(this, '_monthsRegex')) {
                computeMonthsParse.call(this);
            }
            if (isStrict) {
                return this._monthsShortStrictRegex;
            }
            else {
                return this._monthsShortRegex;
            }
        }
        else {
            if (!hasOwnProp(this, '_monthsShortRegex')) {
                this._monthsShortRegex = defaultMonthsShortRegex;
            }
            return this._monthsShortStrictRegex && isStrict ?
                this._monthsShortStrictRegex : this._monthsShortRegex;
        }
    }
    var defaultMonthsRegex = matchWord;
    function monthsRegex(isStrict) {
        if (this._monthsParseExact) {
            if (!hasOwnProp(this, '_monthsRegex')) {
                computeMonthsParse.call(this);
            }
            if (isStrict) {
                return this._monthsStrictRegex;
            }
            else {
                return this._monthsRegex;
            }
        }
        else {
            if (!hasOwnProp(this, '_monthsRegex')) {
                this._monthsRegex = defaultMonthsRegex;
            }
            return this._monthsStrictRegex && isStrict ?
                this._monthsStrictRegex : this._monthsRegex;
        }
    }
    function computeMonthsParse() {
        function cmpLenRev(a, b) {
            return b.length - a.length;
        }
        var shortPieces = [], longPieces = [], mixedPieces = [], i, mom;
        for (i = 0; i < 12; i++) {
            // make the regex if we don't have it already
            mom = create_utc__createUTC([2000, i]);
            shortPieces.push(this.monthsShort(mom, ''));
            longPieces.push(this.months(mom, ''));
            mixedPieces.push(this.months(mom, ''));
            mixedPieces.push(this.monthsShort(mom, ''));
        }
        // Sorting makes sure if one month (or abbr) is a prefix of another it
        // will match the longer piece.
        shortPieces.sort(cmpLenRev);
        longPieces.sort(cmpLenRev);
        mixedPieces.sort(cmpLenRev);
        for (i = 0; i < 12; i++) {
            shortPieces[i] = regexEscape(shortPieces[i]);
            longPieces[i] = regexEscape(longPieces[i]);
        }
        for (i = 0; i < 24; i++) {
            mixedPieces[i] = regexEscape(mixedPieces[i]);
        }
        this._monthsRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');
        this._monthsShortRegex = this._monthsRegex;
        this._monthsStrictRegex = new RegExp('^(' + longPieces.join('|') + ')', 'i');
        this._monthsShortStrictRegex = new RegExp('^(' + shortPieces.join('|') + ')', 'i');
    }
    // FORMATTING
    addFormatToken('Y', 0, 0, function () {
        var y = this.year();
        return y <= 9999 ? '' + y : '+' + y;
    });
    addFormatToken(0, ['YY', 2], 0, function () {
        return this.year() % 100;
    });
    addFormatToken(0, ['YYYY', 4], 0, 'year');
    addFormatToken(0, ['YYYYY', 5], 0, 'year');
    addFormatToken(0, ['YYYYYY', 6, true], 0, 'year');
    // ALIASES
    addUnitAlias('year', 'y');
    // PRIORITIES
    addUnitPriority('year', 1);
    // PARSING
    addRegexToken('Y', matchSigned);
    addRegexToken('YY', match1to2, match2);
    addRegexToken('YYYY', match1to4, match4);
    addRegexToken('YYYYY', match1to6, match6);
    addRegexToken('YYYYYY', match1to6, match6);
    addParseToken(['YYYYY', 'YYYYYY'], YEAR);
    addParseToken('YYYY', function (input, array) {
        array[YEAR] = input.length === 2 ? utils_hooks__hooks.parseTwoDigitYear(input) : toInt(input);
    });
    addParseToken('YY', function (input, array) {
        array[YEAR] = utils_hooks__hooks.parseTwoDigitYear(input);
    });
    addParseToken('Y', function (input, array) {
        array[YEAR] = parseInt(input, 10);
    });
    // HELPERS
    function daysInYear(year) {
        return isLeapYear(year) ? 366 : 365;
    }
    function isLeapYear(year) {
        return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
    }
    // HOOKS
    utils_hooks__hooks.parseTwoDigitYear = function (input) {
        return toInt(input) + (toInt(input) > 68 ? 1900 : 2000);
    };
    // MOMENTS
    var getSetYear = makeGetSet('FullYear', true);
    function getIsLeapYear() {
        return isLeapYear(this.year());
    }
    function createDate(y, m, d, h, M, s, ms) {
        //can't just apply() to create a date:
        //http://stackoverflow.com/questions/181348/instantiating-a-javascript-object-by-calling-prototype-constructor-apply
        var date = new Date(y, m, d, h, M, s, ms);
        //the date constructor remaps years 0-99 to 1900-1999
        if (y < 100 && y >= 0 && isFinite(date.getFullYear())) {
            date.setFullYear(y);
        }
        return date;
    }
    function createUTCDate(y) {
        var date = new Date(Date.UTC.apply(null, arguments));
        //the Date.UTC function remaps years 0-99 to 1900-1999
        if (y < 100 && y >= 0 && isFinite(date.getUTCFullYear())) {
            date.setUTCFullYear(y);
        }
        return date;
    }
    // start-of-first-week - start-of-year
    function firstWeekOffset(year, dow, doy) {
        var // first-week day -- which january is always in the first week (4 for iso, 1 for other)
        fwd = 7 + dow - doy, 
        // first-week day local weekday -- which local weekday is fwd
        fwdlw = (7 + createUTCDate(year, 0, fwd).getUTCDay() - dow) % 7;
        return -fwdlw + fwd - 1;
    }
    //http://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday
    function dayOfYearFromWeeks(year, week, weekday, dow, doy) {
        var localWeekday = (7 + weekday - dow) % 7, weekOffset = firstWeekOffset(year, dow, doy), dayOfYear = 1 + 7 * (week - 1) + localWeekday + weekOffset, resYear, resDayOfYear;
        if (dayOfYear <= 0) {
            resYear = year - 1;
            resDayOfYear = daysInYear(resYear) + dayOfYear;
        }
        else if (dayOfYear > daysInYear(year)) {
            resYear = year + 1;
            resDayOfYear = dayOfYear - daysInYear(year);
        }
        else {
            resYear = year;
            resDayOfYear = dayOfYear;
        }
        return {
            year: resYear,
            dayOfYear: resDayOfYear
        };
    }
    function weekOfYear(mom, dow, doy) {
        var weekOffset = firstWeekOffset(mom.year(), dow, doy), week = Math.floor((mom.dayOfYear() - weekOffset - 1) / 7) + 1, resWeek, resYear;
        if (week < 1) {
            resYear = mom.year() - 1;
            resWeek = week + weeksInYear(resYear, dow, doy);
        }
        else if (week > weeksInYear(mom.year(), dow, doy)) {
            resWeek = week - weeksInYear(mom.year(), dow, doy);
            resYear = mom.year() + 1;
        }
        else {
            resYear = mom.year();
            resWeek = week;
        }
        return {
            week: resWeek,
            year: resYear
        };
    }
    function weeksInYear(year, dow, doy) {
        var weekOffset = firstWeekOffset(year, dow, doy), weekOffsetNext = firstWeekOffset(year + 1, dow, doy);
        return (daysInYear(year) - weekOffset + weekOffsetNext) / 7;
    }
    // FORMATTING
    addFormatToken('w', ['ww', 2], 'wo', 'week');
    addFormatToken('W', ['WW', 2], 'Wo', 'isoWeek');
    // ALIASES
    addUnitAlias('week', 'w');
    addUnitAlias('isoWeek', 'W');
    // PRIORITIES
    addUnitPriority('week', 5);
    addUnitPriority('isoWeek', 5);
    // PARSING
    addRegexToken('w', match1to2);
    addRegexToken('ww', match1to2, match2);
    addRegexToken('W', match1to2);
    addRegexToken('WW', match1to2, match2);
    addWeekParseToken(['w', 'ww', 'W', 'WW'], function (input, week, config, token) {
        week[token.substr(0, 1)] = toInt(input);
    });
    // HELPERS
    // LOCALES
    function localeWeek(mom) {
        return weekOfYear(mom, this._week.dow, this._week.doy).week;
    }
    var defaultLocaleWeek = {
        dow: 0,
        doy: 6 // The week that contains Jan 1st is the first week of the year.
    };
    function localeFirstDayOfWeek() {
        return this._week.dow;
    }
    function localeFirstDayOfYear() {
        return this._week.doy;
    }
    // MOMENTS
    function getSetWeek(input) {
        var week = this.localeData().week(this);
        return input == null ? week : this.add((input - week) * 7, 'd');
    }
    function getSetISOWeek(input) {
        var week = weekOfYear(this, 1, 4).week;
        return input == null ? week : this.add((input - week) * 7, 'd');
    }
    // FORMATTING
    addFormatToken('d', 0, 'do', 'day');
    addFormatToken('dd', 0, 0, function (format) {
        return this.localeData().weekdaysMin(this, format);
    });
    addFormatToken('ddd', 0, 0, function (format) {
        return this.localeData().weekdaysShort(this, format);
    });
    addFormatToken('dddd', 0, 0, function (format) {
        return this.localeData().weekdays(this, format);
    });
    addFormatToken('e', 0, 0, 'weekday');
    addFormatToken('E', 0, 0, 'isoWeekday');
    // ALIASES
    addUnitAlias('day', 'd');
    addUnitAlias('weekday', 'e');
    addUnitAlias('isoWeekday', 'E');
    // PRIORITY
    addUnitPriority('day', 11);
    addUnitPriority('weekday', 11);
    addUnitPriority('isoWeekday', 11);
    // PARSING
    addRegexToken('d', match1to2);
    addRegexToken('e', match1to2);
    addRegexToken('E', match1to2);
    addRegexToken('dd', function (isStrict, locale) {
        return locale.weekdaysMinRegex(isStrict);
    });
    addRegexToken('ddd', function (isStrict, locale) {
        return locale.weekdaysShortRegex(isStrict);
    });
    addRegexToken('dddd', function (isStrict, locale) {
        return locale.weekdaysRegex(isStrict);
    });
    addWeekParseToken(['dd', 'ddd', 'dddd'], function (input, week, config, token) {
        var weekday = config._locale.weekdaysParse(input, token, config._strict);
        // if we didn't get a weekday name, mark the date as invalid
        if (weekday != null) {
            week.d = weekday;
        }
        else {
            getParsingFlags(config).invalidWeekday = input;
        }
    });
    addWeekParseToken(['d', 'e', 'E'], function (input, week, config, token) {
        week[token] = toInt(input);
    });
    // HELPERS
    function parseWeekday(input, locale) {
        if (typeof input !== 'string') {
            return input;
        }
        if (!isNaN(input)) {
            return parseInt(input, 10);
        }
        input = locale.weekdaysParse(input);
        if (typeof input === 'number') {
            return input;
        }
        return null;
    }
    function parseIsoWeekday(input, locale) {
        if (typeof input === 'string') {
            return locale.weekdaysParse(input) % 7 || 7;
        }
        return isNaN(input) ? null : input;
    }
    // LOCALES
    var defaultLocaleWeekdays = 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_');
    function localeWeekdays(m, format) {
        return isArray(this._weekdays) ? this._weekdays[m.day()] :
            this._weekdays[this._weekdays.isFormat.test(format) ? 'format' : 'standalone'][m.day()];
    }
    var defaultLocaleWeekdaysShort = 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_');
    function localeWeekdaysShort(m) {
        return this._weekdaysShort[m.day()];
    }
    var defaultLocaleWeekdaysMin = 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_');
    function localeWeekdaysMin(m) {
        return this._weekdaysMin[m.day()];
    }
    function day_of_week__handleStrictParse(weekdayName, format, strict) {
        var i, ii, mom, llc = weekdayName.toLocaleLowerCase();
        if (!this._weekdaysParse) {
            this._weekdaysParse = [];
            this._shortWeekdaysParse = [];
            this._minWeekdaysParse = [];
            for (i = 0; i < 7; ++i) {
                mom = create_utc__createUTC([2000, 1]).day(i);
                this._minWeekdaysParse[i] = this.weekdaysMin(mom, '').toLocaleLowerCase();
                this._shortWeekdaysParse[i] = this.weekdaysShort(mom, '').toLocaleLowerCase();
                this._weekdaysParse[i] = this.weekdays(mom, '').toLocaleLowerCase();
            }
        }
        if (strict) {
            if (format === 'dddd') {
                ii = indexOf.call(this._weekdaysParse, llc);
                return ii !== -1 ? ii : null;
            }
            else if (format === 'ddd') {
                ii = indexOf.call(this._shortWeekdaysParse, llc);
                return ii !== -1 ? ii : null;
            }
            else {
                ii = indexOf.call(this._minWeekdaysParse, llc);
                return ii !== -1 ? ii : null;
            }
        }
        else {
            if (format === 'dddd') {
                ii = indexOf.call(this._weekdaysParse, llc);
                if (ii !== -1) {
                    return ii;
                }
                ii = indexOf.call(this._shortWeekdaysParse, llc);
                if (ii !== -1) {
                    return ii;
                }
                ii = indexOf.call(this._minWeekdaysParse, llc);
                return ii !== -1 ? ii : null;
            }
            else if (format === 'ddd') {
                ii = indexOf.call(this._shortWeekdaysParse, llc);
                if (ii !== -1) {
                    return ii;
                }
                ii = indexOf.call(this._weekdaysParse, llc);
                if (ii !== -1) {
                    return ii;
                }
                ii = indexOf.call(this._minWeekdaysParse, llc);
                return ii !== -1 ? ii : null;
            }
            else {
                ii = indexOf.call(this._minWeekdaysParse, llc);
                if (ii !== -1) {
                    return ii;
                }
                ii = indexOf.call(this._weekdaysParse, llc);
                if (ii !== -1) {
                    return ii;
                }
                ii = indexOf.call(this._shortWeekdaysParse, llc);
                return ii !== -1 ? ii : null;
            }
        }
    }
    function localeWeekdaysParse(weekdayName, format, strict) {
        var i, mom, regex;
        if (this._weekdaysParseExact) {
            return day_of_week__handleStrictParse.call(this, weekdayName, format, strict);
        }
        if (!this._weekdaysParse) {
            this._weekdaysParse = [];
            this._minWeekdaysParse = [];
            this._shortWeekdaysParse = [];
            this._fullWeekdaysParse = [];
        }
        for (i = 0; i < 7; i++) {
            // make the regex if we don't have it already
            mom = create_utc__createUTC([2000, 1]).day(i);
            if (strict && !this._fullWeekdaysParse[i]) {
                this._fullWeekdaysParse[i] = new RegExp('^' + this.weekdays(mom, '').replace('.', '\.?') + '$', 'i');
                this._shortWeekdaysParse[i] = new RegExp('^' + this.weekdaysShort(mom, '').replace('.', '\.?') + '$', 'i');
                this._minWeekdaysParse[i] = new RegExp('^' + this.weekdaysMin(mom, '').replace('.', '\.?') + '$', 'i');
            }
            if (!this._weekdaysParse[i]) {
                regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, '');
                this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i');
            }
            // test the regex
            if (strict && format === 'dddd' && this._fullWeekdaysParse[i].test(weekdayName)) {
                return i;
            }
            else if (strict && format === 'ddd' && this._shortWeekdaysParse[i].test(weekdayName)) {
                return i;
            }
            else if (strict && format === 'dd' && this._minWeekdaysParse[i].test(weekdayName)) {
                return i;
            }
            else if (!strict && this._weekdaysParse[i].test(weekdayName)) {
                return i;
            }
        }
    }
    // MOMENTS
    function getSetDayOfWeek(input) {
        if (!this.isValid()) {
            return input != null ? this : NaN;
        }
        var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay();
        if (input != null) {
            input = parseWeekday(input, this.localeData());
            return this.add(input - day, 'd');
        }
        else {
            return day;
        }
    }
    function getSetLocaleDayOfWeek(input) {
        if (!this.isValid()) {
            return input != null ? this : NaN;
        }
        var weekday = (this.day() + 7 - this.localeData()._week.dow) % 7;
        return input == null ? weekday : this.add(input - weekday, 'd');
    }
    function getSetISODayOfWeek(input) {
        if (!this.isValid()) {
            return input != null ? this : NaN;
        }
        // behaves the same as moment#day except
        // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6)
        // as a setter, sunday should belong to the previous week.
        if (input != null) {
            var weekday = parseIsoWeekday(input, this.localeData());
            return this.day(this.day() % 7 ? weekday : weekday - 7);
        }
        else {
            return this.day() || 7;
        }
    }
    var defaultWeekdaysRegex = matchWord;
    function weekdaysRegex(isStrict) {
        if (this._weekdaysParseExact) {
            if (!hasOwnProp(this, '_weekdaysRegex')) {
                computeWeekdaysParse.call(this);
            }
            if (isStrict) {
                return this._weekdaysStrictRegex;
            }
            else {
                return this._weekdaysRegex;
            }
        }
        else {
            if (!hasOwnProp(this, '_weekdaysRegex')) {
                this._weekdaysRegex = defaultWeekdaysRegex;
            }
            return this._weekdaysStrictRegex && isStrict ?
                this._weekdaysStrictRegex : this._weekdaysRegex;
        }
    }
    var defaultWeekdaysShortRegex = matchWord;
    function weekdaysShortRegex(isStrict) {
        if (this._weekdaysParseExact) {
            if (!hasOwnProp(this, '_weekdaysRegex')) {
                computeWeekdaysParse.call(this);
            }
            if (isStrict) {
                return this._weekdaysShortStrictRegex;
            }
            else {
                return this._weekdaysShortRegex;
            }
        }
        else {
            if (!hasOwnProp(this, '_weekdaysShortRegex')) {
                this._weekdaysShortRegex = defaultWeekdaysShortRegex;
            }
            return this._weekdaysShortStrictRegex && isStrict ?
                this._weekdaysShortStrictRegex : this._weekdaysShortRegex;
        }
    }
    var defaultWeekdaysMinRegex = matchWord;
    function weekdaysMinRegex(isStrict) {
        if (this._weekdaysParseExact) {
            if (!hasOwnProp(this, '_weekdaysRegex')) {
                computeWeekdaysParse.call(this);
            }
            if (isStrict) {
                return this._weekdaysMinStrictRegex;
            }
            else {
                return this._weekdaysMinRegex;
            }
        }
        else {
            if (!hasOwnProp(this, '_weekdaysMinRegex')) {
                this._weekdaysMinRegex = defaultWeekdaysMinRegex;
            }
            return this._weekdaysMinStrictRegex && isStrict ?
                this._weekdaysMinStrictRegex : this._weekdaysMinRegex;
        }
    }
    function computeWeekdaysParse() {
        function cmpLenRev(a, b) {
            return b.length - a.length;
        }
        var minPieces = [], shortPieces = [], longPieces = [], mixedPieces = [], i, mom, minp, shortp, longp;
        for (i = 0; i < 7; i++) {
            // make the regex if we don't have it already
            mom = create_utc__createUTC([2000, 1]).day(i);
            minp = this.weekdaysMin(mom, '');
            shortp = this.weekdaysShort(mom, '');
            longp = this.weekdays(mom, '');
            minPieces.push(minp);
            shortPieces.push(shortp);
            longPieces.push(longp);
            mixedPieces.push(minp);
            mixedPieces.push(shortp);
            mixedPieces.push(longp);
        }
        // Sorting makes sure if one weekday (or abbr) is a prefix of another it
        // will match the longer piece.
        minPieces.sort(cmpLenRev);
        shortPieces.sort(cmpLenRev);
        longPieces.sort(cmpLenRev);
        mixedPieces.sort(cmpLenRev);
        for (i = 0; i < 7; i++) {
            shortPieces[i] = regexEscape(shortPieces[i]);
            longPieces[i] = regexEscape(longPieces[i]);
            mixedPieces[i] = regexEscape(mixedPieces[i]);
        }
        this._weekdaysRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');
        this._weekdaysShortRegex = this._weekdaysRegex;
        this._weekdaysMinRegex = this._weekdaysRegex;
        this._weekdaysStrictRegex = new RegExp('^(' + longPieces.join('|') + ')', 'i');
        this._weekdaysShortStrictRegex = new RegExp('^(' + shortPieces.join('|') + ')', 'i');
        this._weekdaysMinStrictRegex = new RegExp('^(' + minPieces.join('|') + ')', 'i');
    }
    // FORMATTING
    function hFormat() {
        return this.hours() % 12 || 12;
    }
    function kFormat() {
        return this.hours() || 24;
    }
    addFormatToken('H', ['HH', 2], 0, 'hour');
    addFormatToken('h', ['hh', 2], 0, hFormat);
    addFormatToken('k', ['kk', 2], 0, kFormat);
    addFormatToken('hmm', 0, 0, function () {
        return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2);
    });
    addFormatToken('hmmss', 0, 0, function () {
        return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2) +
            zeroFill(this.seconds(), 2);
    });
    addFormatToken('Hmm', 0, 0, function () {
        return '' + this.hours() + zeroFill(this.minutes(), 2);
    });
    addFormatToken('Hmmss', 0, 0, function () {
        return '' + this.hours() + zeroFill(this.minutes(), 2) +
            zeroFill(this.seconds(), 2);
    });
    function meridiem(token, lowercase) {
        addFormatToken(token, 0, 0, function () {
            return this.localeData().meridiem(this.hours(), this.minutes(), lowercase);
        });
    }
    meridiem('a', true);
    meridiem('A', false);
    // ALIASES
    addUnitAlias('hour', 'h');
    // PRIORITY
    addUnitPriority('hour', 13);
    // PARSING
    function matchMeridiem(isStrict, locale) {
        return locale._meridiemParse;
    }
    addRegexToken('a', matchMeridiem);
    addRegexToken('A', matchMeridiem);
    addRegexToken('H', match1to2);
    addRegexToken('h', match1to2);
    addRegexToken('HH', match1to2, match2);
    addRegexToken('hh', match1to2, match2);
    addRegexToken('hmm', match3to4);
    addRegexToken('hmmss', match5to6);
    addRegexToken('Hmm', match3to4);
    addRegexToken('Hmmss', match5to6);
    addParseToken(['H', 'HH'], HOUR);
    addParseToken(['a', 'A'], function (input, array, config) {
        config._isPm = config._locale.isPM(input);
        config._meridiem = input;
    });
    addParseToken(['h', 'hh'], function (input, array, config) {
        array[HOUR] = toInt(input);
        getParsingFlags(config).bigHour = true;
    });
    addParseToken('hmm', function (input, array, config) {
        var pos = input.length - 2;
        array[HOUR] = toInt(input.substr(0, pos));
        array[MINUTE] = toInt(input.substr(pos));
        getParsingFlags(config).bigHour = true;
    });
    addParseToken('hmmss', function (input, array, config) {
        var pos1 = input.length - 4;
        var pos2 = input.length - 2;
        array[HOUR] = toInt(input.substr(0, pos1));
        array[MINUTE] = toInt(input.substr(pos1, 2));
        array[SECOND] = toInt(input.substr(pos2));
        getParsingFlags(config).bigHour = true;
    });
    addParseToken('Hmm', function (input, array, config) {
        var pos = input.length - 2;
        array[HOUR] = toInt(input.substr(0, pos));
        array[MINUTE] = toInt(input.substr(pos));
    });
    addParseToken('Hmmss', function (input, array, config) {
        var pos1 = input.length - 4;
        var pos2 = input.length - 2;
        array[HOUR] = toInt(input.substr(0, pos1));
        array[MINUTE] = toInt(input.substr(pos1, 2));
        array[SECOND] = toInt(input.substr(pos2));
    });
    // LOCALES
    function localeIsPM(input) {
        // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays
        // Using charAt should be more compatible.
        return ((input + '').toLowerCase().charAt(0) === 'p');
    }
    var defaultLocaleMeridiemParse = /[ap]\.?m?\.?/i;
    function localeMeridiem(hours, minutes, isLower) {
        if (hours > 11) {
            return isLower ? 'pm' : 'PM';
        }
        else {
            return isLower ? 'am' : 'AM';
        }
    }
    // MOMENTS
    // Setting the hour should keep the time, because the user explicitly
    // specified which hour he wants. So trying to maintain the same hour (in
    // a new timezone) makes sense. Adding/subtracting hours does not follow
    // this rule.
    var getSetHour = makeGetSet('Hours', true);
    var baseConfig = {
        calendar: defaultCalendar,
        longDateFormat: defaultLongDateFormat,
        invalidDate: defaultInvalidDate,
        ordinal: defaultOrdinal,
        ordinalParse: defaultOrdinalParse,
        relativeTime: defaultRelativeTime,
        months: defaultLocaleMonths,
        monthsShort: defaultLocaleMonthsShort,
        week: defaultLocaleWeek,
        weekdays: defaultLocaleWeekdays,
        weekdaysMin: defaultLocaleWeekdaysMin,
        weekdaysShort: defaultLocaleWeekdaysShort,
        meridiemParse: defaultLocaleMeridiemParse
    };
    // internal storage for locale config files
    var locales = {};
    var globalLocale;
    function normalizeLocale(key) {
        return key ? key.toLowerCase().replace('_', '-') : key;
    }
    // pick the locale from the array
    // try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each
    // substring from most specific to least, but move to the next array item if it's a more specific variant than the current root
    function chooseLocale(names) {
        var i = 0, j, next, locale, split;
        while (i < names.length) {
            split = normalizeLocale(names[i]).split('-');
            j = split.length;
            next = normalizeLocale(names[i + 1]);
            next = next ? next.split('-') : null;
            while (j > 0) {
                locale = loadLocale(split.slice(0, j).join('-'));
                if (locale) {
                    return locale;
                }
                if (next && next.length >= j && compareArrays(split, next, true) >= j - 1) {
                    //the next array item is better than a shallower substring of this one
                    break;
                }
                j--;
            }
            i++;
        }
        return null;
    }
    function loadLocale(name) {
        var oldLocale = null;
        // TODO: Find a better way to register and load all the locales in Node
        if (!locales[name] && (typeof module !== 'undefined') &&
            module && module.exports) {
            try {
                oldLocale = globalLocale._abbr;
                require('./locale/' + name);
                // because defineLocale currently also sets the global locale, we
                // want to undo that for lazy loaded locales
                locale_locales__getSetGlobalLocale(oldLocale);
            }
            catch (e) { }
        }
        return locales[name];
    }
    // This function will load locale and then set the global locale.  If
    // no arguments are passed in, it will simply return the current global
    // locale key.
    function locale_locales__getSetGlobalLocale(key, values) {
        var data;
        if (key) {
            if (isUndefined(values)) {
                data = locale_locales__getLocale(key);
            }
            else {
                data = defineLocale(key, values);
            }
            if (data) {
                // moment.duration._locale = moment._locale = data;
                globalLocale = data;
            }
        }
        return globalLocale._abbr;
    }
    function defineLocale(name, config) {
        if (config !== null) {
            var parentConfig = baseConfig;
            config.abbr = name;
            if (locales[name] != null) {
                deprecateSimple('defineLocaleOverride', 'use moment.updateLocale(localeName, config) to change ' +
                    'an existing locale. moment.defineLocale(localeName, ' +
                    'config) should only be used for creating a new locale ' +
                    'See http://momentjs.com/guides/#/warnings/define-locale/ for more info.');
                parentConfig = locales[name]._config;
            }
            else if (config.parentLocale != null) {
                if (locales[config.parentLocale] != null) {
                    parentConfig = locales[config.parentLocale]._config;
                }
                else {
                    // treat as if there is no base config
                    deprecateSimple('parentLocaleUndefined', 'specified parentLocale is not defined yet. See http://momentjs.com/guides/#/warnings/parent-locale/');
                }
            }
            locales[name] = new Locale(mergeConfigs(parentConfig, config));
            // backwards compat for now: also set the locale
            locale_locales__getSetGlobalLocale(name);
            return locales[name];
        }
        else {
            // useful for testing
            delete locales[name];
            return null;
        }
    }
    function updateLocale(name, config) {
        if (config != null) {
            var locale, parentConfig = baseConfig;
            // MERGE
            if (locales[name] != null) {
                parentConfig = locales[name]._config;
            }
            config = mergeConfigs(parentConfig, config);
            locale = new Locale(config);
            locale.parentLocale = locales[name];
            locales[name] = locale;
            // backwards compat for now: also set the locale
            locale_locales__getSetGlobalLocale(name);
        }
        else {
            // pass null for config to unupdate, useful for tests
            if (locales[name] != null) {
                if (locales[name].parentLocale != null) {
                    locales[name] = locales[name].parentLocale;
                }
                else if (locales[name] != null) {
                    delete locales[name];
                }
            }
        }
        return locales[name];
    }
    // returns locale data
    function locale_locales__getLocale(key) {
        var locale;
        if (key && key._locale && key._locale._abbr) {
            key = key._locale._abbr;
        }
        if (!key) {
            return globalLocale;
        }
        if (!isArray(key)) {
            //short-circuit everything else
            locale = loadLocale(key);
            if (locale) {
                return locale;
            }
            key = [key];
        }
        return chooseLocale(key);
    }
    function locale_locales__listLocales() {
        return keys(locales);
    }
    function checkOverflow(m) {
        var overflow;
        var a = m._a;
        if (a && getParsingFlags(m).overflow === -2) {
            overflow =
                a[MONTH] < 0 || a[MONTH] > 11 ? MONTH :
                    a[DATE] < 1 || a[DATE] > daysInMonth(a[YEAR], a[MONTH]) ? DATE :
                        a[HOUR] < 0 || a[HOUR] > 24 || (a[HOUR] === 24 && (a[MINUTE] !== 0 || a[SECOND] !== 0 || a[MILLISECOND] !== 0)) ? HOUR :
                            a[MINUTE] < 0 || a[MINUTE] > 59 ? MINUTE :
                                a[SECOND] < 0 || a[SECOND] > 59 ? SECOND :
                                    a[MILLISECOND] < 0 || a[MILLISECOND] > 999 ? MILLISECOND :
                                        -1;
            if (getParsingFlags(m)._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) {
                overflow = DATE;
            }
            if (getParsingFlags(m)._overflowWeeks && overflow === -1) {
                overflow = WEEK;
            }
            if (getParsingFlags(m)._overflowWeekday && overflow === -1) {
                overflow = WEEKDAY;
            }
            getParsingFlags(m).overflow = overflow;
        }
        return m;
    }
    // iso 8601 regex
    // 0000-00-00 0000-W00 or 0000-W00-0 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 or +00)
    var extendedIsoRegex = /^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?/;
    var basicIsoRegex = /^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?/;
    var tzRegex = /Z|[+-]\d\d(?::?\d\d)?/;
    var isoDates = [
        ['YYYYYY-MM-DD', /[+-]\d{6}-\d\d-\d\d/],
        ['YYYY-MM-DD', /\d{4}-\d\d-\d\d/],
        ['GGGG-[W]WW-E', /\d{4}-W\d\d-\d/],
        ['GGGG-[W]WW', /\d{4}-W\d\d/, false],
        ['YYYY-DDD', /\d{4}-\d{3}/],
        ['YYYY-MM', /\d{4}-\d\d/, false],
        ['YYYYYYMMDD', /[+-]\d{10}/],
        ['YYYYMMDD', /\d{8}/],
        // YYYYMM is NOT allowed by the standard
        ['GGGG[W]WWE', /\d{4}W\d{3}/],
        ['GGGG[W]WW', /\d{4}W\d{2}/, false],
        ['YYYYDDD', /\d{7}/]
    ];
    // iso time formats and regexes
    var isoTimes = [
        ['HH:mm:ss.SSSS', /\d\d:\d\d:\d\d\.\d+/],
        ['HH:mm:ss,SSSS', /\d\d:\d\d:\d\d,\d+/],
        ['HH:mm:ss', /\d\d:\d\d:\d\d/],
        ['HH:mm', /\d\d:\d\d/],
        ['HHmmss.SSSS', /\d\d\d\d\d\d\.\d+/],
        ['HHmmss,SSSS', /\d\d\d\d\d\d,\d+/],
        ['HHmmss', /\d\d\d\d\d\d/],
        ['HHmm', /\d\d\d\d/],
        ['HH', /\d\d/]
    ];
    var aspNetJsonRegex = /^\/?Date\((\-?\d+)/i;
    // date from iso format
    function configFromISO(config) {
        var i, l, string = config._i, match = extendedIsoRegex.exec(string) || basicIsoRegex.exec(string), allowTime, dateFormat, timeFormat, tzFormat;
        if (match) {
            getParsingFlags(config).iso = true;
            for (i = 0, l = isoDates.length; i < l; i++) {
                if (isoDates[i][1].exec(match[1])) {
                    dateFormat = isoDates[i][0];
                    allowTime = isoDates[i][2] !== false;
                    break;
                }
            }
            if (dateFormat == null) {
                config._isValid = false;
                return;
            }
            if (match[3]) {
                for (i = 0, l = isoTimes.length; i < l; i++) {
                    if (isoTimes[i][1].exec(match[3])) {
                        // match[2] should be 'T' or space
                        timeFormat = (match[2] || ' ') + isoTimes[i][0];
                        break;
                    }
                }
                if (timeFormat == null) {
                    config._isValid = false;
                    return;
                }
            }
            if (!allowTime && timeFormat != null) {
                config._isValid = false;
                return;
            }
            if (match[4]) {
                if (tzRegex.exec(match[4])) {
                    tzFormat = 'Z';
                }
                else {
                    config._isValid = false;
                    return;
                }
            }
            config._f = dateFormat + (timeFormat || '') + (tzFormat || '');
            configFromStringAndFormat(config);
        }
        else {
            config._isValid = false;
        }
    }
    // date from iso format or fallback
    function configFromString(config) {
        var matched = aspNetJsonRegex.exec(config._i);
        if (matched !== null) {
            config._d = new Date(+matched[1]);
            return;
        }
        configFromISO(config);
        if (config._isValid === false) {
            delete config._isValid;
            utils_hooks__hooks.createFromInputFallback(config);
        }
    }
    utils_hooks__hooks.createFromInputFallback = deprecate('moment construction falls back to js Date. This is ' +
        'discouraged and will be removed in upcoming major ' +
        'release. Please refer to ' +
        'http://momentjs.com/guides/#/warnings/js-date/ for more info.', function (config) {
        config._d = new Date(config._i + (config._useUTC ? ' UTC' : ''));
    });
    // Pick the first defined of two or three arguments.
    function defaults(a, b, c) {
        if (a != null) {
            return a;
        }
        if (b != null) {
            return b;
        }
        return c;
    }
    function currentDateArray(config) {
        // hooks is actually the exported moment object
        var nowValue = new Date(utils_hooks__hooks.now());
        if (config._useUTC) {
            return [nowValue.getUTCFullYear(), nowValue.getUTCMonth(), nowValue.getUTCDate()];
        }
        return [nowValue.getFullYear(), nowValue.getMonth(), nowValue.getDate()];
    }
    // convert an array to a date.
    // the array should mirror the parameters below
    // note: all values past the year are optional and will default to the lowest possible value.
    // [year, month, day , hour, minute, second, millisecond]
    function configFromArray(config) {
        var i, date, input = [], currentDate, yearToUse;
        if (config._d) {
            return;
        }
        currentDate = currentDateArray(config);
        //compute day of the year from weeks and weekdays
        if (config._w && config._a[DATE] == null && config._a[MONTH] == null) {
            dayOfYearFromWeekInfo(config);
        }
        //if the day of the year is set, figure out what it is
        if (config._dayOfYear) {
            yearToUse = defaults(config._a[YEAR], currentDate[YEAR]);
            if (config._dayOfYear > daysInYear(yearToUse)) {
                getParsingFlags(config)._overflowDayOfYear = true;
            }
            date = createUTCDate(yearToUse, 0, config._dayOfYear);
            config._a[MONTH] = date.getUTCMonth();
            config._a[DATE] = date.getUTCDate();
        }
        // Default to current date.
        // * if no year, month, day of month are given, default to today
        // * if day of month is given, default month and year
        // * if month is given, default only year
        // * if year is given, don't default anything
        for (i = 0; i < 3 && config._a[i] == null; ++i) {
            config._a[i] = input[i] = currentDate[i];
        }
        // Zero out whatever was not defaulted, including time
        for (; i < 7; i++) {
            config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i];
        }
        // Check for 24:00:00.000
        if (config._a[HOUR] === 24 &&
            config._a[MINUTE] === 0 &&
            config._a[SECOND] === 0 &&
            config._a[MILLISECOND] === 0) {
            config._nextDay = true;
            config._a[HOUR] = 0;
        }
        config._d = (config._useUTC ? createUTCDate : createDate).apply(null, input);
        // Apply timezone offset from input. The actual utcOffset can be changed
        // with parseZone.
        if (config._tzm != null) {
            config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm);
        }
        if (config._nextDay) {
            config._a[HOUR] = 24;
        }
    }
    function dayOfYearFromWeekInfo(config) {
        var w, weekYear, week, weekday, dow, doy, temp, weekdayOverflow;
        w = config._w;
        if (w.GG != null || w.W != null || w.E != null) {
            dow = 1;
            doy = 4;
            // TODO: We need to take the current isoWeekYear, but that depends on
            // how we interpret now (local, utc, fixed offset). So create
            // a now version of current config (take local/utc/offset flags, and
            // create now).
            weekYear = defaults(w.GG, config._a[YEAR], weekOfYear(local__createLocal(), 1, 4).year);
            week = defaults(w.W, 1);
            weekday = defaults(w.E, 1);
            if (weekday < 1 || weekday > 7) {
                weekdayOverflow = true;
            }
        }
        else {
            dow = config._locale._week.dow;
            doy = config._locale._week.doy;
            weekYear = defaults(w.gg, config._a[YEAR], weekOfYear(local__createLocal(), dow, doy).year);
            week = defaults(w.w, 1);
            if (w.d != null) {
                // weekday -- low day numbers are considered next week
                weekday = w.d;
                if (weekday < 0 || weekday > 6) {
                    weekdayOverflow = true;
                }
            }
            else if (w.e != null) {
                // local weekday -- counting starts from begining of week
                weekday = w.e + dow;
                if (w.e < 0 || w.e > 6) {
                    weekdayOverflow = true;
                }
            }
            else {
                // default to begining of week
                weekday = dow;
            }
        }
        if (week < 1 || week > weeksInYear(weekYear, dow, doy)) {
            getParsingFlags(config)._overflowWeeks = true;
        }
        else if (weekdayOverflow != null) {
            getParsingFlags(config)._overflowWeekday = true;
        }
        else {
            temp = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy);
            config._a[YEAR] = temp.year;
            config._dayOfYear = temp.dayOfYear;
        }
    }
    // constant that refers to the ISO standard
    utils_hooks__hooks.ISO_8601 = function () { };
    // date from string and format string
    function configFromStringAndFormat(config) {
        // TODO: Move this to another part of the creation flow to prevent circular deps
        if (config._f === utils_hooks__hooks.ISO_8601) {
            configFromISO(config);
            return;
        }
        config._a = [];
        getParsingFlags(config).empty = true;
        // This array is used to make a Date, either with `new Date` or `Date.UTC`
        var string = '' + config._i, i, parsedInput, tokens, token, skipped, stringLength = string.length, totalParsedInputLength = 0;
        tokens = expandFormat(config._f, config._locale).match(formattingTokens) || [];
        for (i = 0; i < tokens.length; i++) {
            token = tokens[i];
            parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0];
            // console.log('token', token, 'parsedInput', parsedInput,
            //         'regex', getParseRegexForToken(token, config));
            if (parsedInput) {
                skipped = string.substr(0, string.indexOf(parsedInput));
                if (skipped.length > 0) {
                    getParsingFlags(config).unusedInput.push(skipped);
                }
                string = string.slice(string.indexOf(parsedInput) + parsedInput.length);
                totalParsedInputLength += parsedInput.length;
            }
            // don't parse if it's not a known token
            if (formatTokenFunctions[token]) {
                if (parsedInput) {
                    getParsingFlags(config).empty = false;
                }
                else {
                    getParsingFlags(config).unusedTokens.push(token);
                }
                addTimeToArrayFromToken(token, parsedInput, config);
            }
            else if (config._strict && !parsedInput) {
                getParsingFlags(config).unusedTokens.push(token);
            }
        }
        // add remaining unparsed input length to the string
        getParsingFlags(config).charsLeftOver = stringLength - totalParsedInputLength;
        if (string.length > 0) {
            getParsingFlags(config).unusedInput.push(string);
        }
        // clear _12h flag if hour is <= 12
        if (config._a[HOUR] <= 12 &&
            getParsingFlags(config).bigHour === true &&
            config._a[HOUR] > 0) {
            getParsingFlags(config).bigHour = undefined;
        }
        getParsingFlags(config).parsedDateParts = config._a.slice(0);
        getParsingFlags(config).meridiem = config._meridiem;
        // handle meridiem
        config._a[HOUR] = meridiemFixWrap(config._locale, config._a[HOUR], config._meridiem);
        configFromArray(config);
        checkOverflow(config);
    }
    function meridiemFixWrap(locale, hour, meridiem) {
        var isPm;
        if (meridiem == null) {
            // nothing to do
            return hour;
        }
        if (locale.meridiemHour != null) {
            return locale.meridiemHour(hour, meridiem);
        }
        else if (locale.isPM != null) {
            // Fallback
            isPm = locale.isPM(meridiem);
            if (isPm && hour < 12) {
                hour += 12;
            }
            if (!isPm && hour === 12) {
                hour = 0;
            }
            return hour;
        }
        else {
            // this is not supposed to happen
            return hour;
        }
    }
    // date from string and array of format strings
    function configFromStringAndArray(config) {
        var tempConfig, bestMoment, scoreToBeat, i, currentScore;
        if (config._f.length === 0) {
            getParsingFlags(config).invalidFormat = true;
            config._d = new Date(NaN);
            return;
        }
        for (i = 0; i < config._f.length; i++) {
            currentScore = 0;
            tempConfig = copyConfig({}, config);
            if (config._useUTC != null) {
                tempConfig._useUTC = config._useUTC;
            }
            tempConfig._f = config._f[i];
            configFromStringAndFormat(tempConfig);
            if (!valid__isValid(tempConfig)) {
                continue;
            }
            // if there is any input that was not parsed add a penalty for that format
            currentScore += getParsingFlags(tempConfig).charsLeftOver;
            //or tokens
            currentScore += getParsingFlags(tempConfig).unusedTokens.length * 10;
            getParsingFlags(tempConfig).score = currentScore;
            if (scoreToBeat == null || currentScore < scoreToBeat) {
                scoreToBeat = currentScore;
                bestMoment = tempConfig;
            }
        }
        extend(config, bestMoment || tempConfig);
    }
    function configFromObject(config) {
        if (config._d) {
            return;
        }
        var i = normalizeObjectUnits(config._i);
        config._a = map([i.year, i.month, i.day || i.date, i.hour, i.minute, i.second, i.millisecond], function (obj) {
            return obj && parseInt(obj, 10);
        });
        configFromArray(config);
    }
    function createFromConfig(config) {
        var res = new Moment(checkOverflow(prepareConfig(config)));
        if (res._nextDay) {
            // Adding is smart enough around DST
            res.add(1, 'd');
            res._nextDay = undefined;
        }
        return res;
    }
    function prepareConfig(config) {
        var input = config._i, format = config._f;
        config._locale = config._locale || locale_locales__getLocale(config._l);
        if (input === null || (format === undefined && input === '')) {
            return valid__createInvalid({ nullInput: true });
        }
        if (typeof input === 'string') {
            config._i = input = config._locale.preparse(input);
        }
        if (isMoment(input)) {
            return new Moment(checkOverflow(input));
        }
        else if (isArray(format)) {
            configFromStringAndArray(config);
        }
        else if (isDate(input)) {
            config._d = input;
        }
        else if (format) {
            configFromStringAndFormat(config);
        }
        else {
            configFromInput(config);
        }
        if (!valid__isValid(config)) {
            config._d = null;
        }
        return config;
    }
    function configFromInput(config) {
        var input = config._i;
        if (input === undefined) {
            config._d = new Date(utils_hooks__hooks.now());
        }
        else if (isDate(input)) {
            config._d = new Date(input.valueOf());
        }
        else if (typeof input === 'string') {
            configFromString(config);
        }
        else if (isArray(input)) {
            config._a = map(input.slice(0), function (obj) {
                return parseInt(obj, 10);
            });
            configFromArray(config);
        }
        else if (typeof (input) === 'object') {
            configFromObject(config);
        }
        else if (typeof (input) === 'number') {
            // from milliseconds
            config._d = new Date(input);
        }
        else {
            utils_hooks__hooks.createFromInputFallback(config);
        }
    }
    function createLocalOrUTC(input, format, locale, strict, isUTC) {
        var c = {};
        if (typeof (locale) === 'boolean') {
            strict = locale;
            locale = undefined;
        }
        if ((isObject(input) && isObjectEmpty(input)) ||
            (isArray(input) && input.length === 0)) {
            input = undefined;
        }
        // object construction must be done this way.
        // https://github.com/moment/moment/issues/1423
        c._isAMomentObject = true;
        c._useUTC = c._isUTC = isUTC;
        c._l = locale;
        c._i = input;
        c._f = format;
        c._strict = strict;
        return createFromConfig(c);
    }
    function local__createLocal(input, format, locale, strict) {
        return createLocalOrUTC(input, format, locale, strict, false);
    }
    var prototypeMin = deprecate('moment().min is deprecated, use moment.max instead. http://momentjs.com/guides/#/warnings/min-max/', function () {
        var other = local__createLocal.apply(null, arguments);
        if (this.isValid() && other.isValid()) {
            return other < this ? this : other;
        }
        else {
            return valid__createInvalid();
        }
    });
    var prototypeMax = deprecate('moment().max is deprecated, use moment.min instead. http://momentjs.com/guides/#/warnings/min-max/', function () {
        var other = local__createLocal.apply(null, arguments);
        if (this.isValid() && other.isValid()) {
            return other > this ? this : other;
        }
        else {
            return valid__createInvalid();
        }
    });
    // Pick a moment m from moments so that m[fn](other) is true for all
    // other. This relies on the function fn to be transitive.
    //
    // moments should either be an array of moment objects or an array, whose
    // first element is an array of moment objects.
    function pickBy(fn, moments) {
        var res, i;
        if (moments.length === 1 && isArray(moments[0])) {
            moments = moments[0];
        }
        if (!moments.length) {
            return local__createLocal();
        }
        res = moments[0];
        for (i = 1; i < moments.length; ++i) {
            if (!moments[i].isValid() || moments[i][fn](res)) {
                res = moments[i];
            }
        }
        return res;
    }
    // TODO: Use [].sort instead?
    function min() {
        var args = [].slice.call(arguments, 0);
        return pickBy('isBefore', args);
    }
    function max() {
        var args = [].slice.call(arguments, 0);
        return pickBy('isAfter', args);
    }
    var now = function () {
        return Date.now ? Date.now() : +(new Date());
    };
    function Duration(duration) {
        var normalizedInput = normalizeObjectUnits(duration), years = normalizedInput.year || 0, quarters = normalizedInput.quarter || 0, months = normalizedInput.month || 0, weeks = normalizedInput.week || 0, days = normalizedInput.day || 0, hours = normalizedInput.hour || 0, minutes = normalizedInput.minute || 0, seconds = normalizedInput.second || 0, milliseconds = normalizedInput.millisecond || 0;
        // representation for dateAddRemove
        this._milliseconds = +milliseconds +
            seconds * 1e3 +
            minutes * 6e4 +
            hours * 1000 * 60 * 60; //using 1000 * 60 * 60 instead of 36e5 to avoid floating point rounding errors https://github.com/moment/moment/issues/2978
        // Because of dateAddRemove treats 24 hours as different from a
        // day when working around DST, we need to store them separately
        this._days = +days +
            weeks * 7;
        // It is impossible translate months into days without knowing
        // which months you are are talking about, so we have to store
        // it separately.
        this._months = +months +
            quarters * 3 +
            years * 12;
        this._data = {};
        this._locale = locale_locales__getLocale();
        this._bubble();
    }
    function isDuration(obj) {
        return obj instanceof Duration;
    }
    // FORMATTING
    function offset(token, separator) {
        addFormatToken(token, 0, 0, function () {
            var offset = this.utcOffset();
            var sign = '+';
            if (offset < 0) {
                offset = -offset;
                sign = '-';
            }
            return sign + zeroFill(~~(offset / 60), 2) + separator + zeroFill(~~(offset) % 60, 2);
        });
    }
    offset('Z', ':');
    offset('ZZ', '');
    // PARSING
    addRegexToken('Z', matchShortOffset);
    addRegexToken('ZZ', matchShortOffset);
    addParseToken(['Z', 'ZZ'], function (input, array, config) {
        config._useUTC = true;
        config._tzm = offsetFromString(matchShortOffset, input);
    });
    // HELPERS
    // timezone chunker
    // '+10:00' > ['10',  '00']
    // '-1530'  > ['-15', '30']
    var chunkOffset = /([\+\-]|\d\d)/gi;
    function offsetFromString(matcher, string) {
        var matches = ((string || '').match(matcher) || []);
        var chunk = matches[matches.length - 1] || [];
        var parts = (chunk + '').match(chunkOffset) || ['-', 0, 0];
        var minutes = +(parts[1] * 60) + toInt(parts[2]);
        return parts[0] === '+' ? minutes : -minutes;
    }
    // Return a moment from input, that is local/utc/zone equivalent to model.
    function cloneWithOffset(input, model) {
        var res, diff;
        if (model._isUTC) {
            res = model.clone();
            diff = (isMoment(input) || isDate(input) ? input.valueOf() : local__createLocal(input).valueOf()) - res.valueOf();
            // Use low-level api, because this fn is low-level api.
            res._d.setTime(res._d.valueOf() + diff);
            utils_hooks__hooks.updateOffset(res, false);
            return res;
        }
        else {
            return local__createLocal(input).local();
        }
    }
    function getDateOffset(m) {
        // On Firefox.24 Date#getTimezoneOffset returns a floating point.
        // https://github.com/moment/moment/pull/1871
        return -Math.round(m._d.getTimezoneOffset() / 15) * 15;
    }
    // HOOKS
    // This function will be called whenever a moment is mutated.
    // It is intended to keep the offset in sync with the timezone.
    utils_hooks__hooks.updateOffset = function () { };
    // MOMENTS
    // keepLocalTime = true means only change the timezone, without
    // affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]-->
    // 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset
    // +0200, so we adjust the time as needed, to be valid.
    //
    // Keeping the time actually adds/subtracts (one hour)
    // from the actual represented time. That is why we call updateOffset
    // a second time. In case it wants us to change the offset again
    // _changeInProgress == true case, then we have to adjust, because
    // there is no such time in the given timezone.
    function getSetOffset(input, keepLocalTime) {
        var offset = this._offset || 0, localAdjust;
        if (!this.isValid()) {
            return input != null ? this : NaN;
        }
        if (input != null) {
            if (typeof input === 'string') {
                input = offsetFromString(matchShortOffset, input);
            }
            else if (Math.abs(input) < 16) {
                input = input * 60;
            }
            if (!this._isUTC && keepLocalTime) {
                localAdjust = getDateOffset(this);
            }
            this._offset = input;
            this._isUTC = true;
            if (localAdjust != null) {
                this.add(localAdjust, 'm');
            }
            if (offset !== input) {
                if (!keepLocalTime || this._changeInProgress) {
                    add_subtract__addSubtract(this, create__createDuration(input - offset, 'm'), 1, false);
                }
                else if (!this._changeInProgress) {
                    this._changeInProgress = true;
                    utils_hooks__hooks.updateOffset(this, true);
                    this._changeInProgress = null;
                }
            }
            return this;
        }
        else {
            return this._isUTC ? offset : getDateOffset(this);
        }
    }
    function getSetZone(input, keepLocalTime) {
        if (input != null) {
            if (typeof input !== 'string') {
                input = -input;
            }
            this.utcOffset(input, keepLocalTime);
            return this;
        }
        else {
            return -this.utcOffset();
        }
    }
    function setOffsetToUTC(keepLocalTime) {
        return this.utcOffset(0, keepLocalTime);
    }
    function setOffsetToLocal(keepLocalTime) {
        if (this._isUTC) {
            this.utcOffset(0, keepLocalTime);
            this._isUTC = false;
            if (keepLocalTime) {
                this.subtract(getDateOffset(this), 'm');
            }
        }
        return this;
    }
    function setOffsetToParsedOffset() {
        if (this._tzm) {
            this.utcOffset(this._tzm);
        }
        else if (typeof this._i === 'string') {
            this.utcOffset(offsetFromString(matchOffset, this._i));
        }
        return this;
    }
    function hasAlignedHourOffset(input) {
        if (!this.isValid()) {
            return false;
        }
        input = input ? local__createLocal(input).utcOffset() : 0;
        return (this.utcOffset() - input) % 60 === 0;
    }
    function isDaylightSavingTime() {
        return (this.utcOffset() > this.clone().month(0).utcOffset() ||
            this.utcOffset() > this.clone().month(5).utcOffset());
    }
    function isDaylightSavingTimeShifted() {
        if (!isUndefined(this._isDSTShifted)) {
            return this._isDSTShifted;
        }
        var c = {};
        copyConfig(c, this);
        c = prepareConfig(c);
        if (c._a) {
            var other = c._isUTC ? create_utc__createUTC(c._a) : local__createLocal(c._a);
            this._isDSTShifted = this.isValid() &&
                compareArrays(c._a, other.toArray()) > 0;
        }
        else {
            this._isDSTShifted = false;
        }
        return this._isDSTShifted;
    }
    function isLocal() {
        return this.isValid() ? !this._isUTC : false;
    }
    function isUtcOffset() {
        return this.isValid() ? this._isUTC : false;
    }
    function isUtc() {
        return this.isValid() ? this._isUTC && this._offset === 0 : false;
    }
    // ASP.NET json date format regex
    var aspNetRegex = /^(\-)?(?:(\d*)[. ])?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?\d*)?$/;
    // from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html
    // somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere
    // and further modified to allow for strings containing both week and day
    var isoRegex = /^(-)?P(?:(-?[0-9,.]*)Y)?(?:(-?[0-9,.]*)M)?(?:(-?[0-9,.]*)W)?(?:(-?[0-9,.]*)D)?(?:T(?:(-?[0-9,.]*)H)?(?:(-?[0-9,.]*)M)?(?:(-?[0-9,.]*)S)?)?$/;
    function create__createDuration(input, key) {
        var duration = input, 
        // matching against regexp is expensive, do it on demand
        match = null, sign, ret, diffRes;
        if (isDuration(input)) {
            duration = {
                ms: input._milliseconds,
                d: input._days,
                M: input._months
            };
        }
        else if (typeof input === 'number') {
            duration = {};
            if (key) {
                duration[key] = input;
            }
            else {
                duration.milliseconds = input;
            }
        }
        else if (!!(match = aspNetRegex.exec(input))) {
            sign = (match[1] === '-') ? -1 : 1;
            duration = {
                y: 0,
                d: toInt(match[DATE]) * sign,
                h: toInt(match[HOUR]) * sign,
                m: toInt(match[MINUTE]) * sign,
                s: toInt(match[SECOND]) * sign,
                ms: toInt(match[MILLISECOND]) * sign
            };
        }
        else if (!!(match = isoRegex.exec(input))) {
            sign = (match[1] === '-') ? -1 : 1;
            duration = {
                y: parseIso(match[2], sign),
                M: parseIso(match[3], sign),
                w: parseIso(match[4], sign),
                d: parseIso(match[5], sign),
                h: parseIso(match[6], sign),
                m: parseIso(match[7], sign),
                s: parseIso(match[8], sign)
            };
        }
        else if (duration == null) {
            duration = {};
        }
        else if (typeof duration === 'object' && ('from' in duration || 'to' in duration)) {
            diffRes = momentsDifference(local__createLocal(duration.from), local__createLocal(duration.to));
            duration = {};
            duration.ms = diffRes.milliseconds;
            duration.M = diffRes.months;
        }
        ret = new Duration(duration);
        if (isDuration(input) && hasOwnProp(input, '_locale')) {
            ret._locale = input._locale;
        }
        return ret;
    }
    create__createDuration.fn = Duration.prototype;
    function parseIso(inp, sign) {
        // We'd normally use ~~inp for this, but unfortunately it also
        // converts floats to ints.
        // inp may be undefined, so careful calling replace on it.
        var res = inp && parseFloat(inp.replace(',', '.'));
        // apply sign while we're at it
        return (isNaN(res) ? 0 : res) * sign;
    }
    function positiveMomentsDifference(base, other) {
        var res = { milliseconds: 0, months: 0 };
        res.months = other.month() - base.month() +
            (other.year() - base.year()) * 12;
        if (base.clone().add(res.months, 'M').isAfter(other)) {
            --res.months;
        }
        res.milliseconds = +other - +(base.clone().add(res.months, 'M'));
        return res;
    }
    function momentsDifference(base, other) {
        var res;
        if (!(base.isValid() && other.isValid())) {
            return { milliseconds: 0, months: 0 };
        }
        other = cloneWithOffset(other, base);
        if (base.isBefore(other)) {
            res = positiveMomentsDifference(base, other);
        }
        else {
            res = positiveMomentsDifference(other, base);
            res.milliseconds = -res.milliseconds;
            res.months = -res.months;
        }
        return res;
    }
    function absRound(number) {
        if (number < 0) {
            return Math.round(-1 * number) * -1;
        }
        else {
            return Math.round(number);
        }
    }
    // TODO: remove 'name' arg after deprecation is removed
    function createAdder(direction, name) {
        return function (val, period) {
            var dur, tmp;
            //invert the arguments, but complain about it
            if (period !== null && !isNaN(+period)) {
                deprecateSimple(name, 'moment().' + name + '(period, number) is deprecated. Please use moment().' + name + '(number, period). ' +
                    'See http://momentjs.com/guides/#/warnings/add-inverted-param/ for more info.');
                tmp = val;
                val = period;
                period = tmp;
            }
            val = typeof val === 'string' ? +val : val;
            dur = create__createDuration(val, period);
            add_subtract__addSubtract(this, dur, direction);
            return this;
        };
    }
    function add_subtract__addSubtract(mom, duration, isAdding, updateOffset) {
        var milliseconds = duration._milliseconds, days = absRound(duration._days), months = absRound(duration._months);
        if (!mom.isValid()) {
            // No op
            return;
        }
        updateOffset = updateOffset == null ? true : updateOffset;
        if (milliseconds) {
            mom._d.setTime(mom._d.valueOf() + milliseconds * isAdding);
        }
        if (days) {
            get_set__set(mom, 'Date', get_set__get(mom, 'Date') + days * isAdding);
        }
        if (months) {
            setMonth(mom, get_set__get(mom, 'Month') + months * isAdding);
        }
        if (updateOffset) {
            utils_hooks__hooks.updateOffset(mom, days || months);
        }
    }
    var add_subtract__add = createAdder(1, 'add');
    var add_subtract__subtract = createAdder(-1, 'subtract');
    function getCalendarFormat(myMoment, now) {
        var diff = myMoment.diff(now, 'days', true);
        return diff < -6 ? 'sameElse' :
            diff < -1 ? 'lastWeek' :
                diff < 0 ? 'lastDay' :
                    diff < 1 ? 'sameDay' :
                        diff < 2 ? 'nextDay' :
                            diff < 7 ? 'nextWeek' : 'sameElse';
    }
    function moment_calendar__calendar(time, formats) {
        // We want to compare the start of today, vs this.
        // Getting start-of-today depends on whether we're local/utc/offset or not.
        var now = time || local__createLocal(), sod = cloneWithOffset(now, this).startOf('day'), format = utils_hooks__hooks.calendarFormat(this, sod) || 'sameElse';
        var output = formats && (isFunction(formats[format]) ? formats[format].call(this, now) : formats[format]);
        return this.format(output || this.localeData().calendar(format, this, local__createLocal(now)));
    }
    function clone() {
        return new Moment(this);
    }
    function isAfter(input, units) {
        var localInput = isMoment(input) ? input : local__createLocal(input);
        if (!(this.isValid() && localInput.isValid())) {
            return false;
        }
        units = normalizeUnits(!isUndefined(units) ? units : 'millisecond');
        if (units === 'millisecond') {
            return this.valueOf() > localInput.valueOf();
        }
        else {
            return localInput.valueOf() < this.clone().startOf(units).valueOf();
        }
    }
    function isBefore(input, units) {
        var localInput = isMoment(input) ? input : local__createLocal(input);
        if (!(this.isValid() && localInput.isValid())) {
            return false;
        }
        units = normalizeUnits(!isUndefined(units) ? units : 'millisecond');
        if (units === 'millisecond') {
            return this.valueOf() < localInput.valueOf();
        }
        else {
            return this.clone().endOf(units).valueOf() < localInput.valueOf();
        }
    }
    function isBetween(from, to, units, inclusivity) {
        inclusivity = inclusivity || '()';
        return (inclusivity[0] === '(' ? this.isAfter(from, units) : !this.isBefore(from, units)) &&
            (inclusivity[1] === ')' ? this.isBefore(to, units) : !this.isAfter(to, units));
    }
    function isSame(input, units) {
        var localInput = isMoment(input) ? input : local__createLocal(input), inputMs;
        if (!(this.isValid() && localInput.isValid())) {
            return false;
        }
        units = normalizeUnits(units || 'millisecond');
        if (units === 'millisecond') {
            return this.valueOf() === localInput.valueOf();
        }
        else {
            inputMs = localInput.valueOf();
            return this.clone().startOf(units).valueOf() <= inputMs && inputMs <= this.clone().endOf(units).valueOf();
        }
    }
    function isSameOrAfter(input, units) {
        return this.isSame(input, units) || this.isAfter(input, units);
    }
    function isSameOrBefore(input, units) {
        return this.isSame(input, units) || this.isBefore(input, units);
    }
    function diff(input, units, asFloat) {
        var that, zoneDelta, delta, output;
        if (!this.isValid()) {
            return NaN;
        }
        that = cloneWithOffset(input, this);
        if (!that.isValid()) {
            return NaN;
        }
        zoneDelta = (that.utcOffset() - this.utcOffset()) * 6e4;
        units = normalizeUnits(units);
        if (units === 'year' || units === 'month' || units === 'quarter') {
            output = monthDiff(this, that);
            if (units === 'quarter') {
                output = output / 3;
            }
            else if (units === 'year') {
                output = output / 12;
            }
        }
        else {
            delta = this - that;
            output = units === 'second' ? delta / 1e3 :
                units === 'minute' ? delta / 6e4 :
                    units === 'hour' ? delta / 36e5 :
                        units === 'day' ? (delta - zoneDelta) / 864e5 :
                            units === 'week' ? (delta - zoneDelta) / 6048e5 :
                                delta;
        }
        return asFloat ? output : absFloor(output);
    }
    function monthDiff(a, b) {
        // difference in months
        var wholeMonthDiff = ((b.year() - a.year()) * 12) + (b.month() - a.month()), 
        // b is in (anchor - 1 month, anchor + 1 month)
        anchor = a.clone().add(wholeMonthDiff, 'months'), anchor2, adjust;
        if (b - anchor < 0) {
            anchor2 = a.clone().add(wholeMonthDiff - 1, 'months');
            // linear across the month
            adjust = (b - anchor) / (anchor - anchor2);
        }
        else {
            anchor2 = a.clone().add(wholeMonthDiff + 1, 'months');
            // linear across the month
            adjust = (b - anchor) / (anchor2 - anchor);
        }
        //check for negative zero, return zero if negative zero
        return -(wholeMonthDiff + adjust) || 0;
    }
    utils_hooks__hooks.defaultFormat = 'YYYY-MM-DDTHH:mm:ssZ';
    utils_hooks__hooks.defaultFormatUtc = 'YYYY-MM-DDTHH:mm:ss[Z]';
    function toString() {
        return this.clone().locale('en').format('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ');
    }
    function moment_format__toISOString() {
        var m = this.clone().utc();
        if (0 < m.year() && m.year() <= 9999) {
            if (isFunction(Date.prototype.toISOString)) {
                // native implementation is ~50x faster, use it when we can
                return this.toDate().toISOString();
            }
            else {
                return formatMoment(m, 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]');
            }
        }
        else {
            return formatMoment(m, 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]');
        }
    }
    function format(inputString) {
        if (!inputString) {
            inputString = this.isUtc() ? utils_hooks__hooks.defaultFormatUtc : utils_hooks__hooks.defaultFormat;
        }
        var output = formatMoment(this, inputString);
        return this.localeData().postformat(output);
    }
    function from(time, withoutSuffix) {
        if (this.isValid() &&
            ((isMoment(time) && time.isValid()) ||
                local__createLocal(time).isValid())) {
            return create__createDuration({ to: this, from: time }).locale(this.locale()).humanize(!withoutSuffix);
        }
        else {
            return this.localeData().invalidDate();
        }
    }
    function fromNow(withoutSuffix) {
        return this.from(local__createLocal(), withoutSuffix);
    }
    function to(time, withoutSuffix) {
        if (this.isValid() &&
            ((isMoment(time) && time.isValid()) ||
                local__createLocal(time).isValid())) {
            return create__createDuration({ from: this, to: time }).locale(this.locale()).humanize(!withoutSuffix);
        }
        else {
            return this.localeData().invalidDate();
        }
    }
    function toNow(withoutSuffix) {
        return this.to(local__createLocal(), withoutSuffix);
    }
    // If passed a locale key, it will set the locale for this
    // instance.  Otherwise, it will return the locale configuration
    // variables for this instance.
    function locale(key) {
        var newLocaleData;
        if (key === undefined) {
            return this._locale._abbr;
        }
        else {
            newLocaleData = locale_locales__getLocale(key);
            if (newLocaleData != null) {
                this._locale = newLocaleData;
            }
            return this;
        }
    }
    var lang = deprecate('moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.', function (key) {
        if (key === undefined) {
            return this.localeData();
        }
        else {
            return this.locale(key);
        }
    });
    function localeData() {
        return this._locale;
    }
    function startOf(units) {
        units = normalizeUnits(units);
        // the following switch intentionally omits break keywords
        // to utilize falling through the cases.
        switch (units) {
            case 'year':
                this.month(0);
            /* falls through */
            case 'quarter':
            case 'month':
                this.date(1);
            /* falls through */
            case 'week':
            case 'isoWeek':
            case 'day':
            case 'date':
                this.hours(0);
            /* falls through */
            case 'hour':
                this.minutes(0);
            /* falls through */
            case 'minute':
                this.seconds(0);
            /* falls through */
            case 'second':
                this.milliseconds(0);
        }
        // weeks are a special case
        if (units === 'week') {
            this.weekday(0);
        }
        if (units === 'isoWeek') {
            this.isoWeekday(1);
        }
        // quarters are also special
        if (units === 'quarter') {
            this.month(Math.floor(this.month() / 3) * 3);
        }
        return this;
    }
    function endOf(units) {
        units = normalizeUnits(units);
        if (units === undefined || units === 'millisecond') {
            return this;
        }
        // 'date' is an alias for 'day', so it should be considered as such.
        if (units === 'date') {
            units = 'day';
        }
        return this.startOf(units).add(1, (units === 'isoWeek' ? 'week' : units)).subtract(1, 'ms');
    }
    function to_type__valueOf() {
        return this._d.valueOf() - ((this._offset || 0) * 60000);
    }
    function unix() {
        return Math.floor(this.valueOf() / 1000);
    }
    function toDate() {
        return new Date(this.valueOf());
    }
    function toArray() {
        var m = this;
        return [m.year(), m.month(), m.date(), m.hour(), m.minute(), m.second(), m.millisecond()];
    }
    function toObject() {
        var m = this;
        return {
            years: m.year(),
            months: m.month(),
            date: m.date(),
            hours: m.hours(),
            minutes: m.minutes(),
            seconds: m.seconds(),
            milliseconds: m.milliseconds()
        };
    }
    function toJSON() {
        // new Date(NaN).toJSON() === null
        return this.isValid() ? this.toISOString() : null;
    }
    function moment_valid__isValid() {
        return valid__isValid(this);
    }
    function parsingFlags() {
        return extend({}, getParsingFlags(this));
    }
    function invalidAt() {
        return getParsingFlags(this).overflow;
    }
    function creationData() {
        return {
            input: this._i,
            format: this._f,
            locale: this._locale,
            isUTC: this._isUTC,
            strict: this._strict
        };
    }
    // FORMATTING
    addFormatToken(0, ['gg', 2], 0, function () {
        return this.weekYear() % 100;
    });
    addFormatToken(0, ['GG', 2], 0, function () {
        return this.isoWeekYear() % 100;
    });
    function addWeekYearFormatToken(token, getter) {
        addFormatToken(0, [token, token.length], 0, getter);
    }
    addWeekYearFormatToken('gggg', 'weekYear');
    addWeekYearFormatToken('ggggg', 'weekYear');
    addWeekYearFormatToken('GGGG', 'isoWeekYear');
    addWeekYearFormatToken('GGGGG', 'isoWeekYear');
    // ALIASES
    addUnitAlias('weekYear', 'gg');
    addUnitAlias('isoWeekYear', 'GG');
    // PRIORITY
    addUnitPriority('weekYear', 1);
    addUnitPriority('isoWeekYear', 1);
    // PARSING
    addRegexToken('G', matchSigned);
    addRegexToken('g', matchSigned);
    addRegexToken('GG', match1to2, match2);
    addRegexToken('gg', match1to2, match2);
    addRegexToken('GGGG', match1to4, match4);
    addRegexToken('gggg', match1to4, match4);
    addRegexToken('GGGGG', match1to6, match6);
    addRegexToken('ggggg', match1to6, match6);
    addWeekParseToken(['gggg', 'ggggg', 'GGGG', 'GGGGG'], function (input, week, config, token) {
        week[token.substr(0, 2)] = toInt(input);
    });
    addWeekParseToken(['gg', 'GG'], function (input, week, config, token) {
        week[token] = utils_hooks__hooks.parseTwoDigitYear(input);
    });
    // MOMENTS
    function getSetWeekYear(input) {
        return getSetWeekYearHelper.call(this, input, this.week(), this.weekday(), this.localeData()._week.dow, this.localeData()._week.doy);
    }
    function getSetISOWeekYear(input) {
        return getSetWeekYearHelper.call(this, input, this.isoWeek(), this.isoWeekday(), 1, 4);
    }
    function getISOWeeksInYear() {
        return weeksInYear(this.year(), 1, 4);
    }
    function getWeeksInYear() {
        var weekInfo = this.localeData()._week;
        return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy);
    }
    function getSetWeekYearHelper(input, week, weekday, dow, doy) {
        var weeksTarget;
        if (input == null) {
            return weekOfYear(this, dow, doy).year;
        }
        else {
            weeksTarget = weeksInYear(input, dow, doy);
            if (week > weeksTarget) {
                week = weeksTarget;
            }
            return setWeekAll.call(this, input, week, weekday, dow, doy);
        }
    }
    function setWeekAll(weekYear, week, weekday, dow, doy) {
        var dayOfYearData = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy), date = createUTCDate(dayOfYearData.year, 0, dayOfYearData.dayOfYear);
        this.year(date.getUTCFullYear());
        this.month(date.getUTCMonth());
        this.date(date.getUTCDate());
        return this;
    }
    // FORMATTING
    addFormatToken('Q', 0, 'Qo', 'quarter');
    // ALIASES
    addUnitAlias('quarter', 'Q');
    // PRIORITY
    addUnitPriority('quarter', 7);
    // PARSING
    addRegexToken('Q', match1);
    addParseToken('Q', function (input, array) {
        array[MONTH] = (toInt(input) - 1) * 3;
    });
    // MOMENTS
    function getSetQuarter(input) {
        return input == null ? Math.ceil((this.month() + 1) / 3) : this.month((input - 1) * 3 + this.month() % 3);
    }
    // FORMATTING
    addFormatToken('D', ['DD', 2], 'Do', 'date');
    // ALIASES
    addUnitAlias('date', 'D');
    // PRIOROITY
    addUnitPriority('date', 9);
    // PARSING
    addRegexToken('D', match1to2);
    addRegexToken('DD', match1to2, match2);
    addRegexToken('Do', function (isStrict, locale) {
        return isStrict ? locale._ordinalParse : locale._ordinalParseLenient;
    });
    addParseToken(['D', 'DD'], DATE);
    addParseToken('Do', function (input, array) {
        array[DATE] = toInt(input.match(match1to2)[0], 10);
    });
    // MOMENTS
    var getSetDayOfMonth = makeGetSet('Date', true);
    // FORMATTING
    addFormatToken('DDD', ['DDDD', 3], 'DDDo', 'dayOfYear');
    // ALIASES
    addUnitAlias('dayOfYear', 'DDD');
    // PRIORITY
    addUnitPriority('dayOfYear', 4);
    // PARSING
    addRegexToken('DDD', match1to3);
    addRegexToken('DDDD', match3);
    addParseToken(['DDD', 'DDDD'], function (input, array, config) {
        config._dayOfYear = toInt(input);
    });
    // HELPERS
    // MOMENTS
    function getSetDayOfYear(input) {
        var dayOfYear = Math.round((this.clone().startOf('day') - this.clone().startOf('year')) / 864e5) + 1;
        return input == null ? dayOfYear : this.add((input - dayOfYear), 'd');
    }
    // FORMATTING
    addFormatToken('m', ['mm', 2], 0, 'minute');
    // ALIASES
    addUnitAlias('minute', 'm');
    // PRIORITY
    addUnitPriority('minute', 14);
    // PARSING
    addRegexToken('m', match1to2);
    addRegexToken('mm', match1to2, match2);
    addParseToken(['m', 'mm'], MINUTE);
    // MOMENTS
    var getSetMinute = makeGetSet('Minutes', false);
    // FORMATTING
    addFormatToken('s', ['ss', 2], 0, 'second');
    // ALIASES
    addUnitAlias('second', 's');
    // PRIORITY
    addUnitPriority('second', 15);
    // PARSING
    addRegexToken('s', match1to2);
    addRegexToken('ss', match1to2, match2);
    addParseToken(['s', 'ss'], SECOND);
    // MOMENTS
    var getSetSecond = makeGetSet('Seconds', false);
    // FORMATTING
    addFormatToken('S', 0, 0, function () {
        return ~~(this.millisecond() / 100);
    });
    addFormatToken(0, ['SS', 2], 0, function () {
        return ~~(this.millisecond() / 10);
    });
    addFormatToken(0, ['SSS', 3], 0, 'millisecond');
    addFormatToken(0, ['SSSS', 4], 0, function () {
        return this.millisecond() * 10;
    });
    addFormatToken(0, ['SSSSS', 5], 0, function () {
        return this.millisecond() * 100;
    });
    addFormatToken(0, ['SSSSSS', 6], 0, function () {
        return this.millisecond() * 1000;
    });
    addFormatToken(0, ['SSSSSSS', 7], 0, function () {
        return this.millisecond() * 10000;
    });
    addFormatToken(0, ['SSSSSSSS', 8], 0, function () {
        return this.millisecond() * 100000;
    });
    addFormatToken(0, ['SSSSSSSSS', 9], 0, function () {
        return this.millisecond() * 1000000;
    });
    // ALIASES
    addUnitAlias('millisecond', 'ms');
    // PRIORITY
    addUnitPriority('millisecond', 16);
    // PARSING
    addRegexToken('S', match1to3, match1);
    addRegexToken('SS', match1to3, match2);
    addRegexToken('SSS', match1to3, match3);
    var token;
    for (token = 'SSSS'; token.length <= 9; token += 'S') {
        addRegexToken(token, matchUnsigned);
    }
    function parseMs(input, array) {
        array[MILLISECOND] = toInt(('0.' + input) * 1000);
    }
    for (token = 'S'; token.length <= 9; token += 'S') {
        addParseToken(token, parseMs);
    }
    // MOMENTS
    var getSetMillisecond = makeGetSet('Milliseconds', false);
    // FORMATTING
    addFormatToken('z', 0, 0, 'zoneAbbr');
    addFormatToken('zz', 0, 0, 'zoneName');
    // MOMENTS
    function getZoneAbbr() {
        return this._isUTC ? 'UTC' : '';
    }
    function getZoneName() {
        return this._isUTC ? 'Coordinated Universal Time' : '';
    }
    var momentPrototype__proto = Moment.prototype;
    momentPrototype__proto.add = add_subtract__add;
    momentPrototype__proto.calendar = moment_calendar__calendar;
    momentPrototype__proto.clone = clone;
    momentPrototype__proto.diff = diff;
    momentPrototype__proto.endOf = endOf;
    momentPrototype__proto.format = format;
    momentPrototype__proto.from = from;
    momentPrototype__proto.fromNow = fromNow;
    momentPrototype__proto.to = to;
    momentPrototype__proto.toNow = toNow;
    momentPrototype__proto.get = stringGet;
    momentPrototype__proto.invalidAt = invalidAt;
    momentPrototype__proto.isAfter = isAfter;
    momentPrototype__proto.isBefore = isBefore;
    momentPrototype__proto.isBetween = isBetween;
    momentPrototype__proto.isSame = isSame;
    momentPrototype__proto.isSameOrAfter = isSameOrAfter;
    momentPrototype__proto.isSameOrBefore = isSameOrBefore;
    momentPrototype__proto.isValid = moment_valid__isValid;
    momentPrototype__proto.lang = lang;
    momentPrototype__proto.locale = locale;
    momentPrototype__proto.localeData = localeData;
    momentPrototype__proto.max = prototypeMax;
    momentPrototype__proto.min = prototypeMin;
    momentPrototype__proto.parsingFlags = parsingFlags;
    momentPrototype__proto.set = stringSet;
    momentPrototype__proto.startOf = startOf;
    momentPrototype__proto.subtract = add_subtract__subtract;
    momentPrototype__proto.toArray = toArray;
    momentPrototype__proto.toObject = toObject;
    momentPrototype__proto.toDate = toDate;
    momentPrototype__proto.toISOString = moment_format__toISOString;
    momentPrototype__proto.toJSON = toJSON;
    momentPrototype__proto.toString = toString;
    momentPrototype__proto.unix = unix;
    momentPrototype__proto.valueOf = to_type__valueOf;
    momentPrototype__proto.creationData = creationData;
    // Year
    momentPrototype__proto.year = getSetYear;
    momentPrototype__proto.isLeapYear = getIsLeapYear;
    // Week Year
    momentPrototype__proto.weekYear = getSetWeekYear;
    momentPrototype__proto.isoWeekYear = getSetISOWeekYear;
    // Quarter
    momentPrototype__proto.quarter = momentPrototype__proto.quarters = getSetQuarter;
    // Month
    momentPrototype__proto.month = getSetMonth;
    momentPrototype__proto.daysInMonth = getDaysInMonth;
    // Week
    momentPrototype__proto.week = momentPrototype__proto.weeks = getSetWeek;
    momentPrototype__proto.isoWeek = momentPrototype__proto.isoWeeks = getSetISOWeek;
    momentPrototype__proto.weeksInYear = getWeeksInYear;
    momentPrototype__proto.isoWeeksInYear = getISOWeeksInYear;
    // Day
    momentPrototype__proto.date = getSetDayOfMonth;
    momentPrototype__proto.day = momentPrototype__proto.days = getSetDayOfWeek;
    momentPrototype__proto.weekday = getSetLocaleDayOfWeek;
    momentPrototype__proto.isoWeekday = getSetISODayOfWeek;
    momentPrototype__proto.dayOfYear = getSetDayOfYear;
    // Hour
    momentPrototype__proto.hour = momentPrototype__proto.hours = getSetHour;
    // Minute
    momentPrototype__proto.minute = momentPrototype__proto.minutes = getSetMinute;
    // Second
    momentPrototype__proto.second = momentPrototype__proto.seconds = getSetSecond;
    // Millisecond
    momentPrototype__proto.millisecond = momentPrototype__proto.milliseconds = getSetMillisecond;
    // Offset
    momentPrototype__proto.utcOffset = getSetOffset;
    momentPrototype__proto.utc = setOffsetToUTC;
    momentPrototype__proto.local = setOffsetToLocal;
    momentPrototype__proto.parseZone = setOffsetToParsedOffset;
    momentPrototype__proto.hasAlignedHourOffset = hasAlignedHourOffset;
    momentPrototype__proto.isDST = isDaylightSavingTime;
    momentPrototype__proto.isLocal = isLocal;
    momentPrototype__proto.isUtcOffset = isUtcOffset;
    momentPrototype__proto.isUtc = isUtc;
    momentPrototype__proto.isUTC = isUtc;
    // Timezone
    momentPrototype__proto.zoneAbbr = getZoneAbbr;
    momentPrototype__proto.zoneName = getZoneName;
    // Deprecations
    momentPrototype__proto.dates = deprecate('dates accessor is deprecated. Use date instead.', getSetDayOfMonth);
    momentPrototype__proto.months = deprecate('months accessor is deprecated. Use month instead', getSetMonth);
    momentPrototype__proto.years = deprecate('years accessor is deprecated. Use year instead', getSetYear);
    momentPrototype__proto.zone = deprecate('moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/', getSetZone);
    momentPrototype__proto.isDSTShifted = deprecate('isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information', isDaylightSavingTimeShifted);
    var momentPrototype = momentPrototype__proto;
    function moment__createUnix(input) {
        return local__createLocal(input * 1000);
    }
    function moment__createInZone() {
        return local__createLocal.apply(null, arguments).parseZone();
    }
    function preParsePostFormat(string) {
        return string;
    }
    var prototype__proto = Locale.prototype;
    prototype__proto.calendar = locale_calendar__calendar;
    prototype__proto.longDateFormat = longDateFormat;
    prototype__proto.invalidDate = invalidDate;
    prototype__proto.ordinal = ordinal;
    prototype__proto.preparse = preParsePostFormat;
    prototype__proto.postformat = preParsePostFormat;
    prototype__proto.relativeTime = relative__relativeTime;
    prototype__proto.pastFuture = pastFuture;
    prototype__proto.set = locale_set__set;
    // Month
    prototype__proto.months = localeMonths;
    prototype__proto.monthsShort = localeMonthsShort;
    prototype__proto.monthsParse = localeMonthsParse;
    prototype__proto.monthsRegex = monthsRegex;
    prototype__proto.monthsShortRegex = monthsShortRegex;
    // Week
    prototype__proto.week = localeWeek;
    prototype__proto.firstDayOfYear = localeFirstDayOfYear;
    prototype__proto.firstDayOfWeek = localeFirstDayOfWeek;
    // Day of Week
    prototype__proto.weekdays = localeWeekdays;
    prototype__proto.weekdaysMin = localeWeekdaysMin;
    prototype__proto.weekdaysShort = localeWeekdaysShort;
    prototype__proto.weekdaysParse = localeWeekdaysParse;
    prototype__proto.weekdaysRegex = weekdaysRegex;
    prototype__proto.weekdaysShortRegex = weekdaysShortRegex;
    prototype__proto.weekdaysMinRegex = weekdaysMinRegex;
    // Hours
    prototype__proto.isPM = localeIsPM;
    prototype__proto.meridiem = localeMeridiem;
    function lists__get(format, index, field, setter) {
        var locale = locale_locales__getLocale();
        var utc = create_utc__createUTC().set(setter, index);
        return locale[field](utc, format);
    }
    function listMonthsImpl(format, index, field) {
        if (typeof format === 'number') {
            index = format;
            format = undefined;
        }
        format = format || '';
        if (index != null) {
            return lists__get(format, index, field, 'month');
        }
        var i;
        var out = [];
        for (i = 0; i < 12; i++) {
            out[i] = lists__get(format, i, field, 'month');
        }
        return out;
    }
    // ()
    // (5)
    // (fmt, 5)
    // (fmt)
    // (true)
    // (true, 5)
    // (true, fmt, 5)
    // (true, fmt)
    function listWeekdaysImpl(localeSorted, format, index, field) {
        if (typeof localeSorted === 'boolean') {
            if (typeof format === 'number') {
                index = format;
                format = undefined;
            }
            format = format || '';
        }
        else {
            format = localeSorted;
            index = format;
            localeSorted = false;
            if (typeof format === 'number') {
                index = format;
                format = undefined;
            }
            format = format || '';
        }
        var locale = locale_locales__getLocale(), shift = localeSorted ? locale._week.dow : 0;
        if (index != null) {
            return lists__get(format, (index + shift) % 7, field, 'day');
        }
        var i;
        var out = [];
        for (i = 0; i < 7; i++) {
            out[i] = lists__get(format, (i + shift) % 7, field, 'day');
        }
        return out;
    }
    function lists__listMonths(format, index) {
        return listMonthsImpl(format, index, 'months');
    }
    function lists__listMonthsShort(format, index) {
        return listMonthsImpl(format, index, 'monthsShort');
    }
    function lists__listWeekdays(localeSorted, format, index) {
        return listWeekdaysImpl(localeSorted, format, index, 'weekdays');
    }
    function lists__listWeekdaysShort(localeSorted, format, index) {
        return listWeekdaysImpl(localeSorted, format, index, 'weekdaysShort');
    }
    function lists__listWeekdaysMin(localeSorted, format, index) {
        return listWeekdaysImpl(localeSorted, format, index, 'weekdaysMin');
    }
    locale_locales__getSetGlobalLocale('en', {
        ordinalParse: /\d{1,2}(th|st|nd|rd)/,
        ordinal: function (number) {
            var b = number % 10, output = (toInt(number % 100 / 10) === 1) ? 'th' :
                (b === 1) ? 'st' :
                    (b === 2) ? 'nd' :
                        (b === 3) ? 'rd' : 'th';
            return number + output;
        }
    });
    // Side effect imports
    utils_hooks__hooks.lang = deprecate('moment.lang is deprecated. Use moment.locale instead.', locale_locales__getSetGlobalLocale);
    utils_hooks__hooks.langData = deprecate('moment.langData is deprecated. Use moment.localeData instead.', locale_locales__getLocale);
    var mathAbs = Math.abs;
    function duration_abs__abs() {
        var data = this._data;
        this._milliseconds = mathAbs(this._milliseconds);
        this._days = mathAbs(this._days);
        this._months = mathAbs(this._months);
        data.milliseconds = mathAbs(data.milliseconds);
        data.seconds = mathAbs(data.seconds);
        data.minutes = mathAbs(data.minutes);
        data.hours = mathAbs(data.hours);
        data.months = mathAbs(data.months);
        data.years = mathAbs(data.years);
        return this;
    }
    function duration_add_subtract__addSubtract(duration, input, value, direction) {
        var other = create__createDuration(input, value);
        duration._milliseconds += direction * other._milliseconds;
        duration._days += direction * other._days;
        duration._months += direction * other._months;
        return duration._bubble();
    }
    // supports only 2.0-style add(1, 's') or add(duration)
    function duration_add_subtract__add(input, value) {
        return duration_add_subtract__addSubtract(this, input, value, 1);
    }
    // supports only 2.0-style subtract(1, 's') or subtract(duration)
    function duration_add_subtract__subtract(input, value) {
        return duration_add_subtract__addSubtract(this, input, value, -1);
    }
    function absCeil(number) {
        if (number < 0) {
            return Math.floor(number);
        }
        else {
            return Math.ceil(number);
        }
    }
    function bubble() {
        var milliseconds = this._milliseconds;
        var days = this._days;
        var months = this._months;
        var data = this._data;
        var seconds, minutes, hours, years, monthsFromDays;
        // if we have a mix of positive and negative values, bubble down first
        // check: https://github.com/moment/moment/issues/2166
        if (!((milliseconds >= 0 && days >= 0 && months >= 0) ||
            (milliseconds <= 0 && days <= 0 && months <= 0))) {
            milliseconds += absCeil(monthsToDays(months) + days) * 864e5;
            days = 0;
            months = 0;
        }
        // The following code bubbles up values, see the tests for
        // examples of what that means.
        data.milliseconds = milliseconds % 1000;
        seconds = absFloor(milliseconds / 1000);
        data.seconds = seconds % 60;
        minutes = absFloor(seconds / 60);
        data.minutes = minutes % 60;
        hours = absFloor(minutes / 60);
        data.hours = hours % 24;
        days += absFloor(hours / 24);
        // convert days to months
        monthsFromDays = absFloor(daysToMonths(days));
        months += monthsFromDays;
        days -= absCeil(monthsToDays(monthsFromDays));
        // 12 months -> 1 year
        years = absFloor(months / 12);
        months %= 12;
        data.days = days;
        data.months = months;
        data.years = years;
        return this;
    }
    function daysToMonths(days) {
        // 400 years have 146097 days (taking into account leap year rules)
        // 400 years have 12 months === 4800
        return days * 4800 / 146097;
    }
    function monthsToDays(months) {
        // the reverse of daysToMonths
        return months * 146097 / 4800;
    }
    function as(units) {
        var days;
        var months;
        var milliseconds = this._milliseconds;
        units = normalizeUnits(units);
        if (units === 'month' || units === 'year') {
            days = this._days + milliseconds / 864e5;
            months = this._months + daysToMonths(days);
            return units === 'month' ? months : months / 12;
        }
        else {
            // handle milliseconds separately because of floating point math errors (issue #1867)
            days = this._days + Math.round(monthsToDays(this._months));
            switch (units) {
                case 'week': return days / 7 + milliseconds / 6048e5;
                case 'day': return days + milliseconds / 864e5;
                case 'hour': return days * 24 + milliseconds / 36e5;
                case 'minute': return days * 1440 + milliseconds / 6e4;
                case 'second': return days * 86400 + milliseconds / 1000;
                // Math.floor prevents floating point math errors here
                case 'millisecond': return Math.floor(days * 864e5) + milliseconds;
                default: throw new Error('Unknown unit ' + units);
            }
        }
    }
    // TODO: Use this.as('ms')?
    function duration_as__valueOf() {
        return (this._milliseconds +
            this._days * 864e5 +
            (this._months % 12) * 2592e6 +
            toInt(this._months / 12) * 31536e6);
    }
    function makeAs(alias) {
        return function () {
            return this.as(alias);
        };
    }
    var asMilliseconds = makeAs('ms');
    var asSeconds = makeAs('s');
    var asMinutes = makeAs('m');
    var asHours = makeAs('h');
    var asDays = makeAs('d');
    var asWeeks = makeAs('w');
    var asMonths = makeAs('M');
    var asYears = makeAs('y');
    function duration_get__get(units) {
        units = normalizeUnits(units);
        return this[units + 's']();
    }
    function makeGetter(name) {
        return function () {
            return this._data[name];
        };
    }
    var milliseconds = makeGetter('milliseconds');
    var seconds = makeGetter('seconds');
    var minutes = makeGetter('minutes');
    var hours = makeGetter('hours');
    var days = makeGetter('days');
    var months = makeGetter('months');
    var years = makeGetter('years');
    function weeks() {
        return absFloor(this.days() / 7);
    }
    var round = Math.round;
    var thresholds = {
        s: 45,
        m: 45,
        h: 22,
        d: 26,
        M: 11 // months to year
    };
    // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize
    function substituteTimeAgo(string, number, withoutSuffix, isFuture, locale) {
        return locale.relativeTime(number || 1, !!withoutSuffix, string, isFuture);
    }
    function duration_humanize__relativeTime(posNegDuration, withoutSuffix, locale) {
        var duration = create__createDuration(posNegDuration).abs();
        var seconds = round(duration.as('s'));
        var minutes = round(duration.as('m'));
        var hours = round(duration.as('h'));
        var days = round(duration.as('d'));
        var months = round(duration.as('M'));
        var years = round(duration.as('y'));
        var a = seconds < thresholds.s && ['s', seconds] ||
            minutes <= 1 && ['m'] ||
            minutes < thresholds.m && ['mm', minutes] ||
            hours <= 1 && ['h'] ||
            hours < thresholds.h && ['hh', hours] ||
            days <= 1 && ['d'] ||
            days < thresholds.d && ['dd', days] ||
            months <= 1 && ['M'] ||
            months < thresholds.M && ['MM', months] ||
            years <= 1 && ['y'] || ['yy', years];
        a[2] = withoutSuffix;
        a[3] = +posNegDuration > 0;
        a[4] = locale;
        return substituteTimeAgo.apply(null, a);
    }
    // This function allows you to set the rounding function for relative time strings
    function duration_humanize__getSetRelativeTimeRounding(roundingFunction) {
        if (roundingFunction === undefined) {
            return round;
        }
        if (typeof (roundingFunction) === 'function') {
            round = roundingFunction;
            return true;
        }
        return false;
    }
    // This function allows you to set a threshold for relative time strings
    function duration_humanize__getSetRelativeTimeThreshold(threshold, limit) {
        if (thresholds[threshold] === undefined) {
            return false;
        }
        if (limit === undefined) {
            return thresholds[threshold];
        }
        thresholds[threshold] = limit;
        return true;
    }
    function humanize(withSuffix) {
        var locale = this.localeData();
        var output = duration_humanize__relativeTime(this, !withSuffix, locale);
        if (withSuffix) {
            output = locale.pastFuture(+this, output);
        }
        return locale.postformat(output);
    }
    var iso_string__abs = Math.abs;
    function iso_string__toISOString() {
        // for ISO strings we do not use the normal bubbling rules:
        //  * milliseconds bubble up until they become hours
        //  * days do not bubble at all
        //  * months bubble up until they become years
        // This is because there is no context-free conversion between hours and days
        // (think of clock changes)
        // and also not between days and months (28-31 days per month)
        var seconds = iso_string__abs(this._milliseconds) / 1000;
        var days = iso_string__abs(this._days);
        var months = iso_string__abs(this._months);
        var minutes, hours, years;
        // 3600 seconds -> 60 minutes -> 1 hour
        minutes = absFloor(seconds / 60);
        hours = absFloor(minutes / 60);
        seconds %= 60;
        minutes %= 60;
        // 12 months -> 1 year
        years = absFloor(months / 12);
        months %= 12;
        // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js
        var Y = years;
        var M = months;
        var D = days;
        var h = hours;
        var m = minutes;
        var s = seconds;
        var total = this.asSeconds();
        if (!total) {
            // this is the same as C#'s (Noda) and python (isodate)...
            // but not other JS (goog.date)
            return 'P0D';
        }
        return (total < 0 ? '-' : '') +
            'P' +
            (Y ? Y + 'Y' : '') +
            (M ? M + 'M' : '') +
            (D ? D + 'D' : '') +
            ((h || m || s) ? 'T' : '') +
            (h ? h + 'H' : '') +
            (m ? m + 'M' : '') +
            (s ? s + 'S' : '');
    }
    var duration_prototype__proto = Duration.prototype;
    duration_prototype__proto.abs = duration_abs__abs;
    duration_prototype__proto.add = duration_add_subtract__add;
    duration_prototype__proto.subtract = duration_add_subtract__subtract;
    duration_prototype__proto.as = as;
    duration_prototype__proto.asMilliseconds = asMilliseconds;
    duration_prototype__proto.asSeconds = asSeconds;
    duration_prototype__proto.asMinutes = asMinutes;
    duration_prototype__proto.asHours = asHours;
    duration_prototype__proto.asDays = asDays;
    duration_prototype__proto.asWeeks = asWeeks;
    duration_prototype__proto.asMonths = asMonths;
    duration_prototype__proto.asYears = asYears;
    duration_prototype__proto.valueOf = duration_as__valueOf;
    duration_prototype__proto._bubble = bubble;
    duration_prototype__proto.get = duration_get__get;
    duration_prototype__proto.milliseconds = milliseconds;
    duration_prototype__proto.seconds = seconds;
    duration_prototype__proto.minutes = minutes;
    duration_prototype__proto.hours = hours;
    duration_prototype__proto.days = days;
    duration_prototype__proto.weeks = weeks;
    duration_prototype__proto.months = months;
    duration_prototype__proto.years = years;
    duration_prototype__proto.humanize = humanize;
    duration_prototype__proto.toISOString = iso_string__toISOString;
    duration_prototype__proto.toString = iso_string__toISOString;
    duration_prototype__proto.toJSON = iso_string__toISOString;
    duration_prototype__proto.locale = locale;
    duration_prototype__proto.localeData = localeData;
    // Deprecations
    duration_prototype__proto.toIsoString = deprecate('toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)', iso_string__toISOString);
    duration_prototype__proto.lang = lang;
    // Side effect imports
    // FORMATTING
    addFormatToken('X', 0, 0, 'unix');
    addFormatToken('x', 0, 0, 'valueOf');
    // PARSING
    addRegexToken('x', matchSigned);
    addRegexToken('X', matchTimestamp);
    addParseToken('X', function (input, array, config) {
        config._d = new Date(parseFloat(input, 10) * 1000);
    });
    addParseToken('x', function (input, array, config) {
        config._d = new Date(toInt(input));
    });
    // Side effect imports
    utils_hooks__hooks.version = '2.14.1';
    setHookCallback(local__createLocal);
    utils_hooks__hooks.fn = momentPrototype;
    utils_hooks__hooks.min = min;
    utils_hooks__hooks.max = max;
    utils_hooks__hooks.now = now;
    utils_hooks__hooks.utc = create_utc__createUTC;
    utils_hooks__hooks.unix = moment__createUnix;
    utils_hooks__hooks.months = lists__listMonths;
    utils_hooks__hooks.isDate = isDate;
    utils_hooks__hooks.locale = locale_locales__getSetGlobalLocale;
    utils_hooks__hooks.invalid = valid__createInvalid;
    utils_hooks__hooks.duration = create__createDuration;
    utils_hooks__hooks.isMoment = isMoment;
    utils_hooks__hooks.weekdays = lists__listWeekdays;
    utils_hooks__hooks.parseZone = moment__createInZone;
    utils_hooks__hooks.localeData = locale_locales__getLocale;
    utils_hooks__hooks.isDuration = isDuration;
    utils_hooks__hooks.monthsShort = lists__listMonthsShort;
    utils_hooks__hooks.weekdaysMin = lists__listWeekdaysMin;
    utils_hooks__hooks.defineLocale = defineLocale;
    utils_hooks__hooks.updateLocale = updateLocale;
    utils_hooks__hooks.locales = locale_locales__listLocales;
    utils_hooks__hooks.weekdaysShort = lists__listWeekdaysShort;
    utils_hooks__hooks.normalizeUnits = normalizeUnits;
    utils_hooks__hooks.relativeTimeRounding = duration_humanize__getSetRelativeTimeRounding;
    utils_hooks__hooks.relativeTimeThreshold = duration_humanize__getSetRelativeTimeThreshold;
    utils_hooks__hooks.calendarFormat = getCalendarFormat;
    utils_hooks__hooks.prototype = momentPrototype;
    var _moment = utils_hooks__hooks;
    return _moment;
}));
//# sourceMappingURL=5. moment.js.map 
//# sourceMappingURL=5. moment.js.map 
//# sourceMappingURL=5. moment.js.map 
//# sourceMappingURL=5. moment.js.map 
//# sourceMappingURL=5. moment.js.map 
//# sourceMappingURL=5. moment.js.map 
//# sourceMappingURL=5. moment.js.map 
//# sourceMappingURL=5. moment.js.map 
//# sourceMappingURL=5. moment.js.map 
//# sourceMappingURL=5. moment.js.map;
!function () {
    "use strict";
    function t() {
        var t = { parent: document.body, version: "1.0.11", defaultOkLabel: "Ok", okLabel: "Ok", defaultCancelLabel: "Cancel", cancelLabel: "Cancel", defaultMaxLogItems: 2, maxLogItems: 2, promptValue: "", promptPlaceholder: "", closeLogOnClick: !1, closeLogOnClickDefault: !1, delay: 5e3, defaultDelay: 5e3, logContainerClass: "alertify-logs", logContainerDefaultClass: "alertify-logs", dialogs: { buttons: { holder: "<nav>{{buttons}}</nav>", ok: "<button class='ok' tabindex='1'>{{ok}}</button>", cancel: "<button class='cancel' tabindex='2'>{{cancel}}</button>" }, input: "<input type='text'>", message: "<p class='msg'>{{message}}</p>", log: "<div class='{{class}}'>{{message}}</div>" }, defaultDialogs: { buttons: { holder: "<nav>{{buttons}}</nav>", ok: "<button class='ok' tabindex='1'>{{ok}}</button>", cancel: "<button class='cancel' tabindex='2'>{{cancel}}</button>" }, input: "<input type='text'>", message: "<p class='msg'>{{message}}</p>", log: "<div class='{{class}}'>{{message}}</div>" }, build: function (t) { var e = this.dialogs.buttons.ok, o = "<div class='dialog'><div>" + this.dialogs.message.replace("{{message}}", t.message); return "confirm" !== t.type && "prompt" !== t.type || (e = this.dialogs.buttons.cancel + this.dialogs.buttons.ok), "prompt" === t.type && (o += this.dialogs.input), o = (o + this.dialogs.buttons.holder + "</div></div>").replace("{{buttons}}", e).replace("{{ok}}", this.okLabel).replace("{{cancel}}", this.cancelLabel); }, setCloseLogOnClick: function (t) { this.closeLogOnClick = !!t; }, close: function (t, e) { this.closeLogOnClick && t.addEventListener("click", function () { o(t); }), e = e && !isNaN(+e) ? +e : this.delay, 0 > e ? o(t) : e > 0 && setTimeout(function () { o(t); }, e); }, dialog: function (t, e, o, n) { return this.setup({ type: e, message: t, onOkay: o, onCancel: n }); }, log: function (t, e, o) {
                var n = document.querySelectorAll(".alertify-logs > div");
                if (n) {
                    var i = n.length - this.maxLogItems;
                    if (i >= 0)
                        for (var a = 0, l = i + 1; l > a; a++)
                            this.close(n[a], -1);
                }
                this.notify(t, e, o);
            }, setLogPosition: function (t) { this.logContainerClass = "alertify-logs " + t; }, setupLogContainer: function () { var t = document.querySelector(".alertify-logs"), e = this.logContainerClass; return t || (t = document.createElement("div"), t.className = e, this.parent.appendChild(t)), t.className !== e && (t.className = e), t; }, notify: function (e, o, n) { var i = this.setupLogContainer(), a = document.createElement("div"); a.className = o || "default", t.logTemplateMethod ? a.innerHTML = t.logTemplateMethod(e) : a.innerHTML = e, "function" == typeof n && a.addEventListener("click", n), i.appendChild(a), setTimeout(function () { a.className += " show"; }, 10), this.close(a, this.delay); }, setup: function (t) { function e(e) { "function" != typeof e && (e = function () { }), i && i.addEventListener("click", function (i) { t.onOkay && "function" == typeof t.onOkay && (l ? t.onOkay(l.value, i) : t.onOkay(i)), e(l ? { buttonClicked: "ok", inputValue: l.value, event: i } : { buttonClicked: "ok", event: i }), o(n); }), a && a.addEventListener("click", function (i) { t.onCancel && "function" == typeof t.onCancel && t.onCancel(i), e({ buttonClicked: "cancel", event: i }), o(n); }), l && l.addEventListener("keyup", function (t) { 13 === t.which && i.click(); }); } var n = document.createElement("div"); n.className = "alertify hide", n.innerHTML = this.build(t); var i = n.querySelector(".ok"), a = n.querySelector(".cancel"), l = n.querySelector("input"), s = n.querySelector("label"); l && ("string" == typeof this.promptPlaceholder && (s ? s.textContent = this.promptPlaceholder : l.placeholder = this.promptPlaceholder), "string" == typeof this.promptValue && (l.value = this.promptValue)); var r; return "function" == typeof Promise ? r = new Promise(e) : e(), this.parent.appendChild(n), setTimeout(function () { n.classList.remove("hide"), l && t.type && "prompt" === t.type ? (l.select(), l.focus()) : i && i.focus(); }, 100), r; }, okBtn: function (t) { return this.okLabel = t, this; }, setDelay: function (t) { return t = t || 0, this.delay = isNaN(t) ? this.defaultDelay : parseInt(t, 10), this; }, cancelBtn: function (t) { return this.cancelLabel = t, this; }, setMaxLogItems: function (t) { this.maxLogItems = parseInt(t || this.defaultMaxLogItems); }, theme: function (t) {
                switch (t.toLowerCase()) {
                    case "bootstrap":
                        this.dialogs.buttons.ok = "<button class='ok btn btn-primary' tabindex='1'>{{ok}}</button>", this.dialogs.buttons.cancel = "<button class='cancel btn btn-default' tabindex='2'>{{cancel}}</button>", this.dialogs.input = "<input type='text' class='form-control'>";
                        break;
                    case "purecss":
                        this.dialogs.buttons.ok = "<button class='ok pure-button' tabindex='1'>{{ok}}</button>", this.dialogs.buttons.cancel = "<button class='cancel pure-button' tabindex='2'>{{cancel}}</button>";
                        break;
                    case "mdl":
                    case "material-design-light":
                        this.dialogs.buttons.ok = "<button class='ok mdl-button mdl-js-button mdl-js-ripple-effect'  tabindex='1'>{{ok}}</button>", this.dialogs.buttons.cancel = "<button class='cancel mdl-button mdl-js-button mdl-js-ripple-effect' tabindex='2'>{{cancel}}</button>", this.dialogs.input = "<div class='mdl-textfield mdl-js-textfield'><input class='mdl-textfield__input'><label class='md-textfield__label'></label></div>";
                        break;
                    case "angular-material":
                        this.dialogs.buttons.ok = "<button class='ok md-primary md-button' tabindex='1'>{{ok}}</button>", this.dialogs.buttons.cancel = "<button class='cancel md-button' tabindex='2'>{{cancel}}</button>", this.dialogs.input = "<div layout='column'><md-input-container md-no-float><input type='text'></md-input-container></div>";
                        break;
                    case "default":
                    default: this.dialogs.buttons.ok = this.defaultDialogs.buttons.ok, this.dialogs.buttons.cancel = this.defaultDialogs.buttons.cancel, this.dialogs.input = this.defaultDialogs.input;
                }
            }, reset: function () { this.parent = document.body, this.theme("default"), this.okBtn(this.defaultOkLabel), this.cancelBtn(this.defaultCancelLabel), this.setMaxLogItems(), this.promptValue = "", this.promptPlaceholder = "", this.delay = this.defaultDelay, this.setCloseLogOnClick(this.closeLogOnClickDefault), this.setLogPosition("bottom left"), this.logTemplateMethod = null; }, injectCSS: function () {
                if (!document.querySelector("#alertifyCSS")) {
                    var t = document.getElementsByTagName("head")[0], e = document.createElement("style");
                    e.type = "text/css", e.id = "alertifyCSS", e.innerHTML = ".alertify-logs>*{padding:12px 24px;color:#fff;box-shadow:0 2px 5px 0 rgba(0,0,0,.2);border-radius:1px}.alertify-logs>*,.alertify-logs>.default{background:rgba(0,0,0,.8)}.alertify-logs>.error{background:rgba(244,67,54,.8)}.alertify-logs>.success{background:rgba(76,175,80,.9)}.alertify{position:fixed;background-color:rgba(0,0,0,.3);left:0;right:0;top:0;bottom:0;width:100%;height:100%;z-index:1}.alertify.hide{opacity:0;pointer-events:none}.alertify,.alertify.show{box-sizing:border-box;transition:all .33s cubic-bezier(.25,.8,.25,1)}.alertify,.alertify *{box-sizing:border-box}.alertify .dialog{padding:12px}.alertify .alert,.alertify .dialog{width:100%;margin:0 auto;position:relative;top:50%;transform:translateY(-50%)}.alertify .alert>*,.alertify .dialog>*{width:400px;max-width:95%;margin:0 auto;text-align:center;padding:12px;background:#fff;box-shadow:0 2px 4px -1px rgba(0,0,0,.14),0 4px 5px 0 rgba(0,0,0,.098),0 1px 10px 0 rgba(0,0,0,.084)}.alertify .alert .msg,.alertify .dialog .msg{padding:12px;margin-bottom:12px;margin:0;text-align:left}.alertify .alert input:not(.form-control),.alertify .dialog input:not(.form-control){margin-bottom:15px;width:100%;font-size:100%;padding:12px}.alertify .alert input:not(.form-control):focus,.alertify .dialog input:not(.form-control):focus{outline-offset:-2px}.alertify .alert nav,.alertify .dialog nav{text-align:right}.alertify .alert nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button),.alertify .dialog nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button){background:transparent;box-sizing:border-box;color:rgba(0,0,0,.87);position:relative;outline:0;border:0;display:inline-block;-ms-flex-align:center;-ms-grid-row-align:center;align-items:center;padding:0 6px;margin:6px 8px;line-height:36px;min-height:36px;white-space:nowrap;min-width:88px;text-align:center;text-transform:uppercase;font-size:14px;text-decoration:none;cursor:pointer;border:1px solid transparent;border-radius:2px}.alertify .alert nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button):active,.alertify .alert nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button):hover,.alertify .dialog nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button):active,.alertify .dialog nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button):hover{background-color:rgba(0,0,0,.05)}.alertify .alert nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button):focus,.alertify .dialog nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button):focus{border:1px solid rgba(0,0,0,.1)}.alertify .alert nav button.btn,.alertify .dialog nav button.btn{margin:6px 4px}.alertify-logs{position:fixed;z-index:1}.alertify-logs.bottom,.alertify-logs:not(.top){bottom:16px}.alertify-logs.left,.alertify-logs:not(.right){left:16px}.alertify-logs.left>*,.alertify-logs:not(.right)>*{float:left;transform:translateZ(0);height:auto}.alertify-logs.left>.show,.alertify-logs:not(.right)>.show{left:0}.alertify-logs.left>*,.alertify-logs.left>.hide,.alertify-logs:not(.right)>*,.alertify-logs:not(.right)>.hide{left:-110%}.alertify-logs.right{right:16px}.alertify-logs.right>*{float:right;transform:translateZ(0)}.alertify-logs.right>.show{right:0;opacity:1}.alertify-logs.right>*,.alertify-logs.right>.hide{right:-110%;opacity:0}.alertify-logs.top{top:0}.alertify-logs>*{box-sizing:border-box;transition:all .4s cubic-bezier(.25,.8,.25,1);position:relative;clear:both;backface-visibility:hidden;perspective:1000;max-height:0;margin:0;padding:0;overflow:hidden;opacity:0;pointer-events:none}.alertify-logs>.show{margin-top:12px;opacity:1;max-height:1000px;padding:12px;pointer-events:auto}", t.insertBefore(e, t.firstChild);
                }
            }, removeCSS: function () { var t = document.querySelector("#alertifyCSS"); t && t.parentNode && t.parentNode.removeChild(t); } };
        return t.injectCSS(), { _$$alertify: t, parent: function (e) { t.parent = e; }, reset: function () { return t.reset(), this; }, alert: function (e, o, n) { return t.dialog(e, "alert", o, n) || this; }, confirm: function (e, o, n) { return t.dialog(e, "confirm", o, n) || this; }, prompt: function (e, o, n) { return t.dialog(e, "prompt", o, n) || this; }, log: function (e, o) { return t.log(e, "default", o), this; }, theme: function (e) { return t.theme(e), this; }, success: function (e, o) { return t.log(e, "success", o), this; }, error: function (e, o) { return t.log(e, "error", o), this; }, cancelBtn: function (e) { return t.cancelBtn(e), this; }, okBtn: function (e) { return t.okBtn(e), this; }, delay: function (e) { return t.setDelay(e), this; }, placeholder: function (e) { return t.promptPlaceholder = e, this; }, defaultValue: function (e) { return t.promptValue = e, this; }, maxLogItems: function (e) { return t.setMaxLogItems(e), this; }, closeLogOnClick: function (e) { return t.setCloseLogOnClick(!!e), this; }, logPosition: function (e) { return t.setLogPosition(e || ""), this; }, setLogTemplate: function (e) { return t.logTemplateMethod = e, this; }, clearLogs: function () { return t.setupLogContainer().innerHTML = "", this; }, version: t.version };
    }
    var e = 500, o = function (t) {
        if (t) {
            var o = function () { t && t.parentNode && t.parentNode.removeChild(t); };
            t.classList.remove("show"), t.classList.add("hide"), t.addEventListener("transitionend", o), setTimeout(o, e);
        }
    };
    if ("undefined" != typeof module && module && module.exports) {
        module.exports = function () { return new t; };
        var n = new t;
        for (var i in n)
            module.exports[i] = n[i];
    }
    else
        "function" == typeof define && define.amd ? define(function () { return new t; }) : window.alertify = new t;
}();
//# sourceMappingURL=alertify.js.map 
//# sourceMappingURL=alertify.js.map 
//# sourceMappingURL=alertify.js.map 
//# sourceMappingURL=alertify.js.map;
/*! version : 4.17.46
 =========================================================
 bootstrap-datetimejs
 https://github.com/Eonasdan/bootstrap-datetimepicker
 Copyright (c) 2015 Jonathan Peterson
 =========================================================
 */
/*
 The MIT License (MIT)

 Copyright (c) 2015 Jonathan Peterson

 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.
 */
/*global define:false */
/*global exports:false */
/*global require:false */
/*global jQuery:false */
/*global moment:false */
(function (factory) {
    'use strict';
    if (typeof define === 'function' && define.amd) {
        // AMD is used - Register as an anonymous module.
        define(['jquery', 'moment'], factory);
    }
    else if (typeof exports === 'object') {
        module.exports = factory(require('jquery'), require('moment'));
    }
    else {
        // Neither AMD nor CommonJS used. Use global variables.
        if (typeof jQuery === 'undefined') {
            throw 'bootstrap-datetimepicker requires jQuery to be loaded first';
        }
        if (typeof moment === 'undefined') {
            throw 'bootstrap-datetimepicker requires Moment.js to be loaded first';
        }
        factory(jQuery, moment);
    }
}(function ($, moment) {
    'use strict';
    if (!moment) {
        throw new Error('bootstrap-datetimepicker requires Moment.js to be loaded first');
    }
    var dateTimePicker = function (element, options) {
        var picker = {}, date, viewDate, unset = true, input, component = false, widget = false, use24Hours, minViewModeNumber = 0, actualFormat, parseFormats, currentViewMode, datePickerModes = [
            {
                clsName: 'days',
                navFnc: 'M',
                navStep: 1
            },
            {
                clsName: 'months',
                navFnc: 'y',
                navStep: 1
            },
            {
                clsName: 'years',
                navFnc: 'y',
                navStep: 10
            },
            {
                clsName: 'decades',
                navFnc: 'y',
                navStep: 100
            }
        ], viewModes = ['days', 'months', 'years', 'decades'], verticalModes = ['top', 'bottom', 'auto'], horizontalModes = ['left', 'right', 'auto'], toolbarPlacements = ['default', 'top', 'bottom'], keyMap = {
            'up': 38,
            38: 'up',
            'down': 40,
            40: 'down',
            'left': 37,
            37: 'left',
            'right': 39,
            39: 'right',
            'tab': 9,
            9: 'tab',
            'escape': 27,
            27: 'escape',
            'enter': 13,
            13: 'enter',
            'pageUp': 33,
            33: 'pageUp',
            'pageDown': 34,
            34: 'pageDown',
            'shift': 16,
            16: 'shift',
            'control': 17,
            17: 'control',
            'space': 32,
            32: 'space',
            't': 84,
            84: 't',
            'delete': 46,
            46: 'delete'
        }, keyState = {}, 
        /********************************************************************************
         *
         * Private functions
         *
         ********************************************************************************/
        hasTimeZone = function () {
            return moment.tz !== undefined && options.timeZone !== undefined && options.timeZone !== null && options.timeZone !== '';
        }, getMoment = function (d) {
            var returnMoment;
            if (d === undefined || d === null) {
                returnMoment = moment(); //TODO should this use format? and locale?
            }
            else if (moment.isDate(d) || moment.isMoment(d)) {
                // If the date that is passed in is already a Date() or moment() object,
                // pass it directly to moment.
                returnMoment = moment(d);
            }
            else if (hasTimeZone()) {
                // parse with the tz function which takes a default time zone if it is not in the format string
                returnMoment = moment.tz(d, parseFormats, options.useStrict, options.timeZone);
            }
            else {
                returnMoment = moment(d, parseFormats, options.useStrict);
            }
            if (hasTimeZone()) {
                returnMoment.tz(options.timeZone);
            }
            return returnMoment;
        }, isEnabled = function (granularity) {
            if (typeof granularity !== 'string' || granularity.length > 1) {
                throw new TypeError('isEnabled expects a single character string parameter');
            }
            switch (granularity) {
                case 'y':
                    return actualFormat.indexOf('Y') !== -1;
                case 'M':
                    return actualFormat.indexOf('M') !== -1;
                case 'd':
                    return actualFormat.toLowerCase().indexOf('d') !== -1;
                case 'h':
                case 'H':
                    return actualFormat.toLowerCase().indexOf('h') !== -1;
                case 'm':
                    return actualFormat.indexOf('m') !== -1;
                case 's':
                    return actualFormat.indexOf('s') !== -1;
                default:
                    return false;
            }
        }, hasTime = function () {
            return (isEnabled('h') || isEnabled('m') || isEnabled('s'));
        }, hasDate = function () {
            return (isEnabled('y') || isEnabled('M') || isEnabled('d'));
        }, getDatePickerTemplate = function () {
            var headTemplate = $('<thead>')
                .append($('<tr>')
                .append($('<th>').addClass('prev').attr('data-action', 'previous')
                .append($('<span>').addClass(options.icons.previous)))
                .append($('<th>').addClass('picker-switch').attr('data-action', 'pickerSwitch').attr('colspan', (options.calendarWeeks ? '6' : '5')))
                .append($('<th>').addClass('next').attr('data-action', 'next')
                .append($('<span>').addClass(options.icons.next)))), contTemplate = $('<tbody>')
                .append($('<tr>')
                .append($('<td>').attr('colspan', (options.calendarWeeks ? '8' : '7'))));
            return [
                $('<div>').addClass('datepicker-days')
                    .append($('<table>').addClass('table-condensed')
                    .append(headTemplate)
                    .append($('<tbody>'))),
                $('<div>').addClass('datepicker-months')
                    .append($('<table>').addClass('table-condensed')
                    .append(headTemplate.clone())
                    .append(contTemplate.clone())),
                $('<div>').addClass('datepicker-years')
                    .append($('<table>').addClass('table-condensed')
                    .append(headTemplate.clone())
                    .append(contTemplate.clone())),
                $('<div>').addClass('datepicker-decades')
                    .append($('<table>').addClass('table-condensed')
                    .append(headTemplate.clone())
                    .append(contTemplate.clone()))
            ];
        }, getTimePickerMainTemplate = function () {
            var topRow = $('<tr>'), middleRow = $('<tr>'), bottomRow = $('<tr>');
            if (isEnabled('h')) {
                topRow.append($('<td>')
                    .append($('<a>').attr({ href: '#', tabindex: '-1', 'title': options.tooltips.incrementHour }).addClass('btn').attr('data-action', 'incrementHours').append($('<span>').addClass(options.icons.up))));
                middleRow.append($('<td>')
                    .append($('<span>').addClass('timepicker-hour').attr({ 'data-time-component': 'hours', 'title': options.tooltips.pickHour }).attr('data-action', 'showHours')));
                bottomRow.append($('<td>')
                    .append($('<a>').attr({ href: '#', tabindex: '-1', 'title': options.tooltips.decrementHour }).addClass('btn').attr('data-action', 'decrementHours').append($('<span>').addClass(options.icons.down))));
            }
            if (isEnabled('m')) {
                if (isEnabled('h')) {
                    topRow.append($('<td>').addClass('separator'));
                    middleRow.append($('<td>').addClass('separator').html(':'));
                    bottomRow.append($('<td>').addClass('separator'));
                }
                topRow.append($('<td>')
                    .append($('<a>').attr({ href: '#', tabindex: '-1', 'title': options.tooltips.incrementMinute }).addClass('btn').attr('data-action', 'incrementMinutes')
                    .append($('<span>').addClass(options.icons.up))));
                middleRow.append($('<td>')
                    .append($('<span>').addClass('timepicker-minute').attr({ 'data-time-component': 'minutes', 'title': options.tooltips.pickMinute }).attr('data-action', 'showMinutes')));
                bottomRow.append($('<td>')
                    .append($('<a>').attr({ href: '#', tabindex: '-1', 'title': options.tooltips.decrementMinute }).addClass('btn').attr('data-action', 'decrementMinutes')
                    .append($('<span>').addClass(options.icons.down))));
            }
            if (isEnabled('s')) {
                if (isEnabled('m')) {
                    topRow.append($('<td>').addClass('separator'));
                    middleRow.append($('<td>').addClass('separator').html(':'));
                    bottomRow.append($('<td>').addClass('separator'));
                }
                topRow.append($('<td>')
                    .append($('<a>').attr({ href: '#', tabindex: '-1', 'title': options.tooltips.incrementSecond }).addClass('btn').attr('data-action', 'incrementSeconds')
                    .append($('<span>').addClass(options.icons.up))));
                middleRow.append($('<td>')
                    .append($('<span>').addClass('timepicker-second').attr({ 'data-time-component': 'seconds', 'title': options.tooltips.pickSecond }).attr('data-action', 'showSeconds')));
                bottomRow.append($('<td>')
                    .append($('<a>').attr({ href: '#', tabindex: '-1', 'title': options.tooltips.decrementSecond }).addClass('btn').attr('data-action', 'decrementSeconds')
                    .append($('<span>').addClass(options.icons.down))));
            }
            if (!use24Hours) {
                topRow.append($('<td>').addClass('separator'));
                middleRow.append($('<td>')
                    .append($('<button>').addClass('btn btn-primary').attr({ 'data-action': 'togglePeriod', tabindex: '-1', 'title': options.tooltips.togglePeriod })));
                bottomRow.append($('<td>').addClass('separator'));
            }
            return $('<div>').addClass('timepicker-picker')
                .append($('<table>').addClass('table-condensed')
                .append([topRow, middleRow, bottomRow]));
        }, getTimePickerTemplate = function () {
            var hoursView = $('<div>').addClass('timepicker-hours')
                .append($('<table>').addClass('table-condensed')), minutesView = $('<div>').addClass('timepicker-minutes')
                .append($('<table>').addClass('table-condensed')), secondsView = $('<div>').addClass('timepicker-seconds')
                .append($('<table>').addClass('table-condensed')), ret = [getTimePickerMainTemplate()];
            if (isEnabled('h')) {
                ret.push(hoursView);
            }
            if (isEnabled('m')) {
                ret.push(minutesView);
            }
            if (isEnabled('s')) {
                ret.push(secondsView);
            }
            return ret;
        }, getToolbar = function () {
            var row = [];
            if (options.showTodayButton) {
                row.push($('<td>').append($('<a>').attr({ 'data-action': 'today', 'title': options.tooltips.today }).append($('<span>').addClass(options.icons.today))));
            }
            if (!options.sideBySide && hasDate() && hasTime()) {
                row.push($('<td>').append($('<a>').attr({ 'data-action': 'togglePicker', 'title': options.tooltips.selectTime }).append($('<span>').addClass(options.icons.time))));
            }
            if (options.showClear) {
                row.push($('<td>').append($('<a>').attr({ 'data-action': 'clear', 'title': options.tooltips.clear }).append($('<span>').addClass(options.icons.clear))));
            }
            if (options.showClose) {
                row.push($('<td>').append($('<a>').attr({ 'data-action': 'close', 'title': options.tooltips.close }).append($('<span>').addClass(options.icons.close))));
            }
            return $('<table>').addClass('table-condensed').append($('<tbody>').append($('<tr>').append(row)));
        }, getTemplate = function () {
            var template = $('<div>').addClass('bootstrap-datetimepicker-widget dropdown-menu'), dateView = $('<div>').addClass('datepicker').append(getDatePickerTemplate()), timeView = $('<div>').addClass('timepicker').append(getTimePickerTemplate()), content = $('<ul>').addClass('list-unstyled'), toolbar = $('<li>').addClass('picker-switch' + (options.collapse ? ' accordion-toggle' : '')).append(getToolbar());
            if (options.inline) {
                template.removeClass('dropdown-menu');
            }
            if (use24Hours) {
                template.addClass('usetwentyfour');
            }
            if (isEnabled('s') && !use24Hours) {
                template.addClass('wider');
            }
            if (options.sideBySide && hasDate() && hasTime()) {
                template.addClass('timepicker-sbs');
                if (options.toolbarPlacement === 'top') {
                    template.append(toolbar);
                }
                template.append($('<div>').addClass('row')
                    .append(dateView.addClass('col-md-6'))
                    .append(timeView.addClass('col-md-6')));
                if (options.toolbarPlacement === 'bottom') {
                    template.append(toolbar);
                }
                return template;
            }
            if (options.toolbarPlacement === 'top') {
                content.append(toolbar);
            }
            if (hasDate()) {
                content.append($('<li>').addClass((options.collapse && hasTime() ? 'collapse in' : '')).append(dateView));
            }
            if (options.toolbarPlacement === 'default') {
                content.append(toolbar);
            }
            if (hasTime()) {
                content.append($('<li>').addClass((options.collapse && hasDate() ? 'collapse' : '')).append(timeView));
            }
            if (options.toolbarPlacement === 'bottom') {
                content.append(toolbar);
            }
            return template.append(content);
        }, dataToOptions = function () {
            var eData, dataOptions = {};
            if (element.is('input') || options.inline) {
                eData = element.data();
            }
            else {
                eData = element.find('input').data();
            }
            if (eData.dateOptions && eData.dateOptions instanceof Object) {
                dataOptions = $.extend(true, dataOptions, eData.dateOptions);
            }
            $.each(options, function (key) {
                var attributeName = 'date' + key.charAt(0).toUpperCase() + key.slice(1);
                if (eData[attributeName] !== undefined) {
                    dataOptions[key] = eData[attributeName];
                }
            });
            return dataOptions;
        }, place = function () {
            var position = (component || element).position(), offset = (component || element).offset(), vertical = options.widgetPositioning.vertical, horizontal = options.widgetPositioning.horizontal, parent;
            if (options.widgetParent) {
                parent = options.widgetParent.append(widget);
            }
            else if (element.is('input')) {
                parent = element.after(widget).parent();
            }
            else if (options.inline) {
                parent = element.append(widget);
                return;
            }
            else {
                parent = element;
                element.children().first().after(widget);
            }
            // Top and bottom logic
            if (vertical === 'auto') {
                if (offset.top + widget.height() * 1.5 >= $(window).height() + $(window).scrollTop() &&
                    widget.height() + element.outerHeight() < offset.top) {
                    vertical = 'top';
                }
                else {
                    vertical = 'bottom';
                }
            }
            // Left and right logic
            if (horizontal === 'auto') {
                if (parent.width() < offset.left + widget.outerWidth() / 2 &&
                    offset.left + widget.outerWidth() > $(window).width()) {
                    horizontal = 'right';
                }
                else {
                    horizontal = 'left';
                }
            }
            if (vertical === 'top') {
                widget.addClass('top').removeClass('bottom');
            }
            else {
                widget.addClass('bottom').removeClass('top');
            }
            if (horizontal === 'right') {
                widget.addClass('pull-right');
            }
            else {
                widget.removeClass('pull-right');
            }
            // find the first parent element that has a non-static css positioning
            if (parent.css('position') === 'static') {
                parent = parent.parents().filter(function () {
                    return $(this).css('position') !== 'static';
                }).first();
            }
            if (parent.length === 0) {
                throw new Error('datetimepicker component should be placed within a non-static positioned container');
            }
            widget.css({
                top: vertical === 'top' ? 'auto' : position.top + element.outerHeight(),
                bottom: vertical === 'top' ? parent.outerHeight() - (parent === element ? 0 : position.top) : 'auto',
                left: horizontal === 'left' ? (parent === element ? 0 : position.left) : 'auto',
                right: horizontal === 'left' ? 'auto' : parent.outerWidth() - element.outerWidth() - (parent === element ? 0 : position.left)
            });
        }, notifyEvent = function (e) {
            if (e.type === 'dp.change' && ((e.date && e.date.isSame(e.oldDate)) || (!e.date && !e.oldDate))) {
                return;
            }
            element.trigger(e);
        }, viewUpdate = function (e) {
            if (e === 'y') {
                e = 'YYYY';
            }
            notifyEvent({
                type: 'dp.update',
                change: e,
                viewDate: viewDate.clone()
            });
        }, showMode = function (dir) {
            if (!widget) {
                return;
            }
            if (dir) {
                currentViewMode = Math.max(minViewModeNumber, Math.min(3, currentViewMode + dir));
            }
            widget.find('.datepicker > div').hide().filter('.datepicker-' + datePickerModes[currentViewMode].clsName).show();
        }, fillDow = function () {
            var row = $('<tr>'), currentDate = viewDate.clone().startOf('w').startOf('d');
            if (options.calendarWeeks === true) {
                row.append($('<th>').addClass('cw').text('#'));
            }
            while (currentDate.isBefore(viewDate.clone().endOf('w'))) {
                row.append($('<th>').addClass('dow').text(currentDate.format('dd')));
                currentDate.add(1, 'd');
            }
            widget.find('.datepicker-days thead').append(row);
        }, isInDisabledDates = function (testDate) {
            return options.disabledDates[testDate.format('YYYY-MM-DD')] === true;
        }, isInEnabledDates = function (testDate) {
            return options.enabledDates[testDate.format('YYYY-MM-DD')] === true;
        }, isInDisabledHours = function (testDate) {
            return options.disabledHours[testDate.format('H')] === true;
        }, isInEnabledHours = function (testDate) {
            return options.enabledHours[testDate.format('H')] === true;
        }, isValid = function (targetMoment, granularity) {
            if (!targetMoment.isValid()) {
                return false;
            }
            if (options.disabledDates && granularity === 'd' && isInDisabledDates(targetMoment)) {
                return false;
            }
            if (options.enabledDates && granularity === 'd' && !isInEnabledDates(targetMoment)) {
                return false;
            }
            if (options.minDate && targetMoment.isBefore(options.minDate, granularity)) {
                return false;
            }
            if (options.maxDate && targetMoment.isAfter(options.maxDate, granularity)) {
                return false;
            }
            if (options.daysOfWeekDisabled && granularity === 'd' && options.daysOfWeekDisabled.indexOf(targetMoment.day()) !== -1) {
                return false;
            }
            if (options.disabledHours && (granularity === 'h' || granularity === 'm' || granularity === 's') && isInDisabledHours(targetMoment)) {
                return false;
            }
            if (options.enabledHours && (granularity === 'h' || granularity === 'm' || granularity === 's') && !isInEnabledHours(targetMoment)) {
                return false;
            }
            if (options.disabledTimeIntervals && (granularity === 'h' || granularity === 'm' || granularity === 's')) {
                var found = false;
                $.each(options.disabledTimeIntervals, function () {
                    if (targetMoment.isBetween(this[0], this[1])) {
                        found = true;
                        return false;
                    }
                });
                if (found) {
                    return false;
                }
            }
            return true;
        }, fillMonths = function () {
            var spans = [], monthsShort = viewDate.clone().startOf('y').startOf('d');
            while (monthsShort.isSame(viewDate, 'y')) {
                spans.push($('<span>').attr('data-action', 'selectMonth').addClass('month').text(monthsShort.format('MMM')));
                monthsShort.add(1, 'M');
            }
            widget.find('.datepicker-months td').empty().append(spans);
        }, updateMonths = function () {
            var monthsView = widget.find('.datepicker-months'), monthsViewHeader = monthsView.find('th'), months = monthsView.find('tbody').find('span');
            monthsViewHeader.eq(0).find('span').attr('title', options.tooltips.prevYear);
            monthsViewHeader.eq(1).attr('title', options.tooltips.selectYear);
            monthsViewHeader.eq(2).find('span').attr('title', options.tooltips.nextYear);
            monthsView.find('.disabled').removeClass('disabled');
            if (!isValid(viewDate.clone().subtract(1, 'y'), 'y')) {
                monthsViewHeader.eq(0).addClass('disabled');
            }
            monthsViewHeader.eq(1).text(viewDate.year());
            if (!isValid(viewDate.clone().add(1, 'y'), 'y')) {
                monthsViewHeader.eq(2).addClass('disabled');
            }
            months.removeClass('active');
            if (date.isSame(viewDate, 'y') && !unset) {
                months.eq(date.month()).addClass('active');
            }
            months.each(function (index) {
                if (!isValid(viewDate.clone().month(index), 'M')) {
                    $(this).addClass('disabled');
                }
            });
        }, updateYears = function () {
            var yearsView = widget.find('.datepicker-years'), yearsViewHeader = yearsView.find('th'), startYear = viewDate.clone().subtract(5, 'y'), endYear = viewDate.clone().add(6, 'y'), html = '';
            yearsViewHeader.eq(0).find('span').attr('title', options.tooltips.prevDecade);
            yearsViewHeader.eq(1).attr('title', options.tooltips.selectDecade);
            yearsViewHeader.eq(2).find('span').attr('title', options.tooltips.nextDecade);
            yearsView.find('.disabled').removeClass('disabled');
            if (options.minDate && options.minDate.isAfter(startYear, 'y')) {
                yearsViewHeader.eq(0).addClass('disabled');
            }
            yearsViewHeader.eq(1).text(startYear.year() + '-' + endYear.year());
            if (options.maxDate && options.maxDate.isBefore(endYear, 'y')) {
                yearsViewHeader.eq(2).addClass('disabled');
            }
            while (!startYear.isAfter(endYear, 'y')) {
                html += '<span data-action="selectYear" class="year' + (startYear.isSame(date, 'y') && !unset ? ' active' : '') + (!isValid(startYear, 'y') ? ' disabled' : '') + '">' + startYear.year() + '</span>';
                startYear.add(1, 'y');
            }
            yearsView.find('td').html(html);
        }, updateDecades = function () {
            var decadesView = widget.find('.datepicker-decades'), decadesViewHeader = decadesView.find('th'), startDecade = moment({ y: viewDate.year() - (viewDate.year() % 100) - 1 }), endDecade = startDecade.clone().add(100, 'y'), startedAt = startDecade.clone(), minDateDecade = false, maxDateDecade = false, endDecadeYear, html = '';
            decadesViewHeader.eq(0).find('span').attr('title', options.tooltips.prevCentury);
            decadesViewHeader.eq(2).find('span').attr('title', options.tooltips.nextCentury);
            decadesView.find('.disabled').removeClass('disabled');
            if (startDecade.isSame(moment({ y: 1900 })) || (options.minDate && options.minDate.isAfter(startDecade, 'y'))) {
                decadesViewHeader.eq(0).addClass('disabled');
            }
            decadesViewHeader.eq(1).text(startDecade.year() + '-' + endDecade.year());
            if (startDecade.isSame(moment({ y: 2000 })) || (options.maxDate && options.maxDate.isBefore(endDecade, 'y'))) {
                decadesViewHeader.eq(2).addClass('disabled');
            }
            while (!startDecade.isAfter(endDecade, 'y')) {
                endDecadeYear = startDecade.year() + 12;
                minDateDecade = options.minDate && options.minDate.isAfter(startDecade, 'y') && options.minDate.year() <= endDecadeYear;
                maxDateDecade = options.maxDate && options.maxDate.isAfter(startDecade, 'y') && options.maxDate.year() <= endDecadeYear;
                html += '<span data-action="selectDecade" class="decade' + (date.isAfter(startDecade) && date.year() <= endDecadeYear ? ' active' : '') +
                    (!isValid(startDecade, 'y') && !minDateDecade && !maxDateDecade ? ' disabled' : '') + '" data-selection="' + (startDecade.year() + 6) + '">' + (startDecade.year() + 1) + ' - ' + (startDecade.year() + 12) + '</span>';
                startDecade.add(12, 'y');
            }
            html += '<span></span><span></span><span></span>'; //push the dangling block over, at least this way it's even
            decadesView.find('td').html(html);
            decadesViewHeader.eq(1).text((startedAt.year() + 1) + '-' + (startDecade.year()));
        }, fillDate = function () {
            var daysView = widget.find('.datepicker-days'), daysViewHeader = daysView.find('th'), currentDate, html = [], row, clsNames = [], i;
            if (!hasDate()) {
                return;
            }
            daysViewHeader.eq(0).find('span').attr('title', options.tooltips.prevMonth);
            daysViewHeader.eq(1).attr('title', options.tooltips.selectMonth);
            daysViewHeader.eq(2).find('span').attr('title', options.tooltips.nextMonth);
            daysView.find('.disabled').removeClass('disabled');
            daysViewHeader.eq(1).text(viewDate.format(options.dayViewHeaderFormat));
            if (!isValid(viewDate.clone().subtract(1, 'M'), 'M')) {
                daysViewHeader.eq(0).addClass('disabled');
            }
            if (!isValid(viewDate.clone().add(1, 'M'), 'M')) {
                daysViewHeader.eq(2).addClass('disabled');
            }
            currentDate = viewDate.clone().startOf('M').startOf('w').startOf('d');
            for (i = 0; i < 42; i++) {
                if (currentDate.weekday() === 0) {
                    row = $('<tr>');
                    if (options.calendarWeeks) {
                        row.append('<td class="cw">' + currentDate.week() + '</td>');
                    }
                    html.push(row);
                }
                clsNames = ['day'];
                if (currentDate.isBefore(viewDate, 'M')) {
                    clsNames.push('old');
                }
                if (currentDate.isAfter(viewDate, 'M')) {
                    clsNames.push('new');
                }
                if (currentDate.isSame(date, 'd') && !unset) {
                    clsNames.push('active');
                }
                if (!isValid(currentDate, 'd')) {
                    clsNames.push('disabled');
                }
                if (currentDate.isSame(getMoment(), 'd')) {
                    clsNames.push('today');
                }
                if (currentDate.day() === 0 || currentDate.day() === 6) {
                    clsNames.push('weekend');
                }
                notifyEvent({
                    type: 'dp.classify',
                    date: currentDate,
                    classNames: clsNames
                });
                row.append('<td data-action="selectDay" data-day="' + currentDate.format('L') + '" class="' + clsNames.join(' ') + '">' + currentDate.date() + '</td>');
                currentDate.add(1, 'd');
            }
            daysView.find('tbody').empty().append(html);
            updateMonths();
            updateYears();
            updateDecades();
        }, fillHours = function () {
            var table = widget.find('.timepicker-hours table'), currentHour = viewDate.clone().startOf('d'), html = [], row = $('<tr>');
            if (viewDate.hour() > 11 && !use24Hours) {
                currentHour.hour(12);
            }
            while (currentHour.isSame(viewDate, 'd') && (use24Hours || (viewDate.hour() < 12 && currentHour.hour() < 12) || viewDate.hour() > 11)) {
                if (currentHour.hour() % 4 === 0) {
                    row = $('<tr>');
                    html.push(row);
                }
                row.append('<td data-action="selectHour" class="hour' + (!isValid(currentHour, 'h') ? ' disabled' : '') + '">' + currentHour.format(use24Hours ? 'HH' : 'hh') + '</td>');
                currentHour.add(1, 'h');
            }
            table.empty().append(html);
        }, fillMinutes = function () {
            var table = widget.find('.timepicker-minutes table'), currentMinute = viewDate.clone().startOf('h'), html = [], row = $('<tr>'), step = options.stepping === 1 ? 5 : options.stepping;
            while (viewDate.isSame(currentMinute, 'h')) {
                if (currentMinute.minute() % (step * 4) === 0) {
                    row = $('<tr>');
                    html.push(row);
                }
                row.append('<td data-action="selectMinute" class="minute' + (!isValid(currentMinute, 'm') ? ' disabled' : '') + '">' + currentMinute.format('mm') + '</td>');
                currentMinute.add(step, 'm');
            }
            table.empty().append(html);
        }, fillSeconds = function () {
            var table = widget.find('.timepicker-seconds table'), currentSecond = viewDate.clone().startOf('m'), html = [], row = $('<tr>');
            while (viewDate.isSame(currentSecond, 'm')) {
                if (currentSecond.second() % 20 === 0) {
                    row = $('<tr>');
                    html.push(row);
                }
                row.append('<td data-action="selectSecond" class="second' + (!isValid(currentSecond, 's') ? ' disabled' : '') + '">' + currentSecond.format('ss') + '</td>');
                currentSecond.add(5, 's');
            }
            table.empty().append(html);
        }, fillTime = function () {
            var toggle, newDate, timeComponents = widget.find('.timepicker span[data-time-component]');
            if (!use24Hours) {
                toggle = widget.find('.timepicker [data-action=togglePeriod]');
                newDate = date.clone().add((date.hours() >= 12) ? -12 : 12, 'h');
                toggle.text(date.format('A'));
                if (isValid(newDate, 'h')) {
                    toggle.removeClass('disabled');
                }
                else {
                    toggle.addClass('disabled');
                }
            }
            timeComponents.filter('[data-time-component=hours]').text(date.format(use24Hours ? 'HH' : 'hh'));
            timeComponents.filter('[data-time-component=minutes]').text(date.format('mm'));
            timeComponents.filter('[data-time-component=seconds]').text(date.format('ss'));
            fillHours();
            fillMinutes();
            fillSeconds();
        }, update = function () {
            if (!widget) {
                return;
            }
            fillDate();
            fillTime();
        }, setValue = function (targetMoment) {
            var oldDate = unset ? null : date;
            // case of calling setValue(null or false)
            if (!targetMoment) {
                unset = true;
                input.val('');
                element.data('date', '');
                notifyEvent({
                    type: 'dp.change',
                    date: false,
                    oldDate: oldDate
                });
                update();
                return;
            }
            targetMoment = targetMoment.clone().locale(options.locale);
            if (hasTimeZone()) {
                targetMoment.tz(options.timeZone);
            }
            if (options.stepping !== 1) {
                targetMoment.minutes((Math.round(targetMoment.minutes() / options.stepping) * options.stepping)).seconds(0);
                while (options.minDate && targetMoment.isBefore(options.minDate)) {
                    targetMoment.add(options.stepping, 'minutes');
                }
            }
            if (isValid(targetMoment)) {
                date = targetMoment;
                viewDate = date.clone();
                input.val(date.format(actualFormat));
                element.data('date', date.format(actualFormat));
                unset = false;
                update();
                notifyEvent({
                    type: 'dp.change',
                    date: date.clone(),
                    oldDate: oldDate
                });
            }
            else {
                if (!options.keepInvalid) {
                    input.val(unset ? '' : date.format(actualFormat));
                }
                else {
                    notifyEvent({
                        type: 'dp.change',
                        date: targetMoment,
                        oldDate: oldDate
                    });
                }
                notifyEvent({
                    type: 'dp.error',
                    date: targetMoment,
                    oldDate: oldDate
                });
            }
        }, 
        /**
         * Hides the widget. Possibly will emit dp.hide
         */
        hide = function () {
            var transitioning = false;
            if (!widget) {
                return picker;
            }
            // Ignore event if in the middle of a picker transition
            widget.find('.collapse').each(function () {
                var collapseData = $(this).data('collapse');
                if (collapseData && collapseData.transitioning) {
                    transitioning = true;
                    return false;
                }
                return true;
            });
            if (transitioning) {
                return picker;
            }
            if (component && component.hasClass('btn')) {
                component.toggleClass('active');
            }
            widget.hide();
            $(window).off('resize', place);
            widget.off('click', '[data-action]');
            widget.off('mousedown', false);
            widget.remove();
            widget = false;
            notifyEvent({
                type: 'dp.hide',
                date: date.clone()
            });
            input.blur();
            viewDate = date.clone();
            return picker;
        }, clear = function () {
            setValue(null);
        }, parseInputDate = function (inputDate) {
            if (options.parseInputDate === undefined) {
                if (!moment.isMoment(inputDate) || inputDate instanceof Date) {
                    inputDate = getMoment(inputDate);
                }
            }
            else {
                inputDate = options.parseInputDate(inputDate);
            }
            //inputDate.locale(options.locale);
            return inputDate;
        }, 
        /********************************************************************************
         *
         * Widget UI interaction functions
         *
         ********************************************************************************/
        actions = {
            next: function () {
                var navFnc = datePickerModes[currentViewMode].navFnc;
                viewDate.add(datePickerModes[currentViewMode].navStep, navFnc);
                fillDate();
                viewUpdate(navFnc);
            },
            previous: function () {
                var navFnc = datePickerModes[currentViewMode].navFnc;
                viewDate.subtract(datePickerModes[currentViewMode].navStep, navFnc);
                fillDate();
                viewUpdate(navFnc);
            },
            pickerSwitch: function () {
                showMode(1);
            },
            selectMonth: function (e) {
                var month = $(e.target).closest('tbody').find('span').index($(e.target));
                viewDate.month(month);
                if (currentViewMode === minViewModeNumber) {
                    setValue(date.clone().year(viewDate.year()).month(viewDate.month()));
                    if (!options.inline) {
                        hide();
                    }
                }
                else {
                    showMode(-1);
                    fillDate();
                }
                viewUpdate('M');
            },
            selectYear: function (e) {
                var year = parseInt($(e.target).text(), 10) || 0;
                viewDate.year(year);
                if (currentViewMode === minViewModeNumber) {
                    setValue(date.clone().year(viewDate.year()));
                    if (!options.inline) {
                        hide();
                    }
                }
                else {
                    showMode(-1);
                    fillDate();
                }
                viewUpdate('YYYY');
            },
            selectDecade: function (e) {
                var year = parseInt($(e.target).data('selection'), 10) || 0;
                viewDate.year(year);
                if (currentViewMode === minViewModeNumber) {
                    setValue(date.clone().year(viewDate.year()));
                    if (!options.inline) {
                        hide();
                    }
                }
                else {
                    showMode(-1);
                    fillDate();
                }
                viewUpdate('YYYY');
            },
            selectDay: function (e) {
                var day = viewDate.clone();
                if ($(e.target).is('.old')) {
                    day.subtract(1, 'M');
                }
                if ($(e.target).is('.new')) {
                    day.add(1, 'M');
                }
                setValue(day.date(parseInt($(e.target).text(), 10)));
                if (!hasTime() && !options.keepOpen && !options.inline) {
                    hide();
                }
            },
            incrementHours: function () {
                var newDate = date.clone().add(1, 'h');
                if (isValid(newDate, 'h')) {
                    setValue(newDate);
                }
            },
            incrementMinutes: function () {
                var newDate = date.clone().add(options.stepping, 'm');
                if (isValid(newDate, 'm')) {
                    setValue(newDate);
                }
            },
            incrementSeconds: function () {
                var newDate = date.clone().add(1, 's');
                if (isValid(newDate, 's')) {
                    setValue(newDate);
                }
            },
            decrementHours: function () {
                var newDate = date.clone().subtract(1, 'h');
                if (isValid(newDate, 'h')) {
                    setValue(newDate);
                }
            },
            decrementMinutes: function () {
                var newDate = date.clone().subtract(options.stepping, 'm');
                if (isValid(newDate, 'm')) {
                    setValue(newDate);
                }
            },
            decrementSeconds: function () {
                var newDate = date.clone().subtract(1, 's');
                if (isValid(newDate, 's')) {
                    setValue(newDate);
                }
            },
            togglePeriod: function () {
                setValue(date.clone().add((date.hours() >= 12) ? -12 : 12, 'h'));
            },
            togglePicker: function (e) {
                var $this = $(e.target), $parent = $this.closest('ul'), expanded = $parent.find('.in'), closed = $parent.find('.collapse:not(.in)'), collapseData;
                if (expanded && expanded.length) {
                    collapseData = expanded.data('collapse');
                    if (collapseData && collapseData.transitioning) {
                        return;
                    }
                    if (expanded.collapse) {
                        expanded.collapse('hide');
                        closed.collapse('show');
                    }
                    else {
                        expanded.removeClass('in');
                        closed.addClass('in');
                    }
                    if ($this.is('span')) {
                        $this.toggleClass(options.icons.time + ' ' + options.icons.date);
                    }
                    else {
                        $this.find('span').toggleClass(options.icons.time + ' ' + options.icons.date);
                    }
                }
            },
            showPicker: function () {
                widget.find('.timepicker > div:not(.timepicker-picker)').hide();
                widget.find('.timepicker .timepicker-picker').show();
            },
            showHours: function () {
                widget.find('.timepicker .timepicker-picker').hide();
                widget.find('.timepicker .timepicker-hours').show();
            },
            showMinutes: function () {
                widget.find('.timepicker .timepicker-picker').hide();
                widget.find('.timepicker .timepicker-minutes').show();
            },
            showSeconds: function () {
                widget.find('.timepicker .timepicker-picker').hide();
                widget.find('.timepicker .timepicker-seconds').show();
            },
            selectHour: function (e) {
                var hour = parseInt($(e.target).text(), 10);
                if (!use24Hours) {
                    if (date.hours() >= 12) {
                        if (hour !== 12) {
                            hour += 12;
                        }
                    }
                    else {
                        if (hour === 12) {
                            hour = 0;
                        }
                    }
                }
                setValue(date.clone().hours(hour));
                actions.showPicker.call(picker);
            },
            selectMinute: function (e) {
                setValue(date.clone().minutes(parseInt($(e.target).text(), 10)));
                actions.showPicker.call(picker);
            },
            selectSecond: function (e) {
                setValue(date.clone().seconds(parseInt($(e.target).text(), 10)));
                actions.showPicker.call(picker);
            },
            clear: clear,
            today: function () {
                var todaysDate = getMoment();
                if (isValid(todaysDate, 'd')) {
                    setValue(todaysDate);
                }
            },
            close: hide
        }, doAction = function (e) {
            if ($(e.currentTarget).is('.disabled')) {
                return false;
            }
            actions[$(e.currentTarget).data('action')].apply(picker, arguments);
            return false;
        }, 
        /**
         * Shows the widget. Possibly will emit dp.show and dp.change
         */
        show = function () {
            var currentMoment, useCurrentGranularity = {
                'year': function (m) {
                    return m.month(0).date(1).hours(0).seconds(0).minutes(0);
                },
                'month': function (m) {
                    return m.date(1).hours(0).seconds(0).minutes(0);
                },
                'day': function (m) {
                    return m.hours(0).seconds(0).minutes(0);
                },
                'hour': function (m) {
                    return m.seconds(0).minutes(0);
                },
                'minute': function (m) {
                    return m.seconds(0);
                }
            };
            if (input.prop('disabled') || (!options.ignoreReadonly && input.prop('readonly')) || widget) {
                return picker;
            }
            if (input.val() !== undefined && input.val().trim().length !== 0) {
                setValue(parseInputDate(input.val().trim()));
            }
            else if (unset && options.useCurrent && (options.inline || (input.is('input') && input.val().trim().length === 0))) {
                currentMoment = getMoment();
                if (typeof options.useCurrent === 'string') {
                    currentMoment = useCurrentGranularity[options.useCurrent](currentMoment);
                }
                setValue(currentMoment);
            }
            widget = getTemplate();
            fillDow();
            fillMonths();
            widget.find('.timepicker-hours').hide();
            widget.find('.timepicker-minutes').hide();
            widget.find('.timepicker-seconds').hide();
            update();
            showMode();
            $(window).on('resize', place);
            widget.on('click', '[data-action]', doAction); // this handles clicks on the widget
            widget.on('mousedown', false);
            if (component && component.hasClass('btn')) {
                component.toggleClass('active');
            }
            place();
            widget.show();
            if (options.focusOnShow && !input.is(':focus')) {
                input.focus();
            }
            notifyEvent({
                type: 'dp.show'
            });
            return picker;
        }, 
        /**
         * Shows or hides the widget
         */
        toggle = function () {
            return (widget ? hide() : show());
        }, keydown = function (e) {
            var handler = null, index, index2, pressedKeys = [], pressedModifiers = {}, currentKey = e.which, keyBindKeys, allModifiersPressed, pressed = 'p';
            keyState[currentKey] = pressed;
            for (index in keyState) {
                if (keyState.hasOwnProperty(index) && keyState[index] === pressed) {
                    pressedKeys.push(index);
                    if (parseInt(index, 10) !== currentKey) {
                        pressedModifiers[index] = true;
                    }
                }
            }
            for (index in options.keyBinds) {
                if (options.keyBinds.hasOwnProperty(index) && typeof (options.keyBinds[index]) === 'function') {
                    keyBindKeys = index.split(' ');
                    if (keyBindKeys.length === pressedKeys.length && keyMap[currentKey] === keyBindKeys[keyBindKeys.length - 1]) {
                        allModifiersPressed = true;
                        for (index2 = keyBindKeys.length - 2; index2 >= 0; index2--) {
                            if (!(keyMap[keyBindKeys[index2]] in pressedModifiers)) {
                                allModifiersPressed = false;
                                break;
                            }
                        }
                        if (allModifiersPressed) {
                            handler = options.keyBinds[index];
                            break;
                        }
                    }
                }
            }
            if (handler) {
                handler.call(picker, widget);
                e.stopPropagation();
                e.preventDefault();
            }
        }, keyup = function (e) {
            keyState[e.which] = 'r';
            e.stopPropagation();
            e.preventDefault();
        }, change = function (e) {
            var val = $(e.target).val().trim(), parsedDate = val ? parseInputDate(val) : null;
            setValue(parsedDate);
            e.stopImmediatePropagation();
            return false;
        }, attachDatePickerElementEvents = function () {
            input.on({
                'change': change,
                'blur': options.debug ? '' : hide,
                'keydown': keydown,
                'keyup': keyup,
                'focus': options.allowInputToggle ? show : ''
            });
            if (element.is('input')) {
                input.on({
                    'focus': show
                });
            }
            else if (component) {
                component.on('click', toggle);
                component.on('mousedown', false);
            }
        }, detachDatePickerElementEvents = function () {
            input.off({
                'change': change,
                'blur': blur,
                'keydown': keydown,
                'keyup': keyup,
                'focus': options.allowInputToggle ? hide : ''
            });
            if (element.is('input')) {
                input.off({
                    'focus': show
                });
            }
            else if (component) {
                component.off('click', toggle);
                component.off('mousedown', false);
            }
        }, indexGivenDates = function (givenDatesArray) {
            // Store given enabledDates and disabledDates as keys.
            // This way we can check their existence in O(1) time instead of looping through whole array.
            // (for example: options.enabledDates['2014-02-27'] === true)
            var givenDatesIndexed = {};
            $.each(givenDatesArray, function () {
                var dDate = parseInputDate(this);
                if (dDate.isValid()) {
                    givenDatesIndexed[dDate.format('YYYY-MM-DD')] = true;
                }
            });
            return (Object.keys(givenDatesIndexed).length) ? givenDatesIndexed : false;
        }, indexGivenHours = function (givenHoursArray) {
            // Store given enabledHours and disabledHours as keys.
            // This way we can check their existence in O(1) time instead of looping through whole array.
            // (for example: options.enabledHours['2014-02-27'] === true)
            var givenHoursIndexed = {};
            $.each(givenHoursArray, function () {
                givenHoursIndexed[this] = true;
            });
            return (Object.keys(givenHoursIndexed).length) ? givenHoursIndexed : false;
        }, initFormatting = function () {
            var format = options.format || 'L LT';
            actualFormat = format.replace(/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g, function (formatInput) {
                var newinput = date.localeData().longDateFormat(formatInput) || formatInput;
                return newinput.replace(/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g, function (formatInput2) {
                    return date.localeData().longDateFormat(formatInput2) || formatInput2;
                });
            });
            parseFormats = options.extraFormats ? options.extraFormats.slice() : [];
            if (parseFormats.indexOf(format) < 0 && parseFormats.indexOf(actualFormat) < 0) {
                parseFormats.push(actualFormat);
            }
            use24Hours = (actualFormat.toLowerCase().indexOf('a') < 1 && actualFormat.replace(/\[.*?\]/g, '').indexOf('h') < 1);
            if (isEnabled('y')) {
                minViewModeNumber = 2;
            }
            if (isEnabled('M')) {
                minViewModeNumber = 1;
            }
            if (isEnabled('d')) {
                minViewModeNumber = 0;
            }
            currentViewMode = Math.max(minViewModeNumber, currentViewMode);
            if (!unset) {
                setValue(date);
            }
        };
        /********************************************************************************
         *
         * Public API functions
         * =====================
         *
         * Important: Do not expose direct references to private objects or the options
         * object to the outer world. Always return a clone when returning values or make
         * a clone when setting a private variable.
         *
         ********************************************************************************/
        picker.destroy = function () {
            ///<summary>Destroys the widget and removes all attached event listeners</summary>
            hide();
            detachDatePickerElementEvents();
            element.removeData('DateTimePicker');
            element.removeData('date');
        };
        picker.toggle = toggle;
        picker.show = show;
        picker.hide = hide;
        picker.disable = function () {
            ///<summary>Disables the input element, the component is attached to, by adding a disabled="true" attribute to it.
            ///If the widget was visible before that call it is hidden. Possibly emits dp.hide</summary>
            hide();
            if (component && component.hasClass('btn')) {
                component.addClass('disabled');
            }
            input.prop('disabled', true);
            return picker;
        };
        picker.enable = function () {
            ///<summary>Enables the input element, the component is attached to, by removing disabled attribute from it.</summary>
            if (component && component.hasClass('btn')) {
                component.removeClass('disabled');
            }
            input.prop('disabled', false);
            return picker;
        };
        picker.ignoreReadonly = function (ignoreReadonly) {
            if (arguments.length === 0) {
                return options.ignoreReadonly;
            }
            if (typeof ignoreReadonly !== 'boolean') {
                throw new TypeError('ignoreReadonly () expects a boolean parameter');
            }
            options.ignoreReadonly = ignoreReadonly;
            return picker;
        };
        picker.options = function (newOptions) {
            if (arguments.length === 0) {
                return $.extend(true, {}, options);
            }
            if (!(newOptions instanceof Object)) {
                throw new TypeError('options() options parameter should be an object');
            }
            $.extend(true, options, newOptions);
            $.each(options, function (key, value) {
                if (picker[key] !== undefined) {
                    picker[key](value);
                }
                else {
                    throw new TypeError('option ' + key + ' is not recognized!');
                }
            });
            return picker;
        };
        picker.date = function (newDate) {
            ///<signature helpKeyword="$.fn.datetimepicker.date">
            ///<summary>Returns the component's model current date, a moment object or null if not set.</summary>
            ///<returns type="Moment">date.clone()</returns>
            ///</signature>
            ///<signature>
            ///<summary>Sets the components model current moment to it. Passing a null value unsets the components model current moment. Parsing of the newDate parameter is made using moment library with the options.format and options.useStrict components configuration.</summary>
            ///<param name="newDate" locid="$.fn.datetimepicker.date_p:newDate">Takes string, Date, moment, null parameter.</param>
            ///</signature>
            if (arguments.length === 0) {
                if (unset) {
                    return null;
                }
                return date.clone();
            }
            if (newDate !== null && typeof newDate !== 'string' && !moment.isMoment(newDate) && !(newDate instanceof Date)) {
                throw new TypeError('date() parameter must be one of [null, string, moment or Date]');
            }
            setValue(newDate === null ? null : parseInputDate(newDate));
            return picker;
        };
        picker.format = function (newFormat) {
            ///<summary>test su</summary>
            ///<param name="newFormat">info about para</param>
            ///<returns type="string|boolean">returns foo</returns>
            if (arguments.length === 0) {
                return options.format;
            }
            if ((typeof newFormat !== 'string') && ((typeof newFormat !== 'boolean') || (newFormat !== false))) {
                throw new TypeError('format() expects a string or boolean:false parameter ' + newFormat);
            }
            options.format = newFormat;
            if (actualFormat) {
                initFormatting(); // reinit formatting
            }
            return picker;
        };
        picker.timeZone = function (newZone) {
            if (arguments.length === 0) {
                return options.timeZone;
            }
            if (typeof newZone !== 'string') {
                throw new TypeError('newZone() expects a string parameter');
            }
            options.timeZone = newZone;
            return picker;
        };
        picker.dayViewHeaderFormat = function (newFormat) {
            if (arguments.length === 0) {
                return options.dayViewHeaderFormat;
            }
            if (typeof newFormat !== 'string') {
                throw new TypeError('dayViewHeaderFormat() expects a string parameter');
            }
            options.dayViewHeaderFormat = newFormat;
            return picker;
        };
        picker.extraFormats = function (formats) {
            if (arguments.length === 0) {
                return options.extraFormats;
            }
            if (formats !== false && !(formats instanceof Array)) {
                throw new TypeError('extraFormats() expects an array or false parameter');
            }
            options.extraFormats = formats;
            if (parseFormats) {
                initFormatting(); // reinit formatting
            }
            return picker;
        };
        picker.disabledDates = function (dates) {
            ///<signature helpKeyword="$.fn.datetimepicker.disabledDates">
            ///<summary>Returns an array with the currently set disabled dates on the component.</summary>
            ///<returns type="array">options.disabledDates</returns>
            ///</signature>
            ///<signature>
            ///<summary>Setting this takes precedence over options.minDate, options.maxDate configuration. Also calling this function removes the configuration of
            ///options.enabledDates if such exist.</summary>
            ///<param name="dates" locid="$.fn.datetimepicker.disabledDates_p:dates">Takes an [ string or Date or moment ] of values and allows the user to select only from those days.</param>
            ///</signature>
            if (arguments.length === 0) {
                return (options.disabledDates ? $.extend({}, options.disabledDates) : options.disabledDates);
            }
            if (!dates) {
                options.disabledDates = false;
                update();
                return picker;
            }
            if (!(dates instanceof Array)) {
                throw new TypeError('disabledDates() expects an array parameter');
            }
            options.disabledDates = indexGivenDates(dates);
            options.enabledDates = false;
            update();
            return picker;
        };
        picker.enabledDates = function (dates) {
            ///<signature helpKeyword="$.fn.datetimepicker.enabledDates">
            ///<summary>Returns an array with the currently set enabled dates on the component.</summary>
            ///<returns type="array">options.enabledDates</returns>
            ///</signature>
            ///<signature>
            ///<summary>Setting this takes precedence over options.minDate, options.maxDate configuration. Also calling this function removes the configuration of options.disabledDates if such exist.</summary>
            ///<param name="dates" locid="$.fn.datetimepicker.enabledDates_p:dates">Takes an [ string or Date or moment ] of values and allows the user to select only from those days.</param>
            ///</signature>
            if (arguments.length === 0) {
                return (options.enabledDates ? $.extend({}, options.enabledDates) : options.enabledDates);
            }
            if (!dates) {
                options.enabledDates = false;
                update();
                return picker;
            }
            if (!(dates instanceof Array)) {
                throw new TypeError('enabledDates() expects an array parameter');
            }
            options.enabledDates = indexGivenDates(dates);
            options.disabledDates = false;
            update();
            return picker;
        };
        picker.daysOfWeekDisabled = function (daysOfWeekDisabled) {
            if (arguments.length === 0) {
                return options.daysOfWeekDisabled.splice(0);
            }
            if ((typeof daysOfWeekDisabled === 'boolean') && !daysOfWeekDisabled) {
                options.daysOfWeekDisabled = false;
                update();
                return picker;
            }
            if (!(daysOfWeekDisabled instanceof Array)) {
                throw new TypeError('daysOfWeekDisabled() expects an array parameter');
            }
            options.daysOfWeekDisabled = daysOfWeekDisabled.reduce(function (previousValue, currentValue) {
                currentValue = parseInt(currentValue, 10);
                if (currentValue > 6 || currentValue < 0 || isNaN(currentValue)) {
                    return previousValue;
                }
                if (previousValue.indexOf(currentValue) === -1) {
                    previousValue.push(currentValue);
                }
                return previousValue;
            }, []).sort();
            if (options.useCurrent && !options.keepInvalid) {
                var tries = 0;
                while (!isValid(date, 'd')) {
                    date.add(1, 'd');
                    if (tries === 31) {
                        throw 'Tried 31 times to find a valid date';
                    }
                    tries++;
                }
                setValue(date);
            }
            update();
            return picker;
        };
        picker.maxDate = function (maxDate) {
            if (arguments.length === 0) {
                return options.maxDate ? options.maxDate.clone() : options.maxDate;
            }
            if ((typeof maxDate === 'boolean') && maxDate === false) {
                options.maxDate = false;
                update();
                return picker;
            }
            if (typeof maxDate === 'string') {
                if (maxDate === 'now' || maxDate === 'moment') {
                    maxDate = getMoment();
                }
            }
            var parsedDate = parseInputDate(maxDate);
            if (!parsedDate.isValid()) {
                throw new TypeError('maxDate() Could not parse date parameter: ' + maxDate);
            }
            if (options.minDate && parsedDate.isBefore(options.minDate)) {
                throw new TypeError('maxDate() date parameter is before options.minDate: ' + parsedDate.format(actualFormat));
            }
            options.maxDate = parsedDate;
            if (options.useCurrent && !options.keepInvalid && date.isAfter(maxDate)) {
                setValue(options.maxDate);
            }
            if (viewDate.isAfter(parsedDate)) {
                viewDate = parsedDate.clone().subtract(options.stepping, 'm');
            }
            update();
            return picker;
        };
        picker.minDate = function (minDate) {
            if (arguments.length === 0) {
                return options.minDate ? options.minDate.clone() : options.minDate;
            }
            if ((typeof minDate === 'boolean') && minDate === false) {
                options.minDate = false;
                update();
                return picker;
            }
            if (typeof minDate === 'string') {
                if (minDate === 'now' || minDate === 'moment') {
                    minDate = getMoment();
                }
            }
            var parsedDate = parseInputDate(minDate);
            if (!parsedDate.isValid()) {
                throw new TypeError('minDate() Could not parse date parameter: ' + minDate);
            }
            if (options.maxDate && parsedDate.isAfter(options.maxDate)) {
                throw new TypeError('minDate() date parameter is after options.maxDate: ' + parsedDate.format(actualFormat));
            }
            options.minDate = parsedDate;
            if (options.useCurrent && !options.keepInvalid && date.isBefore(minDate)) {
                setValue(options.minDate);
            }
            if (viewDate.isBefore(parsedDate)) {
                viewDate = parsedDate.clone().add(options.stepping, 'm');
            }
            update();
            return picker;
        };
        picker.defaultDate = function (defaultDate) {
            ///<signature helpKeyword="$.fn.datetimepicker.defaultDate">
            ///<summary>Returns a moment with the options.defaultDate option configuration or false if not set</summary>
            ///<returns type="Moment">date.clone()</returns>
            ///</signature>
            ///<signature>
            ///<summary>Will set the picker's inital date. If a boolean:false value is passed the options.defaultDate parameter is cleared.</summary>
            ///<param name="defaultDate" locid="$.fn.datetimepicker.defaultDate_p:defaultDate">Takes a string, Date, moment, boolean:false</param>
            ///</signature>
            if (arguments.length === 0) {
                return options.defaultDate ? options.defaultDate.clone() : options.defaultDate;
            }
            if (!defaultDate) {
                options.defaultDate = false;
                return picker;
            }
            if (typeof defaultDate === 'string') {
                if (defaultDate === 'now' || defaultDate === 'moment') {
                    defaultDate = getMoment();
                }
                else {
                    defaultDate = getMoment(defaultDate);
                }
            }
            var parsedDate = parseInputDate(defaultDate);
            if (!parsedDate.isValid()) {
                throw new TypeError('defaultDate() Could not parse date parameter: ' + defaultDate);
            }
            if (!isValid(parsedDate)) {
                throw new TypeError('defaultDate() date passed is invalid according to component setup validations');
            }
            options.defaultDate = parsedDate;
            if ((options.defaultDate && options.inline) || input.val().trim() === '') {
                setValue(options.defaultDate);
            }
            return picker;
        };
        picker.locale = function (locale) {
            if (arguments.length === 0) {
                return options.locale;
            }
            if (!moment.localeData(locale)) {
                throw new TypeError('locale() locale ' + locale + ' is not loaded from moment locales!');
            }
            options.locale = locale;
            date.locale(options.locale);
            viewDate.locale(options.locale);
            if (actualFormat) {
                initFormatting(); // reinit formatting
            }
            if (widget) {
                hide();
                show();
            }
            return picker;
        };
        picker.stepping = function (stepping) {
            if (arguments.length === 0) {
                return options.stepping;
            }
            stepping = parseInt(stepping, 10);
            if (isNaN(stepping) || stepping < 1) {
                stepping = 1;
            }
            options.stepping = stepping;
            return picker;
        };
        picker.useCurrent = function (useCurrent) {
            var useCurrentOptions = ['year', 'month', 'day', 'hour', 'minute'];
            if (arguments.length === 0) {
                return options.useCurrent;
            }
            if ((typeof useCurrent !== 'boolean') && (typeof useCurrent !== 'string')) {
                throw new TypeError('useCurrent() expects a boolean or string parameter');
            }
            if (typeof useCurrent === 'string' && useCurrentOptions.indexOf(useCurrent.toLowerCase()) === -1) {
                throw new TypeError('useCurrent() expects a string parameter of ' + useCurrentOptions.join(', '));
            }
            options.useCurrent = useCurrent;
            return picker;
        };
        picker.collapse = function (collapse) {
            if (arguments.length === 0) {
                return options.collapse;
            }
            if (typeof collapse !== 'boolean') {
                throw new TypeError('collapse() expects a boolean parameter');
            }
            if (options.collapse === collapse) {
                return picker;
            }
            options.collapse = collapse;
            if (widget) {
                hide();
                show();
            }
            return picker;
        };
        picker.icons = function (icons) {
            if (arguments.length === 0) {
                return $.extend({}, options.icons);
            }
            if (!(icons instanceof Object)) {
                throw new TypeError('icons() expects parameter to be an Object');
            }
            $.extend(options.icons, icons);
            if (widget) {
                hide();
                show();
            }
            return picker;
        };
        picker.tooltips = function (tooltips) {
            if (arguments.length === 0) {
                return $.extend({}, options.tooltips);
            }
            if (!(tooltips instanceof Object)) {
                throw new TypeError('tooltips() expects parameter to be an Object');
            }
            $.extend(options.tooltips, tooltips);
            if (widget) {
                hide();
                show();
            }
            return picker;
        };
        picker.useStrict = function (useStrict) {
            if (arguments.length === 0) {
                return options.useStrict;
            }
            if (typeof useStrict !== 'boolean') {
                throw new TypeError('useStrict() expects a boolean parameter');
            }
            options.useStrict = useStrict;
            return picker;
        };
        picker.sideBySide = function (sideBySide) {
            if (arguments.length === 0) {
                return options.sideBySide;
            }
            if (typeof sideBySide !== 'boolean') {
                throw new TypeError('sideBySide() expects a boolean parameter');
            }
            options.sideBySide = sideBySide;
            if (widget) {
                hide();
                show();
            }
            return picker;
        };
        picker.viewMode = function (viewMode) {
            if (arguments.length === 0) {
                return options.viewMode;
            }
            if (typeof viewMode !== 'string') {
                throw new TypeError('viewMode() expects a string parameter');
            }
            if (viewModes.indexOf(viewMode) === -1) {
                throw new TypeError('viewMode() parameter must be one of (' + viewModes.join(', ') + ') value');
            }
            options.viewMode = viewMode;
            currentViewMode = Math.max(viewModes.indexOf(viewMode), minViewModeNumber);
            showMode();
            return picker;
        };
        picker.toolbarPlacement = function (toolbarPlacement) {
            if (arguments.length === 0) {
                return options.toolbarPlacement;
            }
            if (typeof toolbarPlacement !== 'string') {
                throw new TypeError('toolbarPlacement() expects a string parameter');
            }
            if (toolbarPlacements.indexOf(toolbarPlacement) === -1) {
                throw new TypeError('toolbarPlacement() parameter must be one of (' + toolbarPlacements.join(', ') + ') value');
            }
            options.toolbarPlacement = toolbarPlacement;
            if (widget) {
                hide();
                show();
            }
            return picker;
        };
        picker.widgetPositioning = function (widgetPositioning) {
            if (arguments.length === 0) {
                return $.extend({}, options.widgetPositioning);
            }
            if (({}).toString.call(widgetPositioning) !== '[object Object]') {
                throw new TypeError('widgetPositioning() expects an object variable');
            }
            if (widgetPositioning.horizontal) {
                if (typeof widgetPositioning.horizontal !== 'string') {
                    throw new TypeError('widgetPositioning() horizontal variable must be a string');
                }
                widgetPositioning.horizontal = widgetPositioning.horizontal.toLowerCase();
                if (horizontalModes.indexOf(widgetPositioning.horizontal) === -1) {
                    throw new TypeError('widgetPositioning() expects horizontal parameter to be one of (' + horizontalModes.join(', ') + ')');
                }
                options.widgetPositioning.horizontal = widgetPositioning.horizontal;
            }
            if (widgetPositioning.vertical) {
                if (typeof widgetPositioning.vertical !== 'string') {
                    throw new TypeError('widgetPositioning() vertical variable must be a string');
                }
                widgetPositioning.vertical = widgetPositioning.vertical.toLowerCase();
                if (verticalModes.indexOf(widgetPositioning.vertical) === -1) {
                    throw new TypeError('widgetPositioning() expects vertical parameter to be one of (' + verticalModes.join(', ') + ')');
                }
                options.widgetPositioning.vertical = widgetPositioning.vertical;
            }
            update();
            return picker;
        };
        picker.calendarWeeks = function (calendarWeeks) {
            if (arguments.length === 0) {
                return options.calendarWeeks;
            }
            if (typeof calendarWeeks !== 'boolean') {
                throw new TypeError('calendarWeeks() expects parameter to be a boolean value');
            }
            options.calendarWeeks = calendarWeeks;
            update();
            return picker;
        };
        picker.showTodayButton = function (showTodayButton) {
            if (arguments.length === 0) {
                return options.showTodayButton;
            }
            if (typeof showTodayButton !== 'boolean') {
                throw new TypeError('showTodayButton() expects a boolean parameter');
            }
            options.showTodayButton = showTodayButton;
            if (widget) {
                hide();
                show();
            }
            return picker;
        };
        picker.showClear = function (showClear) {
            if (arguments.length === 0) {
                return options.showClear;
            }
            if (typeof showClear !== 'boolean') {
                throw new TypeError('showClear() expects a boolean parameter');
            }
            options.showClear = showClear;
            if (widget) {
                hide();
                show();
            }
            return picker;
        };
        picker.widgetParent = function (widgetParent) {
            if (arguments.length === 0) {
                return options.widgetParent;
            }
            if (typeof widgetParent === 'string') {
                widgetParent = $(widgetParent);
            }
            if (widgetParent !== null && (typeof widgetParent !== 'string' && !(widgetParent instanceof $))) {
                throw new TypeError('widgetParent() expects a string or a jQuery object parameter');
            }
            options.widgetParent = widgetParent;
            if (widget) {
                hide();
                show();
            }
            return picker;
        };
        picker.keepOpen = function (keepOpen) {
            if (arguments.length === 0) {
                return options.keepOpen;
            }
            if (typeof keepOpen !== 'boolean') {
                throw new TypeError('keepOpen() expects a boolean parameter');
            }
            options.keepOpen = keepOpen;
            return picker;
        };
        picker.focusOnShow = function (focusOnShow) {
            if (arguments.length === 0) {
                return options.focusOnShow;
            }
            if (typeof focusOnShow !== 'boolean') {
                throw new TypeError('focusOnShow() expects a boolean parameter');
            }
            options.focusOnShow = focusOnShow;
            return picker;
        };
        picker.inline = function (inline) {
            if (arguments.length === 0) {
                return options.inline;
            }
            if (typeof inline !== 'boolean') {
                throw new TypeError('inline() expects a boolean parameter');
            }
            options.inline = inline;
            return picker;
        };
        picker.clear = function () {
            clear();
            return picker;
        };
        picker.keyBinds = function (keyBinds) {
            if (arguments.length === 0) {
                return options.keyBinds;
            }
            options.keyBinds = keyBinds;
            return picker;
        };
        picker.getMoment = function (d) {
            return getMoment(d);
        };
        picker.debug = function (debug) {
            if (typeof debug !== 'boolean') {
                throw new TypeError('debug() expects a boolean parameter');
            }
            options.debug = debug;
            return picker;
        };
        picker.allowInputToggle = function (allowInputToggle) {
            if (arguments.length === 0) {
                return options.allowInputToggle;
            }
            if (typeof allowInputToggle !== 'boolean') {
                throw new TypeError('allowInputToggle() expects a boolean parameter');
            }
            options.allowInputToggle = allowInputToggle;
            return picker;
        };
        picker.showClose = function (showClose) {
            if (arguments.length === 0) {
                return options.showClose;
            }
            if (typeof showClose !== 'boolean') {
                throw new TypeError('showClose() expects a boolean parameter');
            }
            options.showClose = showClose;
            return picker;
        };
        picker.keepInvalid = function (keepInvalid) {
            if (arguments.length === 0) {
                return options.keepInvalid;
            }
            if (typeof keepInvalid !== 'boolean') {
                throw new TypeError('keepInvalid() expects a boolean parameter');
            }
            options.keepInvalid = keepInvalid;
            return picker;
        };
        picker.datepickerInput = function (datepickerInput) {
            if (arguments.length === 0) {
                return options.datepickerInput;
            }
            if (typeof datepickerInput !== 'string') {
                throw new TypeError('datepickerInput() expects a string parameter');
            }
            options.datepickerInput = datepickerInput;
            return picker;
        };
        picker.parseInputDate = function (parseInputDate) {
            if (arguments.length === 0) {
                return options.parseInputDate;
            }
            if (typeof parseInputDate !== 'function') {
                throw new TypeError('parseInputDate() sholud be as function');
            }
            options.parseInputDate = parseInputDate;
            return picker;
        };
        picker.disabledTimeIntervals = function (disabledTimeIntervals) {
            ///<signature helpKeyword="$.fn.datetimepicker.disabledTimeIntervals">
            ///<summary>Returns an array with the currently set disabled dates on the component.</summary>
            ///<returns type="array">options.disabledTimeIntervals</returns>
            ///</signature>
            ///<signature>
            ///<summary>Setting this takes precedence over options.minDate, options.maxDate configuration. Also calling this function removes the configuration of
            ///options.enabledDates if such exist.</summary>
            ///<param name="dates" locid="$.fn.datetimepicker.disabledTimeIntervals_p:dates">Takes an [ string or Date or moment ] of values and allows the user to select only from those days.</param>
            ///</signature>
            if (arguments.length === 0) {
                return (options.disabledTimeIntervals ? $.extend({}, options.disabledTimeIntervals) : options.disabledTimeIntervals);
            }
            if (!disabledTimeIntervals) {
                options.disabledTimeIntervals = false;
                update();
                return picker;
            }
            if (!(disabledTimeIntervals instanceof Array)) {
                throw new TypeError('disabledTimeIntervals() expects an array parameter');
            }
            options.disabledTimeIntervals = disabledTimeIntervals;
            update();
            return picker;
        };
        picker.disabledHours = function (hours) {
            ///<signature helpKeyword="$.fn.datetimepicker.disabledHours">
            ///<summary>Returns an array with the currently set disabled hours on the component.</summary>
            ///<returns type="array">options.disabledHours</returns>
            ///</signature>
            ///<signature>
            ///<summary>Setting this takes precedence over options.minDate, options.maxDate configuration. Also calling this function removes the configuration of
            ///options.enabledHours if such exist.</summary>
            ///<param name="hours" locid="$.fn.datetimepicker.disabledHours_p:hours">Takes an [ int ] of values and disallows the user to select only from those hours.</param>
            ///</signature>
            if (arguments.length === 0) {
                return (options.disabledHours ? $.extend({}, options.disabledHours) : options.disabledHours);
            }
            if (!hours) {
                options.disabledHours = false;
                update();
                return picker;
            }
            if (!(hours instanceof Array)) {
                throw new TypeError('disabledHours() expects an array parameter');
            }
            options.disabledHours = indexGivenHours(hours);
            options.enabledHours = false;
            if (options.useCurrent && !options.keepInvalid) {
                var tries = 0;
                while (!isValid(date, 'h')) {
                    date.add(1, 'h');
                    if (tries === 24) {
                        throw 'Tried 24 times to find a valid date';
                    }
                    tries++;
                }
                setValue(date);
            }
            update();
            return picker;
        };
        picker.enabledHours = function (hours) {
            ///<signature helpKeyword="$.fn.datetimepicker.enabledHours">
            ///<summary>Returns an array with the currently set enabled hours on the component.</summary>
            ///<returns type="array">options.enabledHours</returns>
            ///</signature>
            ///<signature>
            ///<summary>Setting this takes precedence over options.minDate, options.maxDate configuration. Also calling this function removes the configuration of options.disabledHours if such exist.</summary>
            ///<param name="hours" locid="$.fn.datetimepicker.enabledHours_p:hours">Takes an [ int ] of values and allows the user to select only from those hours.</param>
            ///</signature>
            if (arguments.length === 0) {
                return (options.enabledHours ? $.extend({}, options.enabledHours) : options.enabledHours);
            }
            if (!hours) {
                options.enabledHours = false;
                update();
                return picker;
            }
            if (!(hours instanceof Array)) {
                throw new TypeError('enabledHours() expects an array parameter');
            }
            options.enabledHours = indexGivenHours(hours);
            options.disabledHours = false;
            if (options.useCurrent && !options.keepInvalid) {
                var tries = 0;
                while (!isValid(date, 'h')) {
                    date.add(1, 'h');
                    if (tries === 24) {
                        throw 'Tried 24 times to find a valid date';
                    }
                    tries++;
                }
                setValue(date);
            }
            update();
            return picker;
        };
        /**
         * Returns the component's model current viewDate, a moment object or null if not set. Passing a null value unsets the components model current moment. Parsing of the newDate parameter is made using moment library with the options.format and options.useStrict components configuration.
         * @param {Takes string, viewDate, moment, null parameter.} newDate
         * @returns {viewDate.clone()}
         */
        picker.viewDate = function (newDate) {
            if (arguments.length === 0) {
                return viewDate.clone();
            }
            if (!newDate) {
                viewDate = date.clone();
                return picker;
            }
            if (typeof newDate !== 'string' && !moment.isMoment(newDate) && !(newDate instanceof Date)) {
                throw new TypeError('viewDate() parameter must be one of [string, moment or Date]');
            }
            viewDate = parseInputDate(newDate);
            viewUpdate();
            return picker;
        };
        // initializing element and component attributes
        if (element.is('input')) {
            input = element;
        }
        else {
            input = element.find(options.datepickerInput);
            if (input.length === 0) {
                input = element.find('input');
            }
            else if (!input.is('input')) {
                throw new Error('CSS class "' + options.datepickerInput + '" cannot be applied to non input element');
            }
        }
        if (element.hasClass('input-group')) {
            // in case there is more then one 'input-group-addon' Issue #48
            if (element.find('.datepickerbutton').length === 0) {
                component = element.find('.input-group-addon');
            }
            else {
                component = element.find('.datepickerbutton');
            }
        }
        if (!options.inline && !input.is('input')) {
            throw new Error('Could not initialize DateTimePicker without an input element');
        }
        // Set defaults for date here now instead of in var declaration
        date = getMoment();
        viewDate = date.clone();
        $.extend(true, options, dataToOptions());
        picker.options(options);
        initFormatting();
        attachDatePickerElementEvents();
        if (input.prop('disabled')) {
            picker.disable();
        }
        if (input.is('input') && input.val().trim().length !== 0) {
            setValue(parseInputDate(input.val().trim()));
        }
        else if (options.defaultDate && input.attr('placeholder') === undefined) {
            setValue(options.defaultDate);
        }
        if (options.inline) {
            show();
        }
        return picker;
    };
    /********************************************************************************
     *
     * jQuery plugin constructor and defaults object
     *
     ********************************************************************************/
    /**
    * See (http://jquery.com/).
    * @name jQuery
    * @class
    * See the jQuery Library  (http://jquery.com/) for full details.  This just
    * documents the function and classes that are added to jQuery by this plug-in.
    */
    /**
     * See (http://jquery.com/)
     * @name fn
     * @class
     * See the jQuery Library  (http://jquery.com/) for full details.  This just
     * documents the function and classes that are added to jQuery by this plug-in.
     * @memberOf jQuery
     */
    /**
     * Show comments
     * @class datetimepicker
     * @memberOf jQuery.fn
     */
    $.fn.datetimepicker = function (options) {
        options = options || {};
        var args = Array.prototype.slice.call(arguments, 1), isInstance = true, thisMethods = ['destroy', 'hide', 'show', 'toggle'], returnValue;
        if (typeof options === 'object') {
            return this.each(function () {
                var $this = $(this), _options;
                if (!$this.data('DateTimePicker')) {
                    // create a private copy of the defaults object
                    _options = $.extend(true, {}, $.fn.datetimepicker.defaults, options);
                    $this.data('DateTimePicker', dateTimePicker($this, _options));
                }
            });
        }
        else if (typeof options === 'string') {
            this.each(function () {
                var $this = $(this), instance = $this.data('DateTimePicker');
                if (!instance) {
                    throw new Error('bootstrap-datetimepicker("' + options + '") method was called on an element that is not using DateTimePicker');
                }
                returnValue = instance[options].apply(instance, args);
                isInstance = returnValue === instance;
            });
            if (isInstance || $.inArray(options, thisMethods) > -1) {
                return this;
            }
            return returnValue;
        }
        throw new TypeError('Invalid arguments for DateTimePicker: ' + options);
    };
    $.fn.datetimepicker.defaults = {
        timeZone: '',
        format: false,
        dayViewHeaderFormat: 'MMMM YYYY',
        extraFormats: false,
        stepping: 1,
        minDate: false,
        maxDate: false,
        useCurrent: true,
        collapse: true,
        locale: moment.locale(),
        defaultDate: false,
        disabledDates: false,
        enabledDates: false,
        icons: {
            time: 'glyphicon glyphicon-time',
            date: 'glyphicon glyphicon-calendar',
            up: 'glyphicon glyphicon-chevron-up',
            down: 'glyphicon glyphicon-chevron-down',
            previous: 'glyphicon glyphicon-chevron-left',
            next: 'glyphicon glyphicon-chevron-right',
            today: 'glyphicon glyphicon-screenshot',
            clear: 'glyphicon glyphicon-trash',
            close: 'glyphicon glyphicon-remove'
        },
        tooltips: {
            today: 'Go to today',
            clear: 'Clear selection',
            close: 'Close the picker',
            selectMonth: 'Select Month',
            prevMonth: 'Previous Month',
            nextMonth: 'Next Month',
            selectYear: 'Select Year',
            prevYear: 'Previous Year',
            nextYear: 'Next Year',
            selectDecade: 'Select Decade',
            prevDecade: 'Previous Decade',
            nextDecade: 'Next Decade',
            prevCentury: 'Previous Century',
            nextCentury: 'Next Century',
            pickHour: 'Pick Hour',
            incrementHour: 'Increment Hour',
            decrementHour: 'Decrement Hour',
            pickMinute: 'Pick Minute',
            incrementMinute: 'Increment Minute',
            decrementMinute: 'Decrement Minute',
            pickSecond: 'Pick Second',
            incrementSecond: 'Increment Second',
            decrementSecond: 'Decrement Second',
            togglePeriod: 'Toggle Period',
            selectTime: 'Select Time'
        },
        useStrict: false,
        sideBySide: false,
        daysOfWeekDisabled: false,
        calendarWeeks: false,
        viewMode: 'days',
        toolbarPlacement: 'default',
        showTodayButton: false,
        showClear: false,
        showClose: false,
        widgetPositioning: {
            horizontal: 'auto',
            vertical: 'auto'
        },
        widgetParent: null,
        ignoreReadonly: false,
        keepOpen: false,
        focusOnShow: true,
        inline: false,
        keepInvalid: false,
        datepickerInput: '.datepickerinput',
        keyBinds: {
            up: function (widget) {
                if (!widget) {
                    return;
                }
                var d = this.date() || this.getMoment();
                if (widget.find('.datepicker').is(':visible')) {
                    this.date(d.clone().subtract(7, 'd'));
                }
                else {
                    this.date(d.clone().add(this.stepping(), 'm'));
                }
            },
            down: function (widget) {
                if (!widget) {
                    this.show();
                    return;
                }
                var d = this.date() || this.getMoment();
                if (widget.find('.datepicker').is(':visible')) {
                    this.date(d.clone().add(7, 'd'));
                }
                else {
                    this.date(d.clone().subtract(this.stepping(), 'm'));
                }
            },
            'control up': function (widget) {
                if (!widget) {
                    return;
                }
                var d = this.date() || this.getMoment();
                if (widget.find('.datepicker').is(':visible')) {
                    this.date(d.clone().subtract(1, 'y'));
                }
                else {
                    this.date(d.clone().add(1, 'h'));
                }
            },
            'control down': function (widget) {
                if (!widget) {
                    return;
                }
                var d = this.date() || this.getMoment();
                if (widget.find('.datepicker').is(':visible')) {
                    this.date(d.clone().add(1, 'y'));
                }
                else {
                    this.date(d.clone().subtract(1, 'h'));
                }
            },
            left: function (widget) {
                if (!widget) {
                    return;
                }
                var d = this.date() || this.getMoment();
                if (widget.find('.datepicker').is(':visible')) {
                    this.date(d.clone().subtract(1, 'd'));
                }
            },
            right: function (widget) {
                if (!widget) {
                    return;
                }
                var d = this.date() || this.getMoment();
                if (widget.find('.datepicker').is(':visible')) {
                    this.date(d.clone().add(1, 'd'));
                }
            },
            pageUp: function (widget) {
                if (!widget) {
                    return;
                }
                var d = this.date() || this.getMoment();
                if (widget.find('.datepicker').is(':visible')) {
                    this.date(d.clone().subtract(1, 'M'));
                }
            },
            pageDown: function (widget) {
                if (!widget) {
                    return;
                }
                var d = this.date() || this.getMoment();
                if (widget.find('.datepicker').is(':visible')) {
                    this.date(d.clone().add(1, 'M'));
                }
            },
            enter: function () {
                this.hide();
            },
            escape: function () {
                this.hide();
            },
            //tab: function (widget) { //this break the flow of the form. disabling for now
            //    var toggle = widget.find('.picker-switch a[data-action="togglePicker"]');
            //    if(toggle.length > 0) toggle.click();
            //},
            'control space': function (widget) {
                if (!widget) {
                    return;
                }
                if (widget.find('.timepicker').is(':visible')) {
                    widget.find('.btn[data-action="togglePeriod"]').click();
                }
            },
            t: function () {
                this.date(this.getMoment());
            },
            'delete': function () {
                this.clear();
            }
        },
        debug: false,
        allowInputToggle: false,
        disabledTimeIntervals: false,
        disabledHours: false,
        enabledHours: false,
        viewDate: false
    };
    return $.fn.datetimepicker;
}));
//# sourceMappingURL=bootstrap-datetimepicker.js.map 
//# sourceMappingURL=bootstrap-datetimepicker.js.map 
//# sourceMappingURL=bootstrap-datetimepicker.js.map 
//# sourceMappingURL=bootstrap-datetimepicker.js.map 
//# sourceMappingURL=bootstrap-datetimepicker.js.map;
/*! X-editable - v1.5.1 
* In-place editing with Twitter Bootstrap, jQuery UI or pure jQuery
* http://github.com/vitalets/x-editable
* Copyright (c) 2013 Vitaliy Potapov; Licensed MIT */
/**
Form with single input element, two buttons and two states: normal/loading.
Applied as jQuery method to DIV tag (not to form tag!). This is because form can be in loading state when spinner shown.
Editableform is linked with one of input types, e.g. 'text', 'select' etc.

@class editableform
@uses text
@uses textarea
**/
(function ($) {
    "use strict";
    
    var EditableForm = function (div, options) {
        this.options = $.extend({}, $.fn.editableform.defaults, options);
        this.$div = $(div); //div, containing form. Not form tag. Not editable-element.
        if(!this.options.scope) {
            this.options.scope = this;
        }
        //nothing shown after init
    };

    EditableForm.prototype = {
        constructor: EditableForm,
        initInput: function() {  //called once
            //take input from options (as it is created in editable-element)
            this.input = this.options.input;
            
            //set initial value
            //todo: may be add check: typeof str === 'string' ? 
            this.value = this.input.str2value(this.options.value); 
            
            //prerender: get input.$input
            this.input.prerender();
        },
        initTemplate: function() {
            this.$form = $($.fn.editableform.template); 
        },
        initButtons: function() {
            var $btn = this.$form.find('.editable-buttons');
            $btn.append($.fn.editableform.buttons);
            if(this.options.showbuttons === 'bottom') {
                $btn.addClass('editable-buttons-bottom');
            }
        },
        /**
        Renders editableform

        @method render
        **/        
        render: function() {
            //init loader
            this.$loading = $($.fn.editableform.loading);        
            this.$div.empty().append(this.$loading);
            
            //init form template and buttons
            this.initTemplate();
            if(this.options.showbuttons) {
                this.initButtons();
            } else {
                this.$form.find('.editable-buttons').remove();
            }

            //show loading state
            this.showLoading();            
            
            //flag showing is form now saving value to server. 
            //It is needed to wait when closing form.
            this.isSaving = false;
            
            /**        
            Fired when rendering starts
            @event rendering 
            @param {Object} event event object
            **/            
            this.$div.triggerHandler('rendering');
            
            //init input
            this.initInput();
            
            //append input to form
            this.$form.find('div.editable-input').append(this.input.$tpl);            
            
            //append form to container
            this.$div.append(this.$form);
            
            //render input
            $.when(this.input.render())
            .then($.proxy(function () {
                //setup input to submit automatically when no buttons shown
                if(!this.options.showbuttons) {
                    this.input.autosubmit(); 
                }
                 
                //attach 'cancel' handler
                this.$form.find('.editable-cancel').click($.proxy(this.cancel, this));
                
                if(this.input.error) {
                    this.error(this.input.error);
                    this.$form.find('.editable-submit').attr('disabled', true);
                    this.input.$input.attr('disabled', true);
                    //prevent form from submitting
                    this.$form.submit(function(e){ e.preventDefault(); });
                } else {
                    this.error(false);
                    this.input.$input.removeAttr('disabled');
                    this.$form.find('.editable-submit').removeAttr('disabled');
                    var value = (this.value === null || this.value === undefined || this.value === '') ? this.options.defaultValue : this.value;
                    this.input.value2input(value);
                    //attach submit handler
                    this.$form.submit($.proxy(this.submit, this));
                }

                /**        
                Fired when form is rendered
                @event rendered
                @param {Object} event event object
                **/            
                this.$div.triggerHandler('rendered');                

                this.showForm();
                
                //call postrender method to perform actions required visibility of form
                if(this.input.postrender) {
                    this.input.postrender();
                }                
            }, this));
        },
        cancel: function() {   
            /**        
            Fired when form was cancelled by user
            @event cancel 
            @param {Object} event event object
            **/              
            this.$div.triggerHandler('cancel');
        },
        showLoading: function() {
            var w, h;
            if(this.$form) {
                //set loading size equal to form
                w = this.$form.outerWidth();
                h = this.$form.outerHeight(); 
                if(w) {
                    this.$loading.width(w);
                }
                if(h) {
                    this.$loading.height(h);
                }
                this.$form.hide();
            } else {
                //stretch loading to fill container width
                w = this.$loading.parent().width();
                if(w) {
                    this.$loading.width(w);
                }
            }
            this.$loading.show(); 
        },

        showForm: function(activate) {
            this.$loading.hide();
            this.$form.show();
            if(activate !== false) {
                this.input.activate(); 
            }
            /**        
            Fired when form is shown
            @event show 
            @param {Object} event event object
            **/                    
            this.$div.triggerHandler('show');
        },

        error: function(msg) {
            var $group = this.$form.find('.control-group'),
                $block = this.$form.find('.editable-error-block'),
                lines;

            if(msg === false) {
                $group.removeClass($.fn.editableform.errorGroupClass);
                $block.removeClass($.fn.editableform.errorBlockClass).empty().hide(); 
            } else {
                //convert newline to <br> for more pretty error display
                if(msg) {
                    lines = (''+msg).split('\n');
                    for (var i = 0; i < lines.length; i++) {
                        lines[i] = $('<div>').text(lines[i]).html();
                    }
                    msg = lines.join('<br>');
                }
                $group.addClass($.fn.editableform.errorGroupClass);
                $block.addClass($.fn.editableform.errorBlockClass).html(msg).show();
            }
        },

        submit: function(e) {
            e.stopPropagation();
            e.preventDefault();
            
            //get new value from input
            var newValue = this.input.input2value(); 

            //validation: if validate returns string or truthy value - means error
            //if returns object like {newValue: '...'} => submitted value is reassigned to it
            var error = this.validate(newValue);
            if ($.type(error) === 'object' && error.newValue !== undefined) {
                newValue = error.newValue;
                this.input.value2input(newValue);
                if(typeof error.msg === 'string') {
                    this.error(error.msg);
                    this.showForm();
                    return;
                }
            } else if (error) {
                this.error(error);
                this.showForm();
                return;
            } 
            
            //if value not changed --> trigger 'nochange' event and return
            /*jslint eqeq: true*/
            if (!this.options.savenochange && this.input.value2str(newValue) == this.input.value2str(this.value)) {
            /*jslint eqeq: false*/                
                /**        
                Fired when value not changed but form is submitted. Requires savenochange = false.
                @event nochange 
                @param {Object} event event object
                **/                    
                this.$div.triggerHandler('nochange');            
                return;
            } 

            //convert value for submitting to server
            var submitValue = this.input.value2submit(newValue);
            
            this.isSaving = true;
            
            //sending data to server
            $.when(this.save(submitValue))
            .done($.proxy(function(response) {
                this.isSaving = false;

                //run success callback
                var res = typeof this.options.success === 'function' ? this.options.success.call(this.options.scope, response, newValue) : null;

                //if success callback returns false --> keep form open and do not activate input
                if(res === false) {
                    this.error(false);
                    this.showForm(false);
                    return;
                }

                //if success callback returns string -->  keep form open, show error and activate input               
                if(typeof res === 'string') {
                    this.error(res);
                    this.showForm();
                    return;
                }

                //if success callback returns object like {newValue: <something>} --> use that value instead of submitted
                //it is usefull if you want to chnage value in url-function
                if(res && typeof res === 'object' && res.hasOwnProperty('newValue')) {
                    newValue = res.newValue;
                }

                //clear error message
                this.error(false);   
                this.value = newValue;
                /**        
                Fired when form is submitted
                @event save 
                @param {Object} event event object
                @param {Object} params additional params
                @param {mixed} params.newValue raw new value
                @param {mixed} params.submitValue submitted value as string
                @param {Object} params.response ajax response

                @example
                $('#form-div').on('save'), function(e, params){
                    if(params.newValue === 'username') {...}
                });
                **/
                this.$div.triggerHandler('save', {newValue: newValue, submitValue: submitValue, response: response});
            }, this))
            .fail($.proxy(function(xhr) {
                this.isSaving = false;

                var msg;
                if(typeof this.options.error === 'function') {
                    msg = this.options.error.call(this.options.scope, xhr, newValue);
                } else {
                    msg = typeof xhr === 'string' ? xhr : xhr.responseText || xhr.statusText || 'Unknown error!';
                }

                this.error(msg);
                this.showForm();
            }, this));
        },

        save: function(submitValue) {
            //try parse composite pk defined as json string in data-pk 
            this.options.pk = $.fn.editableutils.tryParseJson(this.options.pk, true); 
            
            var pk = (typeof this.options.pk === 'function') ? this.options.pk.call(this.options.scope) : this.options.pk,
            /*
              send on server in following cases:
              1. url is function
              2. url is string AND (pk defined OR send option = always) 
            */
            send = !!(typeof this.options.url === 'function' || (this.options.url && ((this.options.send === 'always') || (this.options.send === 'auto' && pk !== null && pk !== undefined)))),
            params;

            if (send) { //send to server
                this.showLoading();

                //standard params
                params = {
                    name: this.options.name || '',
                    value: submitValue,
                    pk: pk 
                };

                //additional params
                if(typeof this.options.params === 'function') {
                    params = this.options.params.call(this.options.scope, params);  
                } else {
                    //try parse json in single quotes (from data-params attribute)
                    this.options.params = $.fn.editableutils.tryParseJson(this.options.params, true);   
                    $.extend(params, this.options.params);
                }

                if(typeof this.options.url === 'function') { //user's function
                    return this.options.url.call(this.options.scope, params);
                } else {  
                    //send ajax to server and return deferred object
                    return $.ajax($.extend({
                        url     : this.options.url,
                        data    : params,
                        type    : 'POST'
                    }, this.options.ajaxOptions));
                }
            }
        }, 

        validate: function (value) {
            if (value === undefined) {
                value = this.value;
            }
            if (typeof this.options.validate === 'function') {
                return this.options.validate.call(this.options.scope, value);
            }
        },

        option: function(key, value) {
            if(key in this.options) {
                this.options[key] = value;
            }
            
            if(key === 'value') {
                this.setValue(value);
            }
            
            //do not pass option to input as it is passed in editable-element
        },

        setValue: function(value, convertStr) {
            if(convertStr) {
                this.value = this.input.str2value(value);
            } else {
                this.value = value;
            }
            
            //if form is visible, update input
            if(this.$form && this.$form.is(':visible')) {
                this.input.value2input(this.value);
            }            
        }               
    };

    /*
    Initialize editableform. Applied to jQuery object.

    @method $().editableform(options)
    @params {Object} options
    @example
    var $form = $('&lt;div&gt;').editableform({
        type: 'text',
        name: 'username',
        url: '/post',
        value: 'vitaliy'
    });

    //to display form you should call 'render' method
    $form.editableform('render');     
    */
    $.fn.editableform = function (option) {
        var args = arguments;
        return this.each(function () {
            var $this = $(this), 
            data = $this.data('editableform'), 
            options = typeof option === 'object' && option; 
            if (!data) {
                $this.data('editableform', (data = new EditableForm(this, options)));
            }

            if (typeof option === 'string') { //call method 
                data[option].apply(data, Array.prototype.slice.call(args, 1));
            } 
        });
    };

    //keep link to constructor to allow inheritance
    $.fn.editableform.Constructor = EditableForm;    

    //defaults
    $.fn.editableform.defaults = {
        /* see also defaults for input */

        /**
        Type of input. Can be <code>text|textarea|select|date|checklist</code>

        @property type 
        @type string
        @default 'text'
        **/
        type: 'text',
        /**
        Url for submit, e.g. <code>'/post'</code>  
        If function - it will be called instead of ajax. Function should return deferred object to run fail/done callbacks.

        @property url 
        @type string|function
        @default null
        @example
        url: function(params) {
            var d = new $.Deferred;
            if(params.value === 'abc') {
                return d.reject('error message'); //returning error via deferred object
            } else {
                //async saving data in js model
                someModel.asyncSaveMethod({
                   ..., 
                   success: function(){
                      d.resolve();
                   }
                }); 
                return d.promise();
            }
        } 
        **/        
        url:null,
        /**
        Additional params for submit. If defined as <code>object</code> - it is **appended** to original ajax data (pk, name and value).  
        If defined as <code>function</code> - returned object **overwrites** original ajax data.
        @example
        params: function(params) {
            //originally params contain pk, name and value
            params.a = 1;
            return params;
        }

        @property params 
        @type object|function
        @default null
        **/          
        params:null,
        /**
        Name of field. Will be submitted on server. Can be taken from <code>id</code> attribute

        @property name 
        @type string
        @default null
        **/         
        name: null,
        /**
        Primary key of editable object (e.g. record id in database). For composite keys use object, e.g. <code>{id: 1, lang: 'en'}</code>.
        Can be calculated dynamically via function.

        @property pk 
        @type string|object|function
        @default null
        **/         
        pk: null,
        /**
        Initial value. If not defined - will be taken from element's content.
        For __select__ type should be defined (as it is ID of shown text).

        @property value 
        @type string|object
        @default null
        **/        
        value: null,
        /**
        Value that will be displayed in input if original field value is empty (`null|undefined|''`).

        @property defaultValue 
        @type string|object
        @default null
        @since 1.4.6
        **/        
        defaultValue: null,
        /**
        Strategy for sending data on server. Can be `auto|always|never`.
        When 'auto' data will be sent on server **only if pk and url defined**, otherwise new value will be stored locally.

        @property send 
        @type string
        @default 'auto'
        **/          
        send: 'auto', 
        /**
        Function for client-side validation. If returns string - means validation not passed and string showed as error.
        Since 1.5.1 you can modify submitted value by returning object from `validate`: 
        `{newValue: '...'}` or `{newValue: '...', msg: '...'}`

        @property validate 
        @type function
        @default null
        @example
        validate: function(value) {
            if($.trim(value) == '') {
                return 'This field is required';
            }
        }
        **/         
        validate: null,
        /**
        Success callback. Called when value successfully sent on server and **response status = 200**.  
        Usefull to work with json response. For example, if your backend response can be <code>{success: true}</code>
        or <code>{success: false, msg: "server error"}</code> you can check it inside this callback.  
        If it returns **string** - means error occured and string is shown as error message.  
        If it returns **object like** <code>{newValue: &lt;something&gt;}</code> - it overwrites value, submitted by user.  
        Otherwise newValue simply rendered into element.
        
        @property success 
        @type function
        @default null
        @example
        success: function(response, newValue) {
            if(!response.success) return response.msg;
        }
        **/          
        success: null,
        /**
        Error callback. Called when request failed (response status != 200).  
        Usefull when you want to parse error response and display a custom message.
        Must return **string** - the message to be displayed in the error block.
                
        @property error 
        @type function
        @default null
        @since 1.4.4
        @example
        error: function(response, newValue) {
            if(response.status === 500) {
                return 'Service unavailable. Please try later.';
            } else {
                return response.responseText;
            }
        }
        **/          
        error: null,
        /**
        Additional options for submit ajax request.
        List of values: http://api.jquery.com/jQuery.ajax
        
        @property ajaxOptions 
        @type object
        @default null
        @since 1.1.1        
        @example 
        ajaxOptions: {
            type: 'put',
            dataType: 'json'
        }        
        **/        
        ajaxOptions: null,
        /**
        Where to show buttons: left(true)|bottom|false  
        Form without buttons is auto-submitted.

        @property showbuttons 
        @type boolean|string
        @default true
        @since 1.1.1
        **/         
        showbuttons: true,
        /**
        Scope for callback methods (success, validate).  
        If <code>null</code> means editableform instance itself. 

        @property scope 
        @type DOMElement|object
        @default null
        @since 1.2.0
        @private
        **/            
        scope: null,
        /**
        Whether to save or cancel value when it was not changed but form was submitted

        @property savenochange 
        @type boolean
        @default false
        @since 1.2.0
        **/
        savenochange: false
    };   

    /*
    Note: following params could redefined in engine: bootstrap or jqueryui:
    Classes 'control-group' and 'editable-error-block' must always present!
    */      
    $.fn.editableform.template = '<form class="form-inline editableform">'+
    '<div class="control-group">' + 
    '<div><div class="editable-input"></div><div class="editable-buttons"></div></div>'+
    '<div class="editable-error-block"></div>' + 
    '</div>' + 
    '</form>';

    //loading div
    $.fn.editableform.loading = '<div class="editableform-loading"></div>';

    //buttons
    $.fn.editableform.buttons = '<button type="submit" class="editable-submit">ok</button>'+
    '<button type="button" class="editable-cancel">cancel</button>';      

    //error class attached to control-group
    $.fn.editableform.errorGroupClass = null;  

    //error class attached to editable-error-block
    $.fn.editableform.errorBlockClass = 'editable-error';
    
    //engine
    $.fn.editableform.engine = 'jquery';
}(window.jQuery));

/**
* EditableForm utilites
*/
(function ($) {
    "use strict";
    
    //utils
    $.fn.editableutils = {
        /**
        * classic JS inheritance function
        */  
        inherit: function (Child, Parent) {
            var F = function() { };
            F.prototype = Parent.prototype;
            Child.prototype = new F();
            Child.prototype.constructor = Child;
            Child.superclass = Parent.prototype;
        },

        /**
        * set caret position in input
        * see http://stackoverflow.com/questions/499126/jquery-set-cursor-position-in-text-area
        */        
        setCursorPosition: function(elem, pos) {
            if (elem.setSelectionRange) {
                elem.setSelectionRange(pos, pos);
            } else if (elem.createTextRange) {
                var range = elem.createTextRange();
                range.collapse(true);
                range.moveEnd('character', pos);
                range.moveStart('character', pos);
                range.select();
            }
        },

        /**
        * function to parse JSON in *single* quotes. (jquery automatically parse only double quotes)
        * That allows such code as: <a data-source="{'a': 'b', 'c': 'd'}">
        * safe = true --> means no exception will be thrown
        * for details see http://stackoverflow.com/questions/7410348/how-to-set-json-format-to-html5-data-attributes-in-the-jquery
        */
        tryParseJson: function(s, safe) {
            if (typeof s === 'string' && s.length && s.match(/^[\{\[].*[\}\]]$/)) {
                if (safe) {
                    try {
                        /*jslint evil: true*/
                        s = (new Function('return ' + s))();
                        /*jslint evil: false*/
                    } catch (e) {} finally {
                        return s;
                    }
                } else {
                    /*jslint evil: true*/
                    s = (new Function('return ' + s))();
                    /*jslint evil: false*/
                }
            }
            return s;
        },

        /**
        * slice object by specified keys
        */
        sliceObj: function(obj, keys, caseSensitive /* default: false */) {
            var key, keyLower, newObj = {};

            if (!$.isArray(keys) || !keys.length) {
                return newObj;
            }

            for (var i = 0; i < keys.length; i++) {
                key = keys[i];
                if (obj.hasOwnProperty(key)) {
                    newObj[key] = obj[key];
                }

                if(caseSensitive === true) {
                    continue;
                }

                //when getting data-* attributes via $.data() it's converted to lowercase.
                //details: http://stackoverflow.com/questions/7602565/using-data-attributes-with-jquery
                //workaround is code below.
                keyLower = key.toLowerCase();
                if (obj.hasOwnProperty(keyLower)) {
                    newObj[key] = obj[keyLower];
                }
            }

            return newObj;
        },

        /*
        exclude complex objects from $.data() before pass to config
        */
        getConfigData: function($element) {
            var data = {};
            $.each($element.data(), function(k, v) {
                if(typeof v !== 'object' || (v && typeof v === 'object' && (v.constructor === Object || v.constructor === Array))) {
                    data[k] = v;
                }
            });
            return data;
        },

        /*
         returns keys of object
        */
        objectKeys: function(o) {
            if (Object.keys) {
                return Object.keys(o);  
            } else {
                if (o !== Object(o)) {
                    throw new TypeError('Object.keys called on a non-object');
                }
                var k=[], p;
                for (p in o) {
                    if (Object.prototype.hasOwnProperty.call(o,p)) {
                        k.push(p);
                    }
                }
                return k;
            }

        },
        
       /**
        method to escape html.
       **/
       escape: function(str) {
           return $('<div>').text(str).html();
       },
       
       /*
        returns array items from sourceData having value property equal or inArray of 'value'
       */
       itemsByValue: function(value, sourceData, valueProp) {
           if(!sourceData || value === null) {
               return [];
           }
           
           if (typeof(valueProp) !== "function") {
               var idKey = valueProp || 'value';
               valueProp = function (e) { return e[idKey]; };
           }
                      
           var isValArray = $.isArray(value),
           result = [], 
           that = this;

           $.each(sourceData, function(i, o) {
               if(o.children) {
                   result = result.concat(that.itemsByValue(value, o.children, valueProp));
               } else {
                   /*jslint eqeq: true*/
                   if(isValArray) {
                       if($.grep(value, function(v){  return v == (o && typeof o === 'object' ? valueProp(o) : o); }).length) {
                           result.push(o); 
                       }
                   } else {
                       var itemValue = (o && (typeof o === 'object')) ? valueProp(o) : o;
                       if(value == itemValue) {
                           result.push(o); 
                       }
                   }
                   /*jslint eqeq: false*/
               }
           });
           
           return result;
       },
       
       /*
       Returns input by options: type, mode. 
       */
       createInput: function(options) {
           var TypeConstructor, typeOptions, input,
           type = options.type;

           //`date` is some kind of virtual type that is transformed to one of exact types
           //depending on mode and core lib
           if(type === 'date') {
               //inline
               if(options.mode === 'inline') {
                   if($.fn.editabletypes.datefield) {
                       type = 'datefield';
                   } else if($.fn.editabletypes.dateuifield) {
                       type = 'dateuifield';
                   }
               //popup
               } else {
                   if($.fn.editabletypes.date) {
                       type = 'date';
                   } else if($.fn.editabletypes.dateui) {
                       type = 'dateui';
                   }
               }
               
               //if type still `date` and not exist in types, replace with `combodate` that is base input
               if(type === 'date' && !$.fn.editabletypes.date) {
                   type = 'combodate';
               } 
           }
           
           //`datetime` should be datetimefield in 'inline' mode
           if(type === 'datetime' && options.mode === 'inline') {
             type = 'datetimefield';  
           }           

           //change wysihtml5 to textarea for jquery UI and plain versions
           if(type === 'wysihtml5' && !$.fn.editabletypes[type]) {
               type = 'textarea';
           }

           //create input of specified type. Input will be used for converting value, not in form
           if(typeof $.fn.editabletypes[type] === 'function') {
               TypeConstructor = $.fn.editabletypes[type];
               typeOptions = this.sliceObj(options, this.objectKeys(TypeConstructor.defaults));
               input = new TypeConstructor(typeOptions);
               return input;
           } else {
               $.error('Unknown type: '+ type);
               return false; 
           }  
       },
       
       //see http://stackoverflow.com/questions/7264899/detect-css-transitions-using-javascript-and-without-modernizr
       supportsTransitions: function () {
           var b = document.body || document.documentElement,
               s = b.style,
               p = 'transition',
               v = ['Moz', 'Webkit', 'Khtml', 'O', 'ms'];
               
           if(typeof s[p] === 'string') {
               return true; 
           }

           // Tests for vendor specific prop
           p = p.charAt(0).toUpperCase() + p.substr(1);
           for(var i=0; i<v.length; i++) {
               if(typeof s[v[i] + p] === 'string') { 
                   return true; 
               }
           }
           return false;
       }            
       
    };      
}(window.jQuery));

/**
Attaches stand-alone container with editable-form to HTML element. Element is used only for positioning, value is not stored anywhere.<br>
This method applied internally in <code>$().editable()</code>. You should subscribe on it's events (save / cancel) to get profit of it.<br>
Final realization can be different: bootstrap-popover, jqueryui-tooltip, poshytip, inline-div. It depends on which js file you include.<br>
Applied as jQuery method.

@class editableContainer
@uses editableform
**/
(function ($) {
    "use strict";

    var Popup = function (element, options) {
        this.init(element, options);
    };
    
    var Inline = function (element, options) {
        this.init(element, options);
    };    

    //methods
    Popup.prototype = {
        containerName: null, //method to call container on element
        containerDataName: null, //object name in element's .data()
        innerCss: null, //tbd in child class
        containerClass: 'editable-container editable-popup', //css class applied to container element
        defaults: {}, //container itself defaults
        
        init: function(element, options) {
            this.$element = $(element);
            //since 1.4.1 container do not use data-* directly as they already merged into options.
            this.options = $.extend({}, $.fn.editableContainer.defaults, options);         
            this.splitOptions();
            
            //set scope of form callbacks to element
            this.formOptions.scope = this.$element[0]; 
            
            this.initContainer();
            
            //flag to hide container, when saving value will finish
            this.delayedHide = false;

            //bind 'destroyed' listener to destroy container when element is removed from dom
            this.$element.on('destroyed', $.proxy(function(){
                this.destroy();
            }, this)); 
            
            //attach document handler to close containers on click / escape
            if(!$(document).data('editable-handlers-attached')) {
                //close all on escape
                $(document).on('keyup.editable', function (e) {
                    if (e.which === 27) {
                        $('.editable-open').editableContainer('hide');
                        //todo: return focus on element 
                    }
                });

                //close containers when click outside 
                //(mousedown could be better than click, it closes everything also on drag drop)
                $(document).on('click.editable', function(e) {
                    var $target = $(e.target), i,
                        exclude_classes = ['.editable-container', 
                                           '.ui-datepicker-header', 
                                           '.datepicker', //in inline mode datepicker is rendered into body
                                           '.modal-backdrop', 
                                           '.bootstrap-wysihtml5-insert-image-modal', 
                                           '.bootstrap-wysihtml5-insert-link-modal'
                                           ];
                    
                    //check if element is detached. It occurs when clicking in bootstrap datepicker
                    if (!$.contains(document.documentElement, e.target)) {
                      return;
                    }

                    //for some reason FF 20 generates extra event (click) in select2 widget with e.target = document
                    //we need to filter it via construction below. See https://github.com/vitalets/x-editable/issues/199
                    //Possibly related to http://stackoverflow.com/questions/10119793/why-does-firefox-react-differently-from-webkit-and-ie-to-click-event-on-selec
                    if($target.is(document)) {
                       return; 
                    }
                    
                    //if click inside one of exclude classes --> no nothing
                    for(i=0; i<exclude_classes.length; i++) {
                         if($target.is(exclude_classes[i]) || $target.parents(exclude_classes[i]).length) {
                             return;
                         }
                    }
                      
                    //close all open containers (except one - target)
                    Popup.prototype.closeOthers(e.target);
                });
                
                $(document).data('editable-handlers-attached', true);
            }                        
        },

        //split options on containerOptions and formOptions
        splitOptions: function() {
            this.containerOptions = {};
            this.formOptions = {};
            
            if(!$.fn[this.containerName]) {
                throw new Error(this.containerName + ' not found. Have you included corresponding js file?');   
            }
            
            //keys defined in container defaults go to container, others go to form
            for(var k in this.options) {
              if(k in this.defaults) {
                 this.containerOptions[k] = this.options[k];
              } else {
                 this.formOptions[k] = this.options[k];
              } 
            }
        },
        
        /*
        Returns jquery object of container
        @method tip()
        */         
        tip: function() {
            return this.container() ? this.container().$tip : null;
        },

        /* returns container object */
        container: function() {
            var container;
            //first, try get it by `containerDataName`
            if(this.containerDataName) {
                if(container = this.$element.data(this.containerDataName)) {
                    return container;
                }
            }
            //second, try `containerName`
            container = this.$element.data(this.containerName);
            return container;
        },

        /* call native method of underlying container, e.g. this.$element.popover('method') */ 
        call: function() {
            this.$element[this.containerName].apply(this.$element, arguments); 
        },        
        
        initContainer: function(){
            this.call(this.containerOptions);
        },

        renderForm: function() {
            this.$form
            .editableform(this.formOptions)
            .on({
                save: $.proxy(this.save, this), //click on submit button (value changed)
                nochange: $.proxy(function(){ this.hide('nochange'); }, this), //click on submit button (value NOT changed)                
                cancel: $.proxy(function(){ this.hide('cancel'); }, this), //click on calcel button
                show: $.proxy(function() {
                    if(this.delayedHide) {
                        this.hide(this.delayedHide.reason);
                        this.delayedHide = false;
                    } else {
                        this.setPosition();
                    }
                }, this), //re-position container every time form is shown (occurs each time after loading state)
                rendering: $.proxy(this.setPosition, this), //this allows to place container correctly when loading shown
                resize: $.proxy(this.setPosition, this), //this allows to re-position container when form size is changed 
                rendered: $.proxy(function(){
                    /**        
                    Fired when container is shown and form is rendered (for select will wait for loading dropdown options).  
                    **Note:** Bootstrap popover has own `shown` event that now cannot be separated from x-editable's one.
                    The workaround is to check `arguments.length` that is always `2` for x-editable.                     
                    
                    @event shown 
                    @param {Object} event event object
                    @example
                    $('#username').on('shown', function(e, editable) {
                        editable.input.$input.val('overwriting value of input..');
                    });                     
                    **/                      
                    /*
                     TODO: added second param mainly to distinguish from bootstrap's shown event. It's a hotfix that will be solved in future versions via namespaced events.  
                    */
                    this.$element.triggerHandler('shown', $(this.options.scope).data('editable')); 
                }, this) 
            })
            .editableform('render');
        },        

        /**
        Shows container with form
        @method show()
        @param {boolean} closeAll Whether to close all other editable containers when showing this one. Default true.
        **/
        /* Note: poshytip owerwrites this method totally! */          
        show: function (closeAll) {
            this.$element.addClass('editable-open');
            if(closeAll !== false) {
                //close all open containers (except this)
                this.closeOthers(this.$element[0]);  
            }
            
            //show container itself
            this.innerShow();
            this.tip().addClass(this.containerClass);

            /*
            Currently, form is re-rendered on every show. 
            The main reason is that we dont know, what will container do with content when closed:
            remove(), detach() or just hide() - it depends on container.
            
            Detaching form itself before hide and re-insert before show is good solution, 
            but visually it looks ugly --> container changes size before hide.  
            */             
            
            //if form already exist - delete previous data 
            if(this.$form) {
                //todo: destroy prev data!
                //this.$form.destroy();
            }

            this.$form = $('<div>');
            
            //insert form into container body
            if(this.tip().is(this.innerCss)) {
                //for inline container
                this.tip().append(this.$form); 
            } else {
                this.tip().find(this.innerCss).append(this.$form);
            } 
            
            //render form
            this.renderForm();
        },

        /**
        Hides container with form
        @method hide()
        @param {string} reason Reason caused hiding. Can be <code>save|cancel|onblur|nochange|undefined (=manual)</code>
        **/         
        hide: function(reason) {  
            if(!this.tip() || !this.tip().is(':visible') || !this.$element.hasClass('editable-open')) {
                return;
            }
            
            //if form is saving value, schedule hide
            if(this.$form.data('editableform').isSaving) {
                this.delayedHide = {reason: reason};
                return;    
            } else {
                this.delayedHide = false;
            }

            this.$element.removeClass('editable-open');   
            this.innerHide();

            /**
            Fired when container was hidden. It occurs on both save or cancel.  
            **Note:** Bootstrap popover has own `hidden` event that now cannot be separated from x-editable's one.
            The workaround is to check `arguments.length` that is always `2` for x-editable. 

            @event hidden 
            @param {object} event event object
            @param {string} reason Reason caused hiding. Can be <code>save|cancel|onblur|nochange|manual</code>
            @example
            $('#username').on('hidden', function(e, reason) {
                if(reason === 'save' || reason === 'cancel') {
                    //auto-open next editable
                    $(this).closest('tr').next().find('.editable').editable('show');
                } 
            });
            **/
            this.$element.triggerHandler('hidden', reason || 'manual');   
        },

        /* internal show method. To be overwritten in child classes */
        innerShow: function () {
             
        },        

        /* internal hide method. To be overwritten in child classes */
        innerHide: function () {

        },
        
        /**
        Toggles container visibility (show / hide)
        @method toggle()
        @param {boolean} closeAll Whether to close all other editable containers when showing this one. Default true.
        **/          
        toggle: function(closeAll) {
            if(this.container() && this.tip() && this.tip().is(':visible')) {
                this.hide();
            } else {
                this.show(closeAll);
            } 
        },

        /*
        Updates the position of container when content changed.
        @method setPosition()
        */       
        setPosition: function() {
            //tbd in child class
        },

        save: function(e, params) {
            /**        
            Fired when new value was submitted. You can use <code>$(this).data('editableContainer')</code> inside handler to access to editableContainer instance
            
            @event save 
            @param {Object} event event object
            @param {Object} params additional params
            @param {mixed} params.newValue submitted value
            @param {Object} params.response ajax response
            @example
            $('#username').on('save', function(e, params) {
                //assuming server response: '{success: true}'
                var pk = $(this).data('editableContainer').options.pk;
                if(params.response && params.response.success) {
                    alert('value: ' + params.newValue + ' with pk: ' + pk + ' saved!');
                } else {
                    alert('error!'); 
                } 
            });
            **/             
            this.$element.triggerHandler('save', params);
            
            //hide must be after trigger, as saving value may require methods of plugin, applied to input
            this.hide('save');
        },

        /**
        Sets new option
        
        @method option(key, value)
        @param {string} key 
        @param {mixed} value 
        **/         
        option: function(key, value) {
            this.options[key] = value;
            if(key in this.containerOptions) {
                this.containerOptions[key] = value;
                this.setContainerOption(key, value); 
            } else {
                this.formOptions[key] = value;
                if(this.$form) {
                    this.$form.editableform('option', key, value);  
                }
            }
        },
        
        setContainerOption: function(key, value) {
            this.call('option', key, value);
        },

        /**
        Destroys the container instance
        @method destroy()
        **/        
        destroy: function() {
            this.hide();
            this.innerDestroy();
            this.$element.off('destroyed');
            this.$element.removeData('editableContainer');
        },
        
        /* to be overwritten in child classes */
        innerDestroy: function() {
            
        }, 
        
        /*
        Closes other containers except one related to passed element. 
        Other containers can be cancelled or submitted (depends on onblur option)
        */
        closeOthers: function(element) {
            $('.editable-open').each(function(i, el){
                //do nothing with passed element and it's children
                if(el === element || $(el).find(element).length) {
                    return;
                }

                //otherwise cancel or submit all open containers 
                var $el = $(el),
                ec = $el.data('editableContainer');

                if(!ec) {
                    return;  
                }
                
                if(ec.options.onblur === 'cancel') {
                    $el.data('editableContainer').hide('onblur');
                } else if(ec.options.onblur === 'submit') {
                    $el.data('editableContainer').tip().find('form').submit();
                }
            });

        },
        
        /**
        Activates input of visible container (e.g. set focus)
        @method activate()
        **/         
        activate: function() {
            if(this.tip && this.tip().is(':visible') && this.$form) {
               this.$form.data('editableform').input.activate(); 
            }
        } 

    };

    /**
    jQuery method to initialize editableContainer.
    
    @method $().editableContainer(options)
    @params {Object} options
    @example
    $('#edit').editableContainer({
        type: 'text',
        url: '/post',
        pk: 1,
        value: 'hello'
    });
    **/  
    $.fn.editableContainer = function (option) {
        var args = arguments;
        return this.each(function () {
            var $this = $(this),
            dataKey = 'editableContainer', 
            data = $this.data(dataKey),
            options = typeof option === 'object' && option,
            Constructor = (options.mode === 'inline') ? Inline : Popup;             

            if (!data) {
                $this.data(dataKey, (data = new Constructor(this, options)));
            }

            if (typeof option === 'string') { //call method 
                data[option].apply(data, Array.prototype.slice.call(args, 1));
            }            
        });
    };     

    //store constructors
    $.fn.editableContainer.Popup = Popup;
    $.fn.editableContainer.Inline = Inline;

    //defaults
    $.fn.editableContainer.defaults = {
        /**
        Initial value of form input

        @property value 
        @type mixed
        @default null
        @private
        **/        
        value: null,
        /**
        Placement of container relative to element. Can be <code>top|right|bottom|left</code>. Not used for inline container.

        @property placement 
        @type string
        @default 'top'
        **/        
        placement: 'top',
        /**
        Whether to hide container on save/cancel.

        @property autohide 
        @type boolean
        @default true
        @private 
        **/        
        autohide: true,
        /**
        Action when user clicks outside the container. Can be <code>cancel|submit|ignore</code>.  
        Setting <code>ignore</code> allows to have several containers open. 

        @property onblur 
        @type string
        @default 'cancel'
        @since 1.1.1
        **/        
        onblur: 'cancel',
        
        /**
        Animation speed (inline mode only)
        @property anim 
        @type string
        @default false
        **/        
        anim: false,
        
        /**
        Mode of editable, can be `popup` or `inline` 
        
        @property mode 
        @type string         
        @default 'popup'
        @since 1.4.0        
        **/        
        mode: 'popup'        
    };

    /* 
    * workaround to have 'destroyed' event to destroy popover when element is destroyed
    * see http://stackoverflow.com/questions/2200494/jquery-trigger-event-when-an-element-is-removed-from-the-dom
    */
    jQuery.event.special.destroyed = {
        remove: function(o) {
            if (o.handler) {
                o.handler();
            }
        }
    };    

}(window.jQuery));

/**
* Editable Inline 
* ---------------------
*/
(function ($) {
    "use strict";
    
    //copy prototype from EditableContainer
    //extend methods
    $.extend($.fn.editableContainer.Inline.prototype, $.fn.editableContainer.Popup.prototype, {
        containerName: 'editableform',
        innerCss: '.editable-inline',
        containerClass: 'editable-container editable-inline', //css class applied to container element
                 
        initContainer: function(){
            //container is <span> element
            this.$tip = $('<span></span>');
            
            //convert anim to miliseconds (int)
            if(!this.options.anim) {
                this.options.anim = 0;
            }         
        },
        
        splitOptions: function() {
            //all options are passed to form
            this.containerOptions = {};
            this.formOptions = this.options;
        },
        
        tip: function() {
           return this.$tip; 
        },
        
        innerShow: function () {
            this.$element.hide();
            this.tip().insertAfter(this.$element).show();
        }, 
        
        innerHide: function () {
            this.$tip.hide(this.options.anim, $.proxy(function() {
                this.$element.show();
                this.innerDestroy();
            }, this)); 
        },
        
        innerDestroy: function() {
            if(this.tip()) {
                this.tip().empty().remove();
            }
        } 
    });

}(window.jQuery));
/**
Makes editable any HTML element on the page. Applied as jQuery method.

@class editable
@uses editableContainer
**/
(function ($) {
    "use strict";

    var Editable = function (element, options) {
        this.$element = $(element);
        //data-* has more priority over js options: because dynamically created elements may change data-* 
        this.options = $.extend({}, $.fn.editable.defaults, options, $.fn.editableutils.getConfigData(this.$element));  
        if(this.options.selector) {
            this.initLive();
        } else {
            this.init();
        }
        
        //check for transition support
        if(this.options.highlight && !$.fn.editableutils.supportsTransitions()) {
            this.options.highlight = false;
        }
    };

    Editable.prototype = {
        constructor: Editable, 
        init: function () {
            var isValueByText = false, 
                doAutotext, finalize;

            //name
            this.options.name = this.options.name || this.$element.attr('id');
             
            //create input of specified type. Input needed already here to convert value for initial display (e.g. show text by id for select)
            //also we set scope option to have access to element inside input specific callbacks (e. g. source as function)
            this.options.scope = this.$element[0]; 
            this.input = $.fn.editableutils.createInput(this.options);
            if(!this.input) {
                return; 
            }            

            //set value from settings or by element's text
            if (this.options.value === undefined || this.options.value === null) {
                this.value = this.input.html2value($.trim(this.$element.html()));
                isValueByText = true;
            } else {
                /*
                  value can be string when received from 'data-value' attribute
                  for complext objects value can be set as json string in data-value attribute, 
                  e.g. data-value="{city: 'Moscow', street: 'Lenina'}"
                */
                this.options.value = $.fn.editableutils.tryParseJson(this.options.value, true); 
                if(typeof this.options.value === 'string') {
                    this.value = this.input.str2value(this.options.value);
                } else {
                    this.value = this.options.value;
                }
            }
            
            //add 'editable' class to every editable element
            this.$element.addClass('editable');
            
            //specifically for "textarea" add class .editable-pre-wrapped to keep linebreaks
            if(this.input.type === 'textarea') {
                this.$element.addClass('editable-pre-wrapped');
            }
            
            //attach handler activating editable. In disabled mode it just prevent default action (useful for links)
            if(this.options.toggle !== 'manual') {
                this.$element.addClass('editable-click');
                this.$element.on(this.options.toggle + '.editable', $.proxy(function(e){
                    //prevent following link if editable enabled
                    if(!this.options.disabled) {
                        e.preventDefault();
                    }
                    
                    //stop propagation not required because in document click handler it checks event target
                    //e.stopPropagation();
                    
                    if(this.options.toggle === 'mouseenter') {
                        //for hover only show container
                        this.show();
                    } else {
                        //when toggle='click' we should not close all other containers as they will be closed automatically in document click listener
                        var closeAll = (this.options.toggle !== 'click');
                        this.toggle(closeAll);
                    }
                }, this));
            } else {
                this.$element.attr('tabindex', -1); //do not stop focus on element when toggled manually
            }
            
            //if display is function it's far more convinient to have autotext = always to render correctly on init
            //see https://github.com/vitalets/x-editable-yii/issues/34
            if(typeof this.options.display === 'function') {
                this.options.autotext = 'always';
            }
            
            //check conditions for autotext:
            switch(this.options.autotext) {
              case 'always':
               doAutotext = true;
              break;
              case 'auto':
                //if element text is empty and value is defined and value not generated by text --> run autotext
                doAutotext = !$.trim(this.$element.text()).length && this.value !== null && this.value !== undefined && !isValueByText;
              break;
              default:
               doAutotext = false;
            }

            //depending on autotext run render() or just finilize init
            $.when(doAutotext ? this.render() : true).then($.proxy(function() {
                if(this.options.disabled) {
                    this.disable();
                } else {
                    this.enable(); 
                }
               /**        
               Fired when element was initialized by `$().editable()` method. 
               Please note that you should setup `init` handler **before** applying `editable`. 
                              
               @event init 
               @param {Object} event event object
               @param {Object} editable editable instance (as here it cannot accessed via data('editable'))
               @since 1.2.0
               @example
               $('#username').on('init', function(e, editable) {
                   alert('initialized ' + editable.options.name);
               });
               $('#username').editable();
               **/                  
                this.$element.triggerHandler('init', this);
            }, this));
        },

        /*
         Initializes parent element for live editables 
        */
        initLive: function() {
           //store selector 
           var selector = this.options.selector;
           //modify options for child elements
           this.options.selector = false; 
           this.options.autotext = 'never';
           //listen toggle events
           this.$element.on(this.options.toggle + '.editable', selector, $.proxy(function(e){
               var $target = $(e.target);
               if(!$target.data('editable')) {
                   //if delegated element initially empty, we need to clear it's text (that was manually set to `empty` by user)
                   //see https://github.com/vitalets/x-editable/issues/137 
                   if($target.hasClass(this.options.emptyclass)) {
                      $target.empty();
                   }
                   $target.editable(this.options).trigger(e);
               }
           }, this)); 
        },
        
        /*
        Renders value into element's text.
        Can call custom display method from options.
        Can return deferred object.
        @method render()
        @param {mixed} response server response (if exist) to pass into display function
        */          
        render: function(response) {
            //do not display anything
            if(this.options.display === false) {
                return;
            }
            
            //if input has `value2htmlFinal` method, we pass callback in third param to be called when source is loaded
            if(this.input.value2htmlFinal) {
                return this.input.value2html(this.value, this.$element[0], this.options.display, response); 
            //if display method defined --> use it    
            } else if(typeof this.options.display === 'function') {
                return this.options.display.call(this.$element[0], this.value, response);
            //else use input's original value2html() method    
            } else {
                return this.input.value2html(this.value, this.$element[0]); 
            }
        },
        
        /**
        Enables editable
        @method enable()
        **/          
        enable: function() {
            this.options.disabled = false;
            this.$element.removeClass('editable-disabled');
            this.handleEmpty(this.isEmpty);
            if(this.options.toggle !== 'manual') {
                if(this.$element.attr('tabindex') === '-1') {    
                    this.$element.removeAttr('tabindex');                                
                }
            }
        },
        
        /**
        Disables editable
        @method disable()
        **/         
        disable: function() {
            this.options.disabled = true; 
            this.hide();           
            this.$element.addClass('editable-disabled');
            this.handleEmpty(this.isEmpty);
            //do not stop focus on this element
            this.$element.attr('tabindex', -1);                
        },
        
        /**
        Toggles enabled / disabled state of editable element
        @method toggleDisabled()
        **/         
        toggleDisabled: function() {
            if(this.options.disabled) {
                this.enable();
            } else { 
                this.disable(); 
            }
        },  
        
        /**
        Sets new option
        
        @method option(key, value)
        @param {string|object} key option name or object with several options
        @param {mixed} value option new value
        @example
        $('.editable').editable('option', 'pk', 2);
        **/          
        option: function(key, value) {
            //set option(s) by object
            if(key && typeof key === 'object') {
               $.each(key, $.proxy(function(k, v){
                  this.option($.trim(k), v); 
               }, this)); 
               return;
            }

            //set option by string             
            this.options[key] = value;                          
            
            //disabled
            if(key === 'disabled') {
               return value ? this.disable() : this.enable();
            } 
            
            //value
            if(key === 'value') {
                this.setValue(value);
            }
            
            //transfer new option to container! 
            if(this.container) {
                this.container.option(key, value);  
            }
             
            //pass option to input directly (as it points to the same in form)
            if(this.input.option) {
                this.input.option(key, value);
            }
            
        },              
        
        /*
        * set emptytext if element is empty
        */
        handleEmpty: function (isEmpty) {
            //do not handle empty if we do not display anything
            if(this.options.display === false) {
                return;
            }

            /* 
            isEmpty may be set directly as param of method.
            It is required when we enable/disable field and can't rely on content 
            as node content is text: "Empty" that is not empty %)
            */
            if(isEmpty !== undefined) { 
                this.isEmpty = isEmpty;
            } else {
                //detect empty
                //for some inputs we need more smart check
                //e.g. wysihtml5 may have <br>, <p></p>, <img>
                if(typeof(this.input.isEmpty) === 'function') {
                    this.isEmpty = this.input.isEmpty(this.$element);                    
                } else {
                    this.isEmpty = $.trim(this.$element.html()) === '';
                }
            }           
            
            //emptytext shown only for enabled
            if(!this.options.disabled) {
                if (this.isEmpty) {
                    this.$element.html(this.options.emptytext);
                    if(this.options.emptyclass) {
                        this.$element.addClass(this.options.emptyclass);
                    }
                } else if(this.options.emptyclass) {
                    this.$element.removeClass(this.options.emptyclass);
                }
            } else {
                //below required if element disable property was changed
                if(this.isEmpty) {
                    this.$element.empty();
                    if(this.options.emptyclass) {
                        this.$element.removeClass(this.options.emptyclass);
                    }
                }
            }
        },        
        
        /**
        Shows container with form
        @method show()
        @param {boolean} closeAll Whether to close all other editable containers when showing this one. Default true.
        **/  
        show: function (closeAll) {
            if(this.options.disabled) {
                return;
            }
            
            //init editableContainer: popover, tooltip, inline, etc..
            if(!this.container) {
                var containerOptions = $.extend({}, this.options, {
                    value: this.value,
                    input: this.input //pass input to form (as it is already created)
                });
                this.$element.editableContainer(containerOptions);
                //listen `save` event 
                this.$element.on("save.internal", $.proxy(this.save, this));
                this.container = this.$element.data('editableContainer'); 
            } else if(this.container.tip().is(':visible')) {
                return;
            }      
            
            //show container
            this.container.show(closeAll);
        },
        
        /**
        Hides container with form
        @method hide()
        **/       
        hide: function () {   
            if(this.container) {  
                this.container.hide();
            }
        },
        
        /**
        Toggles container visibility (show / hide)
        @method toggle()
        @param {boolean} closeAll Whether to close all other editable containers when showing this one. Default true.
        **/  
        toggle: function(closeAll) {
            if(this.container && this.container.tip().is(':visible')) {
                this.hide();
            } else {
                this.show(closeAll);
            }
        },
        
        /*
        * called when form was submitted
        */          
        save: function(e, params) {
            //mark element with unsaved class if needed
            if(this.options.unsavedclass) {
                /*
                 Add unsaved css to element if:
                  - url is not user's function 
                  - value was not sent to server
                  - params.response === undefined, that means data was not sent
                  - value changed 
                */
                var sent = false;
                sent = sent || typeof this.options.url === 'function';
                sent = sent || this.options.display === false; 
                sent = sent || params.response !== undefined; 
                sent = sent || (this.options.savenochange && this.input.value2str(this.value) !== this.input.value2str(params.newValue)); 
                
                if(sent) {
                    this.$element.removeClass(this.options.unsavedclass); 
                } else {
                    this.$element.addClass(this.options.unsavedclass);                    
                }
            }
            
            //highlight when saving
            if(this.options.highlight) {
                var $e = this.$element,
                    bgColor = $e.css('background-color');
                    
                $e.css('background-color', this.options.highlight);
                setTimeout(function(){
                    if(bgColor === 'transparent') {
                        bgColor = ''; 
                    }
                    $e.css('background-color', bgColor);
                    $e.addClass('editable-bg-transition');
                    setTimeout(function(){
                       $e.removeClass('editable-bg-transition');  
                    }, 1700);
                }, 10);
            }
            
            //set new value
            this.setValue(params.newValue, false, params.response);
            
            /**        
            Fired when new value was submitted. You can use <code>$(this).data('editable')</code> to access to editable instance
            
            @event save 
            @param {Object} event event object
            @param {Object} params additional params
            @param {mixed} params.newValue submitted value
            @param {Object} params.response ajax response
            @example
            $('#username').on('save', function(e, params) {
                alert('Saved value: ' + params.newValue);
            });
            **/
            //event itself is triggered by editableContainer. Description here is only for documentation              
        },

        validate: function () {
            if (typeof this.options.validate === 'function') {
                return this.options.validate.call(this, this.value);
            }
        },
        
        /**
        Sets new value of editable
        @method setValue(value, convertStr)
        @param {mixed} value new value 
        @param {boolean} convertStr whether to convert value from string to internal format
        **/         
        setValue: function(value, convertStr, response) {
            if(convertStr) {
                this.value = this.input.str2value(value);
            } else {
                this.value = value;
            }
            if(this.container) {
                this.container.option('value', this.value);
            }
            $.when(this.render(response))
            .then($.proxy(function() {
                this.handleEmpty();
            }, this));
        },
        
        /**
        Activates input of visible container (e.g. set focus)
        @method activate()
        **/         
        activate: function() {
            if(this.container) {
               this.container.activate(); 
            }
        },
        
        /**
        Removes editable feature from element
        @method destroy()
        **/        
        destroy: function() {
            this.disable();
            
            if(this.container) {
               this.container.destroy(); 
            }
            
            this.input.destroy();

            if(this.options.toggle !== 'manual') {
                this.$element.removeClass('editable-click');
                this.$element.off(this.options.toggle + '.editable');
            } 
            
            this.$element.off("save.internal");
            
            this.$element.removeClass('editable editable-open editable-disabled');
            this.$element.removeData('editable');
        }        
    };

    /* EDITABLE PLUGIN DEFINITION
    * ======================= */

    /**
    jQuery method to initialize editable element.
    
    @method $().editable(options)
    @params {Object} options
    @example
    $('#username').editable({
        type: 'text',
        url: '/post',
        pk: 1
    });
    **/
    $.fn.editable = function (option) {
        //special API methods returning non-jquery object
        var result = {}, args = arguments, datakey = 'editable';
        switch (option) {
            /**
            Runs client-side validation for all matched editables
            
            @method validate()
            @returns {Object} validation errors map
            @example
            $('#username, #fullname').editable('validate');
            // possible result:
            {
              username: "username is required",
              fullname: "fullname should be minimum 3 letters length"
            }
            **/
            case 'validate':
                this.each(function () {
                    var $this = $(this), data = $this.data(datakey), error;
                    if (data && (error = data.validate())) {
                        result[data.options.name] = error;
                    }
                });
            return result;

            /**
            Returns current values of editable elements.   
            Note that it returns an **object** with name-value pairs, not a value itself. It allows to get data from several elements.    
            If value of some editable is `null` or `undefined` it is excluded from result object.
            When param `isSingle` is set to **true** - it is supposed you have single element and will return value of editable instead of object.   
             
            @method getValue()
            @param {bool} isSingle whether to return just value of single element
            @returns {Object} object of element names and values
            @example
            $('#username, #fullname').editable('getValue');
            //result:
            {
            username: "superuser",
            fullname: "John"
            }
            //isSingle = true
            $('#username').editable('getValue', true);
            //result "superuser" 
            **/
            case 'getValue':
                if(arguments.length === 2 && arguments[1] === true) { //isSingle = true
                    result = this.eq(0).data(datakey).value;
                } else {
                    this.each(function () {
                        var $this = $(this), data = $this.data(datakey);
                        if (data && data.value !== undefined && data.value !== null) {
                            result[data.options.name] = data.input.value2submit(data.value);
                        }
                    });
                }
            return result;

            /**
            This method collects values from several editable elements and submit them all to server.   
            Internally it runs client-side validation for all fields and submits only in case of success.  
            See <a href="#newrecord">creating new records</a> for details.  
            Since 1.5.1 `submit` can be applied to single element to send data programmatically. In that case
            `url`, `success` and `error` is taken from initial options and you can just call `$('#username').editable('submit')`. 
            
            @method submit(options)
            @param {object} options 
            @param {object} options.url url to submit data 
            @param {object} options.data additional data to submit
            @param {object} options.ajaxOptions additional ajax options
            @param {function} options.error(obj) error handler 
            @param {function} options.success(obj,config) success handler
            @returns {Object} jQuery object
            **/
            case 'submit':  //collects value, validate and submit to server for creating new record
                var config = arguments[1] || {},
                $elems = this,
                errors = this.editable('validate');

                // validation ok
                if($.isEmptyObject(errors)) {
                    var ajaxOptions = {};
                                                      
                    // for single element use url, success etc from options
                    if($elems.length === 1) {
                        var editable = $elems.data('editable');
                        //standard params
                        var params = {
                            name: editable.options.name || '',
                            value: editable.input.value2submit(editable.value),
                            pk: (typeof editable.options.pk === 'function') ? 
                                editable.options.pk.call(editable.options.scope) : 
                                editable.options.pk 
                        };

                        //additional params
                        if(typeof editable.options.params === 'function') {
                            params = editable.options.params.call(editable.options.scope, params);  
                        } else {
                            //try parse json in single quotes (from data-params attribute)
                            editable.options.params = $.fn.editableutils.tryParseJson(editable.options.params, true);   
                            $.extend(params, editable.options.params);
                        }

                        ajaxOptions = {
                            url: editable.options.url,
                            data: params,
                            type: 'POST'  
                        };
                        
                        // use success / error from options 
                        config.success = config.success || editable.options.success;
                        config.error = config.error || editable.options.error;
                        
                    // multiple elements
                    } else {
                        var values = this.editable('getValue'); 
                        
                        ajaxOptions = {
                            url: config.url,
                            data: values, 
                            type: 'POST'
                        };                        
                    }                    

                    // ajax success callabck (response 200 OK)
                    ajaxOptions.success = typeof config.success === 'function' ? function(response) {
                            config.success.call($elems, response, config);
                        } : $.noop;
                                  
                    // ajax error callabck
                    ajaxOptions.error = typeof config.error === 'function' ? function() {
                             config.error.apply($elems, arguments);
                        } : $.noop;
                       
                    // extend ajaxOptions    
                    if(config.ajaxOptions) { 
                        $.extend(ajaxOptions, config.ajaxOptions);
                    }
                    
                    // extra data 
                    if(config.data) {
                        $.extend(ajaxOptions.data, config.data);
                    }                     
                    
                    // perform ajax request
                    $.ajax(ajaxOptions);
                } else { //client-side validation error
                    if(typeof config.error === 'function') {
                        config.error.call($elems, errors);
                    }
                }
            return this;
        }

        //return jquery object
        return this.each(function () {
            var $this = $(this), 
                data = $this.data(datakey), 
                options = typeof option === 'object' && option;

            //for delegated targets do not store `editable` object for element
            //it's allows several different selectors.
            //see: https://github.com/vitalets/x-editable/issues/312    
            if(options && options.selector) {
                data = new Editable(this, options);
                return; 
            }    
            
            if (!data) {
                $this.data(datakey, (data = new Editable(this, options)));
            }

            if (typeof option === 'string') { //call method 
                data[option].apply(data, Array.prototype.slice.call(args, 1));
            } 
        });
    };    
            

    $.fn.editable.defaults = {
        /**
        Type of input. Can be <code>text|textarea|select|date|checklist</code> and more

        @property type 
        @type string
        @default 'text'
        **/
        type: 'text',        
        /**
        Sets disabled state of editable

        @property disabled 
        @type boolean
        @default false
        **/         
        disabled: false,
        /**
        How to toggle editable. Can be <code>click|dblclick|mouseenter|manual</code>.   
        When set to <code>manual</code> you should manually call <code>show/hide</code> methods of editable.    
        **Note**: if you call <code>show</code> or <code>toggle</code> inside **click** handler of some DOM element, 
        you need to apply <code>e.stopPropagation()</code> because containers are being closed on any click on document.
        
        @example
        $('#edit-button').click(function(e) {
            e.stopPropagation();
            $('#username').editable('toggle');
        });

        @property toggle 
        @type string
        @default 'click'
        **/          
        toggle: 'click',
        /**
        Text shown when element is empty.

        @property emptytext 
        @type string
        @default 'Empty'
        **/         
        emptytext: 'Empty',
        /**
        Allows to automatically set element's text based on it's value. Can be <code>auto|always|never</code>. Useful for select and date.
        For example, if dropdown list is <code>{1: 'a', 2: 'b'}</code> and element's value set to <code>1</code>, it's html will be automatically set to <code>'a'</code>.  
        <code>auto</code> - text will be automatically set only if element is empty.  
        <code>always|never</code> - always(never) try to set element's text.

        @property autotext 
        @type string
        @default 'auto'
        **/          
        autotext: 'auto', 
        /**
        Initial value of input. If not set, taken from element's text.  
        Note, that if element's text is empty - text is automatically generated from value and can be customized (see `autotext` option).  
        For example, to display currency sign:
        @example
        <a id="price" data-type="text" data-value="100"></a>
        <script>
        $('#price').editable({
            ...
            display: function(value) {
              $(this).text(value + '$');
            } 
        }) 
        </script>
                
        @property value 
        @type mixed
        @default element's text
        **/
        value: null,
        /**
        Callback to perform custom displaying of value in element's text.  
        If `null`, default input's display used.  
        If `false`, no displaying methods will be called, element's text will never change.  
        Runs under element's scope.  
        _**Parameters:**_  
        
        * `value` current value to be displayed
        * `response` server response (if display called after ajax submit), since 1.4.0
         
        For _inputs with source_ (select, checklist) parameters are different:  
          
        * `value` current value to be displayed
        * `sourceData` array of items for current input (e.g. dropdown items) 
        * `response` server response (if display called after ajax submit), since 1.4.0
                  
        To get currently selected items use `$.fn.editableutils.itemsByValue(value, sourceData)`.
        
        @property display 
        @type function|boolean
        @default null
        @since 1.2.0
        @example
        display: function(value, sourceData) {
           //display checklist as comma-separated values
           var html = [],
               checked = $.fn.editableutils.itemsByValue(value, sourceData);
               
           if(checked.length) {
               $.each(checked, function(i, v) { html.push($.fn.editableutils.escape(v.text)); });
               $(this).html(html.join(', '));
           } else {
               $(this).empty(); 
           }
        }
        **/          
        display: null,
        /**
        Css class applied when editable text is empty.

        @property emptyclass 
        @type string
        @since 1.4.1        
        @default editable-empty
        **/        
        emptyclass: 'editable-empty',
        /**
        Css class applied when value was stored but not sent to server (`pk` is empty or `send = 'never'`).  
        You may set it to `null` if you work with editables locally and submit them together.  

        @property unsavedclass 
        @type string
        @since 1.4.1        
        @default editable-unsaved
        **/        
        unsavedclass: 'editable-unsaved',
        /**
        If selector is provided, editable will be delegated to the specified targets.  
        Usefull for dynamically generated DOM elements.  
        **Please note**, that delegated targets can't be initialized with `emptytext` and `autotext` options, 
        as they actually become editable only after first click.  
        You should manually set class `editable-click` to these elements.  
        Also, if element originally empty you should add class `editable-empty`, set `data-value=""` and write emptytext into element:

        @property selector 
        @type string
        @since 1.4.1        
        @default null
        @example
        <div id="user">
          <!-- empty -->
          <a href="#" data-name="username" data-type="text" class="editable-click editable-empty" data-value="" title="Username">Empty</a>
          <!-- non-empty -->
          <a href="#" data-name="group" data-type="select" data-source="/groups" data-value="1" class="editable-click" title="Group">Operator</a>
        </div>     
        
        <script>
        $('#user').editable({
            selector: 'a',
            url: '/post',
            pk: 1
        });
        </script>
        **/         
        selector: null,
        /**
        Color used to highlight element after update. Implemented via CSS3 transition, works in modern browsers.
        
        @property highlight 
        @type string|boolean
        @since 1.4.5        
        @default #FFFF80 
        **/
        highlight: '#FFFF80'
    };
    
}(window.jQuery));

/**
AbstractInput - base class for all editable inputs.
It defines interface to be implemented by any input type.
To create your own input you can inherit from this class.

@class abstractinput
**/
(function ($) {
    "use strict";

    //types
    $.fn.editabletypes = {};

    var AbstractInput = function () { };

    AbstractInput.prototype = {
       /**
        Initializes input

        @method init() 
        **/
       init: function(type, options, defaults) {
           this.type = type;
           this.options = $.extend({}, defaults, options);
       },

       /*
       this method called before render to init $tpl that is inserted in DOM
       */
       prerender: function() {
           this.$tpl = $(this.options.tpl); //whole tpl as jquery object    
           this.$input = this.$tpl;         //control itself, can be changed in render method
           this.$clear = null;              //clear button
           this.error = null;               //error message, if input cannot be rendered           
       },
       
       /**
        Renders input from tpl. Can return jQuery deferred object.
        Can be overwritten in child objects

        @method render()
       **/
       render: function() {

       }, 

       /**
        Sets element's html by value. 

        @method value2html(value, element)
        @param {mixed} value
        @param {DOMElement} element
       **/
       value2html: function(value, element) {
           $(element)[this.options.escape ? 'text' : 'html']($.trim(value));
       },

       /**
        Converts element's html to value

        @method html2value(html)
        @param {string} html
        @returns {mixed}
       **/
       html2value: function(html) {
           return $('<div>').html(html).text();
       },

       /**
        Converts value to string (for internal compare). For submitting to server used value2submit().

        @method value2str(value) 
        @param {mixed} value
        @returns {string}
       **/
       value2str: function(value) {
           return value;
       }, 

       /**
        Converts string received from server into value. Usually from `data-value` attribute.

        @method str2value(str)
        @param {string} str
        @returns {mixed}
       **/
       str2value: function(str) {
           return str;
       }, 
       
       /**
        Converts value for submitting to server. Result can be string or object.

        @method value2submit(value) 
        @param {mixed} value
        @returns {mixed}
       **/
       value2submit: function(value) {
           return value;
       },

       /**
        Sets value of input.

        @method value2input(value) 
        @param {mixed} value
       **/
       value2input: function(value) {
           this.$input.val(value);
       },

       /**
        Returns value of input. Value can be object (e.g. datepicker)

        @method input2value() 
       **/
       input2value: function() { 
           return this.$input.val();
       }, 

       /**
        Activates input. For text it sets focus.

        @method activate() 
       **/
       activate: function() {
           if(this.$input.is(':visible')) {
               this.$input.focus();
           }
       },

       /**
        Creates input.

        @method clear() 
       **/        
       clear: function() {
           this.$input.val(null);
       },

       /**
        method to escape html.
       **/
       escape: function(str) {
           return $('<div>').text(str).html();
       },
       
       /**
        attach handler to automatically submit form when value changed (useful when buttons not shown)
       **/
       autosubmit: function() {
        
       },
       
       /**
       Additional actions when destroying element 
       **/
       destroy: function() {
       },

       // -------- helper functions --------
       setClass: function() {          
           if(this.options.inputclass) {
               this.$input.addClass(this.options.inputclass); 
           } 
       },

       setAttr: function(attr) {
           if (this.options[attr] !== undefined && this.options[attr] !== null) {
               this.$input.attr(attr, this.options[attr]);
           } 
       },
       
       option: function(key, value) {
            this.options[key] = value;
       }
       
    };
        
    AbstractInput.defaults = {  
        /**
        HTML template of input. Normally you should not change it.

        @property tpl 
        @type string
        @default ''
        **/   
        tpl: '',
        /**
        CSS class automatically applied to input
        
        @property inputclass 
        @type string
        @default null
        **/         
        inputclass: null,
        
        /**
        If `true` - html will be escaped in content of element via $.text() method.  
        If `false` - html will not be escaped, $.html() used.  
        When you use own `display` function, this option obviosly has no effect.
        
        @property escape 
        @type boolean
        @since 1.5.0
        @default true
        **/         
        escape: true,
                
        //scope for external methods (e.g. source defined as function)
        //for internal use only
        scope: null,
        
        //need to re-declare showbuttons here to get it's value from common config (passed only options existing in defaults)
        showbuttons: true 
    };
    
    $.extend($.fn.editabletypes, {abstractinput: AbstractInput});
        
}(window.jQuery));

/**
List - abstract class for inputs that have source option loaded from js array or via ajax

@class list
@extends abstractinput
**/
(function ($) {
    "use strict";
    
    var List = function (options) {
       
    };

    $.fn.editableutils.inherit(List, $.fn.editabletypes.abstractinput);

    $.extend(List.prototype, {
        render: function () {
            var deferred = $.Deferred();

            this.error = null;
            this.onSourceReady(function () {
                this.renderList();
                deferred.resolve();
            }, function () {
                this.error = this.options.sourceError;
                deferred.resolve();
            });

            return deferred.promise();
        },

        html2value: function (html) {
            return null; //can't set value by text
        },
        
        value2html: function (value, element, display, response) {
            var deferred = $.Deferred(),
                success = function () {
                    if(typeof display === 'function') {
                        //custom display method
                        display.call(element, value, this.sourceData, response); 
                    } else {
                        this.value2htmlFinal(value, element);
                    }
                    deferred.resolve();
               };
            
            //for null value just call success without loading source
            if(value === null) {
               success.call(this);   
            } else {
               this.onSourceReady(success, function () { deferred.resolve(); });
            }

            return deferred.promise();
        },  

        // ------------- additional functions ------------

        onSourceReady: function (success, error) {
            //run source if it function
            var source;
            if ($.isFunction(this.options.source)) {
                source = this.options.source.call(this.options.scope);
                this.sourceData = null;
                //note: if function returns the same source as URL - sourceData will be taken from cahce and no extra request performed
            } else {
                source = this.options.source;
            }            
            
            //if allready loaded just call success
            if(this.options.sourceCache && $.isArray(this.sourceData)) {
                success.call(this);
                return; 
            }

            //try parse json in single quotes (for double quotes jquery does automatically)
            try {
                source = $.fn.editableutils.tryParseJson(source, false);
            } catch (e) {
                error.call(this);
                return;
            }

            //loading from url
            if (typeof source === 'string') {
                //try to get sourceData from cache
                if(this.options.sourceCache) {
                    var cacheID = source,
                    cache;

                    if (!$(document).data(cacheID)) {
                        $(document).data(cacheID, {});
                    }
                    cache = $(document).data(cacheID);

                    //check for cached data
                    if (cache.loading === false && cache.sourceData) { //take source from cache
                        this.sourceData = cache.sourceData;
                        this.doPrepend();
                        success.call(this);
                        return;
                    } else if (cache.loading === true) { //cache is loading, put callback in stack to be called later
                        cache.callbacks.push($.proxy(function () {
                            this.sourceData = cache.sourceData;
                            this.doPrepend();
                            success.call(this);
                        }, this));

                        //also collecting error callbacks
                        cache.err_callbacks.push($.proxy(error, this));
                        return;
                    } else { //no cache yet, activate it
                        cache.loading = true;
                        cache.callbacks = [];
                        cache.err_callbacks = [];
                    }
                }
                
                //ajaxOptions for source. Can be overwritten bt options.sourceOptions
                var ajaxOptions = $.extend({
                    url: source,
                    type: 'get',
                    cache: false,
                    dataType: 'json',
                    success: $.proxy(function (data) {
                        if(cache) {
                            cache.loading = false;
                        }
                        this.sourceData = this.makeArray(data);
                        if($.isArray(this.sourceData)) {
                            if(cache) {
                                //store result in cache
                                cache.sourceData = this.sourceData;
                                //run success callbacks for other fields waiting for this source
                                $.each(cache.callbacks, function () { this.call(); }); 
                            }
                            this.doPrepend();
                            success.call(this);
                        } else {
                            error.call(this);
                            if(cache) {
                                //run error callbacks for other fields waiting for this source
                                $.each(cache.err_callbacks, function () { this.call(); }); 
                            }
                        }
                    }, this),
                    error: $.proxy(function () {
                        error.call(this);
                        if(cache) {
                             cache.loading = false;
                             //run error callbacks for other fields
                             $.each(cache.err_callbacks, function () { this.call(); }); 
                        }
                    }, this)
                }, this.options.sourceOptions);
                
                //loading sourceData from server
                $.ajax(ajaxOptions);
                
            } else { //options as json/array
                this.sourceData = this.makeArray(source);
                    
                if($.isArray(this.sourceData)) {
                    this.doPrepend();
                    success.call(this);   
                } else {
                    error.call(this);
                }
            }
        },

        doPrepend: function () {
            if(this.options.prepend === null || this.options.prepend === undefined) {
                return;  
            }
            
            if(!$.isArray(this.prependData)) {
                //run prepend if it is function (once)
                if ($.isFunction(this.options.prepend)) {
                    this.options.prepend = this.options.prepend.call(this.options.scope);
                }
              
                //try parse json in single quotes
                this.options.prepend = $.fn.editableutils.tryParseJson(this.options.prepend, true);
                
                //convert prepend from string to object
                if (typeof this.options.prepend === 'string') {
                    this.options.prepend = {'': this.options.prepend};
                }
                
                this.prependData = this.makeArray(this.options.prepend);
            }

            if($.isArray(this.prependData) && $.isArray(this.sourceData)) {
                this.sourceData = this.prependData.concat(this.sourceData);
            }
        },

        /*
         renders input list
        */
        renderList: function() {
            // this method should be overwritten in child class
        },
       
         /*
         set element's html by value
        */
        value2htmlFinal: function(value, element) {
            // this method should be overwritten in child class
        },        

        /**
        * convert data to array suitable for sourceData, e.g. [{value: 1, text: 'abc'}, {...}]
        */
        makeArray: function(data) {
            var count, obj, result = [], item, iterateItem;
            if(!data || typeof data === 'string') {
                return null; 
            }

            if($.isArray(data)) { //array
                /* 
                   function to iterate inside item of array if item is object.
                   Caclulates count of keys in item and store in obj. 
                */
                iterateItem = function (k, v) {
                    obj = {value: k, text: v};
                    if(count++ >= 2) {
                        return false;// exit from `each` if item has more than one key.
                    }
                };
            
                for(var i = 0; i < data.length; i++) {
                    item = data[i]; 
                    if(typeof item === 'object') {
                        count = 0; //count of keys inside item
                        $.each(item, iterateItem);
                        //case: [{val1: 'text1'}, {val2: 'text2} ...]
                        if(count === 1) { 
                            result.push(obj); 
                            //case: [{value: 1, text: 'text1'}, {value: 2, text: 'text2'}, ...]
                        } else if(count > 1) {
                            //removed check of existance: item.hasOwnProperty('value') && item.hasOwnProperty('text')
                            if(item.children) {
                                item.children = this.makeArray(item.children);   
                            }
                            result.push(item);
                        }
                    } else {
                        //case: ['text1', 'text2' ...]
                        result.push({value: item, text: item}); 
                    }
                }
            } else {  //case: {val1: 'text1', val2: 'text2, ...}
                $.each(data, function (k, v) {
                    result.push({value: k, text: v});
                });  
            }
            return result;
        },
        
        option: function(key, value) {
            this.options[key] = value;
            if(key === 'source') {
                this.sourceData = null;
            }
            if(key === 'prepend') {
                this.prependData = null;
            }            
        }        

    });      

    List.defaults = $.extend({}, $.fn.editabletypes.abstractinput.defaults, {
        /**
        Source data for list.  
        If **array** - it should be in format: `[{value: 1, text: "text1"}, {value: 2, text: "text2"}, ...]`  
        For compability, object format is also supported: `{"1": "text1", "2": "text2" ...}` but it does not guarantee elements order.
        
        If **string** - considered ajax url to load items. In that case results will be cached for fields with the same source and name. See also `sourceCache` option.
          
        If **function**, it should return data in format above (since 1.4.0).
        
        Since 1.4.1 key `children` supported to render OPTGROUP (for **select** input only).  
        `[{text: "group1", children: [{value: 1, text: "text1"}, {value: 2, text: "text2"}]}, ...]` 

		
        @property source 
        @type string | array | object | function
        @default null
        **/         
        source: null, 
        /**
        Data automatically prepended to the beginning of dropdown list.
        
        @property prepend 
        @type string | array | object | function
        @default false
        **/         
        prepend: false,
        /**
        Error message when list cannot be loaded (e.g. ajax error)
        
        @property sourceError 
        @type string
        @default Error when loading list
        **/          
        sourceError: 'Error when loading list',
        /**
        if <code>true</code> and source is **string url** - results will be cached for fields with the same source.    
        Usefull for editable column in grid to prevent extra requests.
        
        @property sourceCache 
        @type boolean
        @default true
        @since 1.2.0
        **/        
        sourceCache: true,
        /**
        Additional ajax options to be used in $.ajax() when loading list from server.
        Useful to send extra parameters (`data` key) or change request method (`type` key).
        
        @property sourceOptions 
        @type object|function
        @default null
        @since 1.5.0
        **/        
        sourceOptions: null
    });

    $.fn.editabletypes.list = List;      

}(window.jQuery));

/**
Text input

@class text
@extends abstractinput
@final
@example
<a href="#" id="username" data-type="text" data-pk="1">awesome</a>
<script>
$(function(){
    $('#username').editable({
        url: '/post',
        title: 'Enter username'
    });
});
</script>
**/
(function ($) {
    "use strict";
    
    var Text = function (options) {
        this.init('text', options, Text.defaults);
    };

    $.fn.editableutils.inherit(Text, $.fn.editabletypes.abstractinput);

    $.extend(Text.prototype, {
        render: function() {
           this.renderClear();
           this.setClass();
           this.setAttr('placeholder');
        },
        
        activate: function() {
            if(this.$input.is(':visible')) {
                this.$input.focus();
                $.fn.editableutils.setCursorPosition(this.$input.get(0), this.$input.val().length);
                if(this.toggleClear) {
                    this.toggleClear();
                }
            }
        },
        
        //render clear button
        renderClear:  function() {
           if (this.options.clear) {
               this.$clear = $('<span class="editable-clear-x"></span>');
               this.$input.after(this.$clear)
                          .css('padding-right', 24)
                          .keyup($.proxy(function(e) {
                              //arrows, enter, tab, etc
                              if(~$.inArray(e.keyCode, [40,38,9,13,27])) {
                                return;
                              }                            

                              clearTimeout(this.t);
                              var that = this;
                              this.t = setTimeout(function() {
                                that.toggleClear(e);
                              }, 100);
                              
                          }, this))
                          .parent().css('position', 'relative');
                          
               this.$clear.click($.proxy(this.clear, this));                       
           }            
        },
        
        postrender: function() {
            /*
            //now `clear` is positioned via css
            if(this.$clear) {
                //can position clear button only here, when form is shown and height can be calculated
//                var h = this.$input.outerHeight(true) || 20,
                var h = this.$clear.parent().height(),
                    delta = (h - this.$clear.height()) / 2;
                    
                //this.$clear.css({bottom: delta, right: delta});
            }
            */ 
        },
        
        //show / hide clear button
        toggleClear: function(e) {
            if(!this.$clear) {
                return;
            }
            
            var len = this.$input.val().length,
                visible = this.$clear.is(':visible');
                 
            if(len && !visible) {
                this.$clear.show();
            } 
            
            if(!len && visible) {
                this.$clear.hide();
            } 
        },
        
        clear: function() {
           this.$clear.hide();
           this.$input.val('').focus();
        }          
    });

    Text.defaults = $.extend({}, $.fn.editabletypes.abstractinput.defaults, {
        /**
        @property tpl 
        @default <input type="text">
        **/         
        tpl: '<input type="text">',
        /**
        Placeholder attribute of input. Shown when input is empty.

        @property placeholder 
        @type string
        @default null
        **/             
        placeholder: null,
        
        /**
        Whether to show `clear` button 
        
        @property clear 
        @type boolean
        @default true        
        **/
        clear: true
    });

    $.fn.editabletypes.text = Text;

}(window.jQuery));

/**
Textarea input

@class textarea
@extends abstractinput
@final
@example
<a href="#" id="comments" data-type="textarea" data-pk="1">awesome comment!</a>
<script>
$(function(){
    $('#comments').editable({
        url: '/post',
        title: 'Enter comments',
        rows: 10
    });
});
</script>
**/
(function ($) {
    "use strict";
    
    var Textarea = function (options) {
        this.init('textarea', options, Textarea.defaults);
    };

    $.fn.editableutils.inherit(Textarea, $.fn.editabletypes.abstractinput);

    $.extend(Textarea.prototype, {
        render: function () {
            this.setClass();
            this.setAttr('placeholder');
            this.setAttr('rows');                        
            
            //ctrl + enter
            this.$input.keydown(function (e) {
                if (e.ctrlKey && e.which === 13) {
                    $(this).closest('form').submit();
                }
            });
        },
        
       //using `white-space: pre-wrap` solves \n  <--> BR conversion very elegant!
       /* 
       value2html: function(value, element) {
            var html = '', lines;
            if(value) {
                lines = value.split("\n");
                for (var i = 0; i < lines.length; i++) {
                    lines[i] = $('<div>').text(lines[i]).html();
                }
                html = lines.join('<br>');
            }
            $(element).html(html);
        },
       
        html2value: function(html) {
            if(!html) {
                return '';
            }

            var regex = new RegExp(String.fromCharCode(10), 'g');
            var lines = html.split(/<br\s*\/?>/i);
            for (var i = 0; i < lines.length; i++) {
                var text = $('<div>').html(lines[i]).text();

                // Remove newline characters (\n) to avoid them being converted by value2html() method
                // thus adding extra <br> tags
                text = text.replace(regex, '');

                lines[i] = text;
            }
            return lines.join("\n");
        },
         */
        activate: function() {
            $.fn.editabletypes.text.prototype.activate.call(this);
        }
    });

    Textarea.defaults = $.extend({}, $.fn.editabletypes.abstractinput.defaults, {
        /**
        @property tpl
        @default <textarea></textarea>
        **/
        tpl:'<textarea></textarea>',
        /**
        @property inputclass
        @default input-large
        **/
        inputclass: 'input-large',
        /**
        Placeholder attribute of input. Shown when input is empty.

        @property placeholder
        @type string
        @default null
        **/
        placeholder: null,
        /**
        Number of rows in textarea

        @property rows
        @type integer
        @default 7
        **/        
        rows: 7        
    });

    $.fn.editabletypes.textarea = Textarea;

}(window.jQuery));

/**
Select (dropdown)

@class select
@extends list
@final
@example
<a href="#" id="status" data-type="select" data-pk="1" data-url="/post" data-title="Select status"></a>
<script>
$(function(){
    $('#status').editable({
        value: 2,    
        source: [
              {value: 1, text: 'Active'},
              {value: 2, text: 'Blocked'},
              {value: 3, text: 'Deleted'}
           ]
    });
});
</script>
**/
(function ($) {
    "use strict";
    
    var Select = function (options) {
        this.init('select', options, Select.defaults);
    };

    $.fn.editableutils.inherit(Select, $.fn.editabletypes.list);

    $.extend(Select.prototype, {
        renderList: function() {
            this.$input.empty();

            var fillItems = function($el, data) {
                var attr;
                if($.isArray(data)) {
                    for(var i=0; i<data.length; i++) {
                        attr = {};
                        if(data[i].children) {
                            attr.label = data[i].text;
                            $el.append(fillItems($('<optgroup>', attr), data[i].children)); 
                        } else {
                            attr.value = data[i].value;
                            if(data[i].disabled) {
                                attr.disabled = true;
                            }
                            $el.append($('<option>', attr).text(data[i].text)); 
                        }
                    }
                }
                return $el;
            };        

            fillItems(this.$input, this.sourceData);
            
            this.setClass();
            
            //enter submit
            this.$input.on('keydown.editable', function (e) {
                if (e.which === 13) {
                    $(this).closest('form').submit();
                }
            });            
        },
       
        value2htmlFinal: function(value, element) {
            var text = '', 
                items = $.fn.editableutils.itemsByValue(value, this.sourceData);
                
            if(items.length) {
                text = items[0].text;
            }
            
            //$(element).text(text);
            $.fn.editabletypes.abstractinput.prototype.value2html.call(this, text, element);
        },
        
        autosubmit: function() {
            this.$input.off('keydown.editable').on('change.editable', function(){
                $(this).closest('form').submit();
            });
        }
    });      

    Select.defaults = $.extend({}, $.fn.editabletypes.list.defaults, {
        /**
        @property tpl 
        @default <select></select>
        **/         
        tpl:'<select></select>'
    });

    $.fn.editabletypes.select = Select;      

}(window.jQuery));

/**
List of checkboxes. 
Internally value stored as javascript array of values.

@class checklist
@extends list
@final
@example
<a href="#" id="options" data-type="checklist" data-pk="1" data-url="/post" data-title="Select options"></a>
<script>
$(function(){
    $('#options').editable({
        value: [2, 3],    
        source: [
              {value: 1, text: 'option1'},
              {value: 2, text: 'option2'},
              {value: 3, text: 'option3'}
           ]
    });
});
</script>
**/
(function ($) {
    "use strict";
    
    var Checklist = function (options) {
        this.init('checklist', options, Checklist.defaults);
    };

    $.fn.editableutils.inherit(Checklist, $.fn.editabletypes.list);

    $.extend(Checklist.prototype, {
        renderList: function() {
            var $label, $div;
            
            this.$tpl.empty();
            
            if(!$.isArray(this.sourceData)) {
                return;
            }

            for(var i=0; i<this.sourceData.length; i++) {
                $label = $('<label>').append($('<input>', {
                                           type: 'checkbox',
                                           value: this.sourceData[i].value 
                                     }))
                                     .append($('<span>').text(' '+this.sourceData[i].text));
                
                $('<div>').append($label).appendTo(this.$tpl);
            }
            
            this.$input = this.$tpl.find('input[type="checkbox"]');
            this.setClass();
        },
       
       value2str: function(value) {
           return $.isArray(value) ? value.sort().join($.trim(this.options.separator)) : '';
       },  
       
       //parse separated string
        str2value: function(str) {
           var reg, value = null;
           if(typeof str === 'string' && str.length) {
               reg = new RegExp('\\s*'+$.trim(this.options.separator)+'\\s*');
               value = str.split(reg);
           } else if($.isArray(str)) {
               value = str; 
           } else {
               value = [str];
           }
           return value;
        },       
       
       //set checked on required checkboxes
       value2input: function(value) {
            this.$input.prop('checked', false);
            if($.isArray(value) && value.length) {
               this.$input.each(function(i, el) {
                   var $el = $(el);
                   // cannot use $.inArray as it performs strict comparison
                   $.each(value, function(j, val){
                       /*jslint eqeq: true*/
                       if($el.val() == val) {
                       /*jslint eqeq: false*/                           
                           $el.prop('checked', true);
                       }
                   });
               }); 
            }  
        },  
        
       input2value: function() { 
           var checked = [];
           this.$input.filter(':checked').each(function(i, el) {
               checked.push($(el).val());
           });
           return checked;
       },            
          
       //collect text of checked boxes
        value2htmlFinal: function(value, element) {
           var html = [],
               checked = $.fn.editableutils.itemsByValue(value, this.sourceData),
               escape = this.options.escape;
               
           if(checked.length) {
               $.each(checked, function(i, v) {
                   var text = escape ? $.fn.editableutils.escape(v.text) : v.text; 
                   html.push(text); 
               });
               $(element).html(html.join('<br>'));
           } else {
               $(element).empty(); 
           }
        },
        
       activate: function() {
           this.$input.first().focus();
       },
       
       autosubmit: function() {
           this.$input.on('keydown', function(e){
               if (e.which === 13) {
                   $(this).closest('form').submit();
               }
           });
       }
    });      

    Checklist.defaults = $.extend({}, $.fn.editabletypes.list.defaults, {
        /**
        @property tpl 
        @default <div></div>
        **/         
        tpl:'<div class="editable-checklist"></div>',
        
        /**
        @property inputclass 
        @type string
        @default null
        **/         
        inputclass: null,        
        
        /**
        Separator of values when reading from `data-value` attribute

        @property separator 
        @type string
        @default ','
        **/         
        separator: ','
    });

    $.fn.editabletypes.checklist = Checklist;      

}(window.jQuery));

/**
HTML5 input types.
Following types are supported:

* password
* email
* url
* tel
* number
* range
* time

Learn more about html5 inputs:  
http://www.w3.org/wiki/HTML5_form_additions  
To check browser compatibility please see:  
https://developer.mozilla.org/en-US/docs/HTML/Element/Input
            
@class html5types 
@extends text
@final
@since 1.3.0
@example
<a href="#" id="email" data-type="email" data-pk="1">admin@example.com</a>
<script>
$(function(){
    $('#email').editable({
        url: '/post',
        title: 'Enter email'
    });
});
</script>
**/

/**
@property tpl 
@default depends on type
**/ 

/*
Password
*/
(function ($) {
    "use strict";
    
    var Password = function (options) {
        this.init('password', options, Password.defaults);
    };
    $.fn.editableutils.inherit(Password, $.fn.editabletypes.text);
    $.extend(Password.prototype, {
       //do not display password, show '[hidden]' instead
       value2html: function(value, element) {
           if(value) {
               $(element).text('[hidden]');
           } else {
               $(element).empty(); 
           }
       },
       //as password not displayed, should not set value by html
       html2value: function(html) {
           return null;
       }       
    });    
    Password.defaults = $.extend({}, $.fn.editabletypes.text.defaults, {
        tpl: '<input type="password">'
    });
    $.fn.editabletypes.password = Password;
}(window.jQuery));


/*
Email
*/
(function ($) {
    "use strict";
    
    var Email = function (options) {
        this.init('email', options, Email.defaults);
    };
    $.fn.editableutils.inherit(Email, $.fn.editabletypes.text);
    Email.defaults = $.extend({}, $.fn.editabletypes.text.defaults, {
        tpl: '<input type="email">'
    });
    $.fn.editabletypes.email = Email;
}(window.jQuery));


/*
Url
*/
(function ($) {
    "use strict";
    
    var Url = function (options) {
        this.init('url', options, Url.defaults);
    };
    $.fn.editableutils.inherit(Url, $.fn.editabletypes.text);
    Url.defaults = $.extend({}, $.fn.editabletypes.text.defaults, {
        tpl: '<input type="url">'
    });
    $.fn.editabletypes.url = Url;
}(window.jQuery));


/*
Tel
*/
(function ($) {
    "use strict";
    
    var Tel = function (options) {
        this.init('tel', options, Tel.defaults);
    };
    $.fn.editableutils.inherit(Tel, $.fn.editabletypes.text);
    Tel.defaults = $.extend({}, $.fn.editabletypes.text.defaults, {
        tpl: '<input type="tel">'
    });
    $.fn.editabletypes.tel = Tel;
}(window.jQuery));


/*
Number
*/
(function ($) {
    "use strict";
    
    var NumberInput = function (options) {
        this.init('number', options, NumberInput.defaults);
    };
    $.fn.editableutils.inherit(NumberInput, $.fn.editabletypes.text);
    $.extend(NumberInput.prototype, {
         render: function () {
            NumberInput.superclass.render.call(this);
            this.setAttr('min');
            this.setAttr('max');
            this.setAttr('step');
        },
        postrender: function() {
            if(this.$clear) {
                //increase right ffset  for up/down arrows
                this.$clear.css({right: 24});
                /*
                //can position clear button only here, when form is shown and height can be calculated
                var h = this.$input.outerHeight(true) || 20,
                    delta = (h - this.$clear.height()) / 2;
                
                //add 12px to offset right for up/down arrows    
                this.$clear.css({top: delta, right: delta + 16});
                */
            } 
        }        
    });     
    NumberInput.defaults = $.extend({}, $.fn.editabletypes.text.defaults, {
        tpl: '<input type="number">',
        inputclass: 'input-mini',
        min: null,
        max: null,
        step: null
    });
    $.fn.editabletypes.number = NumberInput;
}(window.jQuery));


/*
Range (inherit from number)
*/
(function ($) {
    "use strict";
    
    var Range = function (options) {
        this.init('range', options, Range.defaults);
    };
    $.fn.editableutils.inherit(Range, $.fn.editabletypes.number);
    $.extend(Range.prototype, {
        render: function () {
            this.$input = this.$tpl.filter('input');
            
            this.setClass();
            this.setAttr('min');
            this.setAttr('max');
            this.setAttr('step');           
            
            this.$input.on('input', function(){
                $(this).siblings('output').text($(this).val()); 
            });  
        },
        activate: function() {
            this.$input.focus();
        }         
    });
    Range.defaults = $.extend({}, $.fn.editabletypes.number.defaults, {
        tpl: '<input type="range"><output style="width: 30px; display: inline-block"></output>',
        inputclass: 'input-medium'
    });
    $.fn.editabletypes.range = Range;
}(window.jQuery));

/*
Time
*/
(function ($) {
    "use strict";

    var Time = function (options) {
        this.init('time', options, Time.defaults);
    };
    //inherit from abstract, as inheritance from text gives selection error.
    $.fn.editableutils.inherit(Time, $.fn.editabletypes.abstractinput);
    $.extend(Time.prototype, {
        render: function() {
           this.setClass();
        }        
    });
    Time.defaults = $.extend({}, $.fn.editabletypes.abstractinput.defaults, {
        tpl: '<input type="time">'
    });
    $.fn.editabletypes.time = Time;
}(window.jQuery));

/**
Select2 input. Based on amazing work of Igor Vaynberg https://github.com/ivaynberg/select2.  
Please see [original select2 docs](http://ivaynberg.github.com/select2) for detailed description and options.  
 
You should manually download and include select2 distributive:  

    <link href="select2/select2.css" rel="stylesheet" type="text/css"></link>  
    <script src="select2/select2.js"></script>  
    
To make it **bootstrap-styled** you can use css from [here](https://github.com/t0m/select2-bootstrap-css): 

    <link href="select2-bootstrap.css" rel="stylesheet" type="text/css"></link>    
    
**Note:** currently `autotext` feature does not work for select2 with `ajax` remote source.    
You need initially put both `data-value` and element's text youself:    

    <a href="#" data-type="select2" data-value="1">Text1</a>
    
    
@class select2
@extends abstractinput
@since 1.4.1
@final
@example
<a href="#" id="country" data-type="select2" data-pk="1" data-value="ru" data-url="/post" data-title="Select country"></a>
<script>
$(function(){
    //local source
    $('#country').editable({
        source: [
              {id: 'gb', text: 'Great Britain'},
              {id: 'us', text: 'United States'},
              {id: 'ru', text: 'Russia'}
           ],
        select2: {
           multiple: true
        }
    });
    //remote source (simple)
    $('#country').editable({
        source: '/getCountries',
        select2: {
            placeholder: 'Select Country',
            minimumInputLength: 1
        }
    });
    //remote source (advanced)
    $('#country').editable({
        select2: {
            placeholder: 'Select Country',
            allowClear: true,
            minimumInputLength: 3,
            id: function (item) {
                return item.CountryId;
            },
            ajax: {
                url: '/getCountries',
                dataType: 'json',
                data: function (term, page) {
                    return { query: term };
                },
                results: function (data, page) {
                    return { results: data };
                }
            },
            formatResult: function (item) {
                return item.CountryName;
            },
            formatSelection: function (item) {
                return item.CountryName;
            },
            initSelection: function (element, callback) {
                return $.get('/getCountryById', { query: element.val() }, function (data) {
                    callback(data);
                });
            } 
        }  
    });
});
</script>
**/
(function ($) {
    "use strict";
    
    var Constructor = function (options) {
        this.init('select2', options, Constructor.defaults);

        options.select2 = options.select2 || {};

        this.sourceData = null;
        
        //placeholder
        if(options.placeholder) {
            options.select2.placeholder = options.placeholder;
        }
       
        //if not `tags` mode, use source
        if(!options.select2.tags && options.source) {
            var source = options.source;
            //if source is function, call it (once!)
            if ($.isFunction(options.source)) {
                source = options.source.call(options.scope);
            }               

            if (typeof source === 'string') {
                options.select2.ajax = options.select2.ajax || {};
                //some default ajax params
                if(!options.select2.ajax.data) {
                    options.select2.ajax.data = function(term) {return { query:term };};
                }
                if(!options.select2.ajax.results) {
                    options.select2.ajax.results = function(data) { return {results:data };};
                }
                options.select2.ajax.url = source;
            } else {
                //check format and convert x-editable format to select2 format (if needed)
                this.sourceData = this.convertSource(source);
                options.select2.data = this.sourceData;
            }
        } 

        //overriding objects in config (as by default jQuery extend() is not recursive)
        this.options.select2 = $.extend({}, Constructor.defaults.select2, options.select2);

        //detect whether it is multi-valued
        this.isMultiple = this.options.select2.tags || this.options.select2.multiple;
        this.isRemote = ('ajax' in this.options.select2);

        //store function returning ID of item
        //should be here as used inautotext for local source
        this.idFunc = this.options.select2.id;
        if (typeof(this.idFunc) !== "function") {
            var idKey = this.idFunc || 'id';
            this.idFunc = function (e) { return e[idKey]; };
        }

        //store function that renders text in select2
        this.formatSelection = this.options.select2.formatSelection;
        if (typeof(this.formatSelection) !== "function") {
            this.formatSelection = function (e) { return e.text; };
        }
    };

    $.fn.editableutils.inherit(Constructor, $.fn.editabletypes.abstractinput);

    $.extend(Constructor.prototype, {
        render: function() {
            this.setClass();

            //can not apply select2 here as it calls initSelection 
            //over input that does not have correct value yet.
            //apply select2 only in value2input
            //this.$input.select2(this.options.select2);

            //when data is loaded via ajax, we need to know when it's done to populate listData
            if(this.isRemote) {
                //listen to loaded event to populate data
                this.$input.on('select2-loaded', $.proxy(function(e) {
                    this.sourceData = e.items.results;
                }, this));
            }

            //trigger resize of editableform to re-position container in multi-valued mode
            if(this.isMultiple) {
               this.$input.on('change', function() {
                   $(this).closest('form').parent().triggerHandler('resize');
               });
            }
       },

       value2html: function(value, element) {
           var text = '', data,
               that = this;

           if(this.options.select2.tags) { //in tags mode just assign value
              data = value; 
              //data = $.fn.editableutils.itemsByValue(value, this.options.select2.tags, this.idFunc);
           } else if(this.sourceData) {
              data = $.fn.editableutils.itemsByValue(value, this.sourceData, this.idFunc); 
           } else {
              //can not get list of possible values 
              //(e.g. autotext for select2 with ajax source)
           }

           //data may be array (when multiple values allowed)
           if($.isArray(data)) {
               //collect selected data and show with separator
               text = [];
               $.each(data, function(k, v){
                   text.push(v && typeof v === 'object' ? that.formatSelection(v) : v);
               });
           } else if(data) {
               text = that.formatSelection(data);
           }

           text = $.isArray(text) ? text.join(this.options.viewseparator) : text;

           //$(element).text(text);
           Constructor.superclass.value2html.call(this, text, element); 
       },

       html2value: function(html) {
           return this.options.select2.tags ? this.str2value(html, this.options.viewseparator) : null;
       },

       value2input: function(value) {
           // if value array => join it anyway
           if($.isArray(value)) {
              value = value.join(this.getSeparator());
           }

           //for remote source just set value, text is updated by initSelection
           if(!this.$input.data('select2')) {
               this.$input.val(value);
               this.$input.select2(this.options.select2);
           } else {
               //second argument needed to separate initial change from user's click (for autosubmit)   
               this.$input.val(value).trigger('change', true); 

               //Uncaught Error: cannot call val() if initSelection() is not defined
               //this.$input.select2('val', value);
           }

           // if defined remote source AND no multiple mode AND no user's initSelection provided --> 
           // we should somehow get text for provided id.
           // The solution is to use element's text as text for that id (exclude empty)
           if(this.isRemote && !this.isMultiple && !this.options.select2.initSelection) {
               // customId and customText are methods to extract `id` and `text` from data object
               // we can use this workaround only if user did not define these methods
               // otherwise we cant construct data object
               var customId = this.options.select2.id,
                   customText = this.options.select2.formatSelection;

               if(!customId && !customText) {
                   var $el = $(this.options.scope);
                   if (!$el.data('editable').isEmpty) {
                       var data = {id: value, text: $el.text()};
                       this.$input.select2('data', data); 
                   }
               }
           }
       },
       
       input2value: function() { 
           return this.$input.select2('val');
       },

       str2value: function(str, separator) {
            if(typeof str !== 'string' || !this.isMultiple) {
                return str;
            }

            separator = separator || this.getSeparator();

            var val, i, l;

            if (str === null || str.length < 1) {
                return null;
            }
            val = str.split(separator);
            for (i = 0, l = val.length; i < l; i = i + 1) {
                val[i] = $.trim(val[i]);
            }

            return val;
       },

        autosubmit: function() {
            this.$input.on('change', function(e, isInitial){
                if(!isInitial) {
                  $(this).closest('form').submit();
                }
            });
        },

        getSeparator: function() {
            return this.options.select2.separator || $.fn.select2.defaults.separator;
        },

        /*
        Converts source from x-editable format: {value: 1, text: "1"} to
        select2 format: {id: 1, text: "1"}
        */
        convertSource: function(source) {
            if($.isArray(source) && source.length && source[0].value !== undefined) {
                for(var i = 0; i<source.length; i++) {
                    if(source[i].value !== undefined) {
                        source[i].id = source[i].value;
                        delete source[i].value;
                    }
                }
            }
            return source;
        },
        
        destroy: function() {
            if(this.$input.data('select2')) {
                this.$input.select2('destroy');
            }
        }
        
    });

    Constructor.defaults = $.extend({}, $.fn.editabletypes.abstractinput.defaults, {
        /**
        @property tpl 
        @default <input type="hidden">
        **/
        tpl:'<input type="hidden">',
        /**
        Configuration of select2. [Full list of options](http://ivaynberg.github.com/select2).

        @property select2 
        @type object
        @default null
        **/
        select2: null,
        /**
        Placeholder attribute of select

        @property placeholder 
        @type string
        @default null
        **/
        placeholder: null,
        /**
        Source data for select. It will be assigned to select2 `data` property and kept here just for convenience.
        Please note, that format is different from simple `select` input: use 'id' instead of 'value'.
        E.g. `[{id: 1, text: "text1"}, {id: 2, text: "text2"}, ...]`.

        @property source 
        @type array|string|function
        @default null        
        **/
        source: null,
        /**
        Separator used to display tags.

        @property viewseparator 
        @type string
        @default ', '        
        **/
        viewseparator: ', '
    });

    $.fn.editabletypes.select2 = Constructor;

}(window.jQuery));

/**
* Combodate - 1.0.5
* Dropdown date and time picker.
* Converts text input into dropdowns to pick day, month, year, hour, minute and second.
* Uses momentjs as datetime library http://momentjs.com.
* For i18n include corresponding file from https://github.com/timrwood/moment/tree/master/lang 
*
* Confusion at noon and midnight - see http://en.wikipedia.org/wiki/12-hour_clock#Confusion_at_noon_and_midnight
* In combodate: 
* 12:00 pm --> 12:00 (24-h format, midday)
* 12:00 am --> 00:00 (24-h format, midnight, start of day)
* 
* Differs from momentjs parse rules:
* 00:00 pm, 12:00 pm --> 12:00 (24-h format, day not change)
* 00:00 am, 12:00 am --> 00:00 (24-h format, day not change)
* 
* 
* Author: Vitaliy Potapov
* Project page: http://github.com/vitalets/combodate
* Copyright (c) 2012 Vitaliy Potapov. Released under MIT License.
**/
(function ($) {

    var Combodate = function (element, options) {
        this.$element = $(element);
        if(!this.$element.is('input')) {
            $.error('Combodate should be applied to INPUT element');
            return;
        }
        this.options = $.extend({}, $.fn.combodate.defaults, options, this.$element.data());
        this.init();  
     };

    Combodate.prototype = {
        constructor: Combodate, 
        init: function () {
            this.map = {
                //key   regexp    moment.method
                day:    ['D',    'date'], 
                month:  ['M',    'month'], 
                year:   ['Y',    'year'], 
                hour:   ['[Hh]', 'hours'],
                minute: ['m',    'minutes'], 
                second: ['s',    'seconds'],
                ampm:   ['[Aa]', ''] 
            };
            
            this.$widget = $('<span class="combodate"></span>').html(this.getTemplate());
                      
            this.initCombos();
            
            //update original input on change 
            this.$widget.on('change', 'select', $.proxy(function(e) {
                this.$element.val(this.getValue()).change();
                // update days count if month or year changes
                if (this.options.smartDays) {
                    if ($(e.target).is('.month') || $(e.target).is('.year')) {
                        this.fillCombo('day');
                    }
                }
            }, this));
            
            this.$widget.find('select').css('width', 'auto');
                                       
            // hide original input and insert widget                                       
            this.$element.hide().after(this.$widget);
            
            // set initial value
            this.setValue(this.$element.val() || this.options.value);
        },
        
        /*
         Replace tokens in template with <select> elements 
        */         
        getTemplate: function() {
            var tpl = this.options.template;

            //first pass
            $.each(this.map, function(k, v) {
                v = v[0]; 
                var r = new RegExp(v+'+'),
                    token = v.length > 1 ? v.substring(1, 2) : v;
                    
                tpl = tpl.replace(r, '{'+token+'}');
            });

            //replace spaces with &nbsp;
            tpl = tpl.replace(/ /g, '&nbsp;');

            //second pass
            $.each(this.map, function(k, v) {
                v = v[0];
                var token = v.length > 1 ? v.substring(1, 2) : v;
                    
                tpl = tpl.replace('{'+token+'}', '<select class="'+k+'"></select>');
            });   

            return tpl;
        },
        
        /*
         Initialize combos that presents in template 
        */        
        initCombos: function() {
            for (var k in this.map) {
                var $c = this.$widget.find('.'+k);
                // set properties like this.$day, this.$month etc.
                this['$'+k] = $c.length ? $c : null;
                // fill with items
                this.fillCombo(k);
            }
        },

        /*
         Fill combo with items 
        */        
        fillCombo: function(k) {
            var $combo = this['$'+k];
            if (!$combo) {
                return;
            }

            // define method name to fill items, e.g `fillDays`
            var f = 'fill' + k.charAt(0).toUpperCase() + k.slice(1); 
            var items = this[f]();
            var value = $combo.val();

            $combo.empty();
            for(var i=0; i<items.length; i++) {
                $combo.append('<option value="'+items[i][0]+'">'+items[i][1]+'</option>');
            }

            $combo.val(value);
        },

        /*
         Initialize items of combos. Handles `firstItem` option 
        */
        fillCommon: function(key) {
            var values = [],
                relTime;
                
            if(this.options.firstItem === 'name') {
                //need both to support moment ver < 2 and  >= 2
                relTime = moment.relativeTime || moment.langData()._relativeTime; 
                var header = typeof relTime[key] === 'function' ? relTime[key](1, true, key, false) : relTime[key];
                //take last entry (see momentjs lang files structure) 
                header = header.split(' ').reverse()[0];                
                values.push(['', header]);
            } else if(this.options.firstItem === 'empty') {
                values.push(['', '']);
            }
            return values;
        },  


        /*
        fill day
        */
        fillDay: function() {
            var items = this.fillCommon('d'), name, i,
                twoDigit = this.options.template.indexOf('DD') !== -1,
                daysCount = 31;

            // detect days count (depends on month and year)
            // originally https://github.com/vitalets/combodate/pull/7
            if (this.options.smartDays && this.$month && this.$year) {
                var month = parseInt(this.$month.val(), 10);
                var year = parseInt(this.$year.val(), 10);

                if (!isNaN(month) && !isNaN(year)) {
                    daysCount = moment([year, month]).daysInMonth();
                }
            }

            for (i = 1; i <= daysCount; i++) {
                name = twoDigit ? this.leadZero(i) : i;
                items.push([i, name]);
            }
            return items;        
        },
        
        /*
        fill month
        */
        fillMonth: function() {
            var items = this.fillCommon('M'), name, i, 
                longNames = this.options.template.indexOf('MMMM') !== -1,
                shortNames = this.options.template.indexOf('MMM') !== -1,
                twoDigit = this.options.template.indexOf('MM') !== -1;
                
            for(i=0; i<=11; i++) {
                if(longNames) {
                    //see https://github.com/timrwood/momentjs.com/pull/36
                    name = moment().date(1).month(i).format('MMMM');
                } else if(shortNames) {
                    name = moment().date(1).month(i).format('MMM');
                } else if(twoDigit) {
                    name = this.leadZero(i+1);
                } else {
                    name = i+1;
                }
                items.push([i, name]);
            } 
            return items;
        },  
        
        /*
        fill year
        */
        fillYear: function() {
            var items = [], name, i, 
                longNames = this.options.template.indexOf('YYYY') !== -1;
           
            for(i=this.options.maxYear; i>=this.options.minYear; i--) {
                name = longNames ? i : (i+'').substring(2);
                items[this.options.yearDescending ? 'push' : 'unshift']([i, name]);
            }
            
            items = this.fillCommon('y').concat(items);
            
            return items;              
        },    
        
        /*
        fill hour
        */
        fillHour: function() {
            var items = this.fillCommon('h'), name, i,
                h12 = this.options.template.indexOf('h') !== -1,
                h24 = this.options.template.indexOf('H') !== -1,
                twoDigit = this.options.template.toLowerCase().indexOf('hh') !== -1,
                min = h12 ? 1 : 0, 
                max = h12 ? 12 : 23;
                
            for(i=min; i<=max; i++) {
                name = twoDigit ? this.leadZero(i) : i;
                items.push([i, name]);
            } 
            return items;                 
        },    
        
        /*
        fill minute
        */
        fillMinute: function() {
            var items = this.fillCommon('m'), name, i,
                twoDigit = this.options.template.indexOf('mm') !== -1;

            for(i=0; i<=59; i+= this.options.minuteStep) {
                name = twoDigit ? this.leadZero(i) : i;
                items.push([i, name]);
            }    
            return items;              
        },  
        
        /*
        fill second
        */
        fillSecond: function() {
            var items = this.fillCommon('s'), name, i,
                twoDigit = this.options.template.indexOf('ss') !== -1;

            for(i=0; i<=59; i+= this.options.secondStep) {
                name = twoDigit ? this.leadZero(i) : i;
                items.push([i, name]);
            }    
            return items;              
        },  
        
        /*
        fill ampm
        */
        fillAmpm: function() {
            var ampmL = this.options.template.indexOf('a') !== -1,
                ampmU = this.options.template.indexOf('A') !== -1,            
                items = [
                    ['am', ampmL ? 'am' : 'AM'],
                    ['pm', ampmL ? 'pm' : 'PM']
                ];
            return items;                              
        },                                       

        /*
         Returns current date value from combos. 
         If format not specified - `options.format` used.
         If format = `null` - Moment object returned.
        */
        getValue: function(format) {
            var dt, values = {}, 
                that = this,
                notSelected = false;
                
            //getting selected values    
            $.each(this.map, function(k, v) {
                if(k === 'ampm') {
                    return;
                }
                var def = k === 'day' ? 1 : 0;
                  
                values[k] = that['$'+k] ? parseInt(that['$'+k].val(), 10) : def; 
                
                if(isNaN(values[k])) {
                   notSelected = true;
                   return false; 
                }
            });
            
            //if at least one visible combo not selected - return empty string
            if(notSelected) {
               return '';
            }
            
            //convert hours 12h --> 24h 
            if(this.$ampm) {
                //12:00 pm --> 12:00 (24-h format, midday), 12:00 am --> 00:00 (24-h format, midnight, start of day)
                if(values.hour === 12) {
                    values.hour = this.$ampm.val() === 'am' ? 0 : 12;                    
                } else {
                    values.hour = this.$ampm.val() === 'am' ? values.hour : values.hour+12;
                }
            }    
            
            dt = moment([values.year, values.month, values.day, values.hour, values.minute, values.second]);
            
            //highlight invalid date
            this.highlight(dt);
                              
            format = format === undefined ? this.options.format : format;
            if(format === null) {
               return dt.isValid() ? dt : null; 
            } else {
               return dt.isValid() ? dt.format(format) : ''; 
            }           
        },
        
        setValue: function(value) {
            if(!value) {
                return;
            }
            
            var dt = typeof value === 'string' ? moment(value, this.options.format) : moment(value),
                that = this,
                values = {};
            
            //function to find nearest value in select options
            function getNearest($select, value) {
                var delta = {};
                $select.children('option').each(function(i, opt){
                    var optValue = $(opt).attr('value'),
                    distance;

                    if(optValue === '') return;
                    distance = Math.abs(optValue - value); 
                    if(typeof delta.distance === 'undefined' || distance < delta.distance) {
                        delta = {value: optValue, distance: distance};
                    } 
                }); 
                return delta.value;
            }             
            
            if(dt.isValid()) {
                //read values from date object
                $.each(this.map, function(k, v) {
                    if(k === 'ampm') {
                       return; 
                    }
                    values[k] = dt[v[1]]();
                });
               
                if(this.$ampm) {
                    //12:00 pm --> 12:00 (24-h format, midday), 12:00 am --> 00:00 (24-h format, midnight, start of day)
                    if(values.hour >= 12) {
                        values.ampm = 'pm';
                        if(values.hour > 12) {
                            values.hour -= 12;
                        }
                    } else {
                        values.ampm = 'am';
                        if(values.hour === 0) {
                            values.hour = 12;
                        }
                    } 
                }
               
                $.each(values, function(k, v) {
                    //call val() for each existing combo, e.g. this.$hour.val()
                    if(that['$'+k]) {
                       
                        if(k === 'minute' && that.options.minuteStep > 1 && that.options.roundTime) {
                           v = getNearest(that['$'+k], v);
                        }
                       
                        if(k === 'second' && that.options.secondStep > 1 && that.options.roundTime) {
                           v = getNearest(that['$'+k], v);
                        }                       
                       
                        that['$'+k].val(v);
                    }
                });

                // update days count
                if (this.options.smartDays) {
                    this.fillCombo('day');
                }
               
               this.$element.val(dt.format(this.options.format)).change();
            }
        },
        
        /*
         highlight combos if date is invalid
        */
        highlight: function(dt) {
            if(!dt.isValid()) {
                if(this.options.errorClass) {
                    this.$widget.addClass(this.options.errorClass);
                } else {
                    //store original border color
                    if(!this.borderColor) {
                        this.borderColor = this.$widget.find('select').css('border-color'); 
                    }
                    this.$widget.find('select').css('border-color', 'red');
                } 
            } else {
                if(this.options.errorClass) {
                    this.$widget.removeClass(this.options.errorClass);
                } else {
                    this.$widget.find('select').css('border-color', this.borderColor);
                }  
            }
        },
        
        leadZero: function(v) {
            return v <= 9 ? '0' + v : v; 
        },
        
        destroy: function() {
            this.$widget.remove();
            this.$element.removeData('combodate').show();
        }
        
        //todo: clear method        
    };

    $.fn.combodate = function ( option ) {
        var d, args = Array.apply(null, arguments);
        args.shift();

        //getValue returns date as string / object (not jQuery object)
        if(option === 'getValue' && this.length && (d = this.eq(0).data('combodate'))) {
          return d.getValue.apply(d, args);
        }        
        
        return this.each(function () {
            var $this = $(this),
            data = $this.data('combodate'),
            options = typeof option == 'object' && option;
            if (!data) {
                $this.data('combodate', (data = new Combodate(this, options)));
            }
            if (typeof option == 'string' && typeof data[option] == 'function') {
                data[option].apply(data, args);
            }
        });
    };  
    
    $.fn.combodate.defaults = {
         //in this format value stored in original input
        format: 'DD-MM-YYYY HH:mm',      
        //in this format items in dropdowns are displayed
        template: 'D / MMM / YYYY   H : mm',
        //initial value, can be `new Date()`    
        value: null,                       
        minYear: 1970,
        maxYear: 2015,
        yearDescending: true,
        minuteStep: 5,
        secondStep: 1,
        firstItem: 'empty', //'name', 'empty', 'none'
        errorClass: null,
        roundTime: true, // whether to round minutes and seconds if step > 1
        smartDays: false // whether days in combo depend on selected month: 31, 30, 28
    };

}(window.jQuery));
/**
Combodate input - dropdown date and time picker.    
Based on [combodate](http://vitalets.github.com/combodate) plugin (included). To use it you should manually include [momentjs](http://momentjs.com).

    <script src="js/moment.min.js"></script>
   
Allows to input:

* only date
* only time 
* both date and time  

Please note, that format is taken from momentjs and **not compatible** with bootstrap-datepicker / jquery UI datepicker.  
Internally value stored as `momentjs` object. 

@class combodate
@extends abstractinput
@final
@since 1.4.0
@example
<a href="#" id="dob" data-type="combodate" data-pk="1" data-url="/post" data-value="1984-05-15" data-title="Select date"></a>
<script>
$(function(){
    $('#dob').editable({
        format: 'YYYY-MM-DD',    
        viewformat: 'DD.MM.YYYY',    
        template: 'D / MMMM / YYYY',    
        combodate: {
                minYear: 2000,
                maxYear: 2015,
                minuteStep: 1
           }
        }
    });
});
</script>
**/

/*global moment*/

(function ($) {
    "use strict";
    
    var Constructor = function (options) {
        this.init('combodate', options, Constructor.defaults);
        
        //by default viewformat equals to format
        if(!this.options.viewformat) {
            this.options.viewformat = this.options.format;
        }        
        
        //try parse combodate config defined as json string in data-combodate
        options.combodate = $.fn.editableutils.tryParseJson(options.combodate, true);

        //overriding combodate config (as by default jQuery extend() is not recursive)
        this.options.combodate = $.extend({}, Constructor.defaults.combodate, options.combodate, {
            format: this.options.format,
            template: this.options.template
        });
    };

    $.fn.editableutils.inherit(Constructor, $.fn.editabletypes.abstractinput);    
    
    $.extend(Constructor.prototype, {
        render: function () {
            this.$input.combodate(this.options.combodate);
                    
            if($.fn.editableform.engine === 'bs3') {
                this.$input.siblings().find('select').addClass('form-control');
            }
            
            if(this.options.inputclass) {
                this.$input.siblings().find('select').addClass(this.options.inputclass);
            }            
            //"clear" link
            /*
            if(this.options.clear) {
                this.$clear = $('<a href="#"></a>').html(this.options.clear).click($.proxy(function(e){
                    e.preventDefault();
                    e.stopPropagation();
                    this.clear();
                }, this));
                
                this.$tpl.parent().append($('<div class="editable-clear">').append(this.$clear));  
            } 
            */               
        },
        
        value2html: function(value, element) {
            var text = value ? value.format(this.options.viewformat) : '';
            //$(element).text(text);
            Constructor.superclass.value2html.call(this, text, element);  
        },

        html2value: function(html) {
            return html ? moment(html, this.options.viewformat) : null;
        },   
        
        value2str: function(value) {
            return value ? value.format(this.options.format) : '';
       }, 
       
       str2value: function(str) {
           return str ? moment(str, this.options.format) : null;
       }, 
       
       value2submit: function(value) {
           return this.value2str(value);
       },                    

       value2input: function(value) {
           this.$input.combodate('setValue', value);
       },
        
       input2value: function() { 
           return this.$input.combodate('getValue', null);
       },       
       
       activate: function() {
           this.$input.siblings('.combodate').find('select').eq(0).focus();
       },
       
       /*
       clear:  function() {
          this.$input.data('datepicker').date = null;
          this.$input.find('.active').removeClass('active');
       },
       */
       
       autosubmit: function() {
           
       }

    });
    
    Constructor.defaults = $.extend({}, $.fn.editabletypes.abstractinput.defaults, {
        /**
        @property tpl 
        @default <input type="text">
        **/         
        tpl:'<input type="text">',
        /**
        @property inputclass 
        @default null
        **/         
        inputclass: null,
        /**
        Format used for sending value to server. Also applied when converting date from <code>data-value</code> attribute.<br>
        See list of tokens in [momentjs docs](http://momentjs.com/docs/#/parsing/string-format)  
        
        @property format 
        @type string
        @default YYYY-MM-DD
        **/         
        format:'YYYY-MM-DD',
        /**
        Format used for displaying date. Also applied when converting date from element's text on init.   
        If not specified equals to `format`.
        
        @property viewformat 
        @type string
        @default null
        **/          
        viewformat: null,        
        /**
        Template used for displaying dropdowns.
        
        @property template 
        @type string
        @default D / MMM / YYYY
        **/          
        template: 'D / MMM / YYYY',  
        /**
        Configuration of combodate.
        Full list of options: http://vitalets.github.com/combodate/#docs
        
        @property combodate 
        @type object
        @default null
        **/
        combodate: null
        
        /*
        (not implemented yet)
        Text shown as clear date button. 
        If <code>false</code> clear button will not be rendered.
        
        @property clear 
        @type boolean|string
        @default 'x clear'         
        */
        //clear: '&times; clear'
    });   

    $.fn.editabletypes.combodate = Constructor;

}(window.jQuery));

/*
Editableform based on Twitter Bootstrap 3
*/
(function ($) {
    "use strict";
    
    //store parent methods
    var pInitInput = $.fn.editableform.Constructor.prototype.initInput;
    
    $.extend($.fn.editableform.Constructor.prototype, {
        initTemplate: function() {
            this.$form = $($.fn.editableform.template); 
            this.$form.find('.control-group').addClass('form-group');
            this.$form.find('.editable-error-block').addClass('help-block');
        },
        initInput: function() {  
            pInitInput.apply(this);

            //for bs3 set default class `input-sm` to standard inputs
            var emptyInputClass = this.input.options.inputclass === null || this.input.options.inputclass === false;
            var defaultClass = 'input-sm';
            
            //bs3 add `form-control` class to standard inputs
            var stdtypes = 'text,select,textarea,password,email,url,tel,number,range,time,typeaheadjs'.split(','); 
            if(~$.inArray(this.input.type, stdtypes)) {
                this.input.$input.addClass('form-control');
                if(emptyInputClass) {
                    this.input.options.inputclass = defaultClass;
                    this.input.$input.addClass(defaultClass);
                }
            }             
        
            //apply bs3 size class also to buttons (to fit size of control)
            var $btn = this.$form.find('.editable-buttons');
            var classes = emptyInputClass ? [defaultClass] : this.input.options.inputclass.split(' ');
            for(var i=0; i<classes.length; i++) {
                // `btn-sm` is default now
                /*
                if(classes[i].toLowerCase() === 'input-sm') { 
                    $btn.find('button').addClass('btn-sm');  
                }
                */
                if(classes[i].toLowerCase() === 'input-lg') {
                    $btn.find('button').removeClass('btn-sm').addClass('btn-lg'); 
                }
            }
        }
    });    
    
    //buttons
    $.fn.editableform.buttons = 
      '<button type="submit" class="btn btn-primary btn-sm editable-submit">'+
        '<i class="fa fa-check"></i>'+
      '</button>'+
      '<button type="button" class="btn btn-default btn-sm editable-cancel">'+
        '<i class="fa fa-times"></i>'+
      '</button>';         
    
    //error classes
    $.fn.editableform.errorGroupClass = 'has-error';
    $.fn.editableform.errorBlockClass = null;  
    //engine
    $.fn.editableform.engine = 'bs3';  
}(window.jQuery));
/**
* Editable Popover3 (for Bootstrap 3) 
* ---------------------
* requires bootstrap-popover.js
*/
(function ($) {
    "use strict";

    //extend methods
    $.extend($.fn.editableContainer.Popup.prototype, {
        containerName: 'popover',
        containerDataName: 'bs.popover',
        innerCss: '.popover-content',
        defaults: $.fn.popover.Constructor.DEFAULTS,

        initContainer: function(){
            $.extend(this.containerOptions, {
                trigger: 'manual',
                selector: false,
                content: ' ',
                template: this.defaults.template
            });
            
            //as template property is used in inputs, hide it from popover
            var t;
            if(this.$element.data('template')) {
               t = this.$element.data('template');
               this.$element.removeData('template');  
            } 
            
            this.call(this.containerOptions);
            
            if(t) {
               //restore data('template')
               this.$element.data('template', t); 
            }
        }, 
        
        /* show */
        innerShow: function () {
            this.call('show');                
        },  
        
        /* hide */
        innerHide: function () {
            this.call('hide');       
        }, 
        
        /* destroy */
        innerDestroy: function() {
            this.call('destroy');
        },                               
        
        setContainerOption: function(key, value) {
            this.container().options[key] = value; 
        },               

        /**
        * move popover to new position. This function mainly copied from bootstrap-popover.
        */
        /*jshint laxcomma: true, eqeqeq: false*/
        setPosition: function () { 

            (function() {
            /*    
                var $tip = this.tip()
                , inside
                , pos
                , actualWidth
                , actualHeight
                , placement
                , tp
                , tpt
                , tpb
                , tpl
                , tpr;

                placement = typeof this.options.placement === 'function' ?
                this.options.placement.call(this, $tip[0], this.$element[0]) :
                this.options.placement;

                inside = /in/.test(placement);
               
                $tip
              //  .detach()
              //vitalets: remove any placement class because otherwise they dont influence on re-positioning of visible popover
                .removeClass('top right bottom left')
                .css({ top: 0, left: 0, display: 'block' });
              //  .insertAfter(this.$element);
               
                pos = this.getPosition(inside);

                actualWidth = $tip[0].offsetWidth;
                actualHeight = $tip[0].offsetHeight;

                placement = inside ? placement.split(' ')[1] : placement;

                tpb = {top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2};
                tpt = {top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2};
                tpl = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth};
                tpr = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width};

                switch (placement) {
                    case 'bottom':
                        if ((tpb.top + actualHeight) > ($(window).scrollTop() + $(window).height())) {
                            if (tpt.top > $(window).scrollTop()) {
                                placement = 'top';
                            } else if ((tpr.left + actualWidth) < ($(window).scrollLeft() + $(window).width())) {
                                placement = 'right';
                            } else if (tpl.left > $(window).scrollLeft()) {
                                placement = 'left';
                            } else {
                                placement = 'right';
                            }
                        }
                        break;
                    case 'top':
                        if (tpt.top < $(window).scrollTop()) {
                            if ((tpb.top + actualHeight) < ($(window).scrollTop() + $(window).height())) {
                                placement = 'bottom';
                            } else if ((tpr.left + actualWidth) < ($(window).scrollLeft() + $(window).width())) {
                                placement = 'right';
                            } else if (tpl.left > $(window).scrollLeft()) {
                                placement = 'left';
                            } else {
                                placement = 'right';
                            }
                        }
                        break;
                    case 'left':
                        if (tpl.left < $(window).scrollLeft()) {
                            if ((tpr.left + actualWidth) < ($(window).scrollLeft() + $(window).width())) {
                                placement = 'right';
                            } else if (tpt.top > $(window).scrollTop()) {
                                placement = 'top';
                            } else if (tpt.top > $(window).scrollTop()) {
                                placement = 'bottom';
                            } else {
                                placement = 'right';
                            }
                        }
                        break;
                    case 'right':
                        if ((tpr.left + actualWidth) > ($(window).scrollLeft() + $(window).width())) {
                            if (tpl.left > $(window).scrollLeft()) {
                                placement = 'left';
                            } else if (tpt.top > $(window).scrollTop()) {
                                placement = 'top';
                            } else if (tpt.top > $(window).scrollTop()) {
                                placement = 'bottom';
                            }
                        }
                        break;
                }

                switch (placement) {
                    case 'bottom':
                        tp = tpb;
                        break;
                    case 'top':
                        tp = tpt;
                        break;
                    case 'left':
                        tp = tpl;
                        break;
                    case 'right':
                        tp = tpr;
                        break;
                }

                $tip
                .offset(tp)
                .addClass(placement)
                .addClass('in');
           */
                     
           
            var $tip = this.tip();
            
            var placement = typeof this.options.placement == 'function' ?
                this.options.placement.call(this, $tip[0], this.$element[0]) :
                this.options.placement;            

            var autoToken = /\s?auto?\s?/i;
            var autoPlace = autoToken.test(placement);
            if (autoPlace) {
                placement = placement.replace(autoToken, '') || 'top';
            }
            
            
            var pos = this.getPosition();
            var actualWidth = $tip[0].offsetWidth;
            var actualHeight = $tip[0].offsetHeight;

            if (autoPlace) {
                var $parent = this.$element.parent();

                var orgPlacement = placement;
                var docScroll    = document.documentElement.scrollTop || document.body.scrollTop;
                var parentWidth  = this.options.container == 'body' ? window.innerWidth  : $parent.outerWidth();
                var parentHeight = this.options.container == 'body' ? window.innerHeight : $parent.outerHeight();
                var parentLeft   = this.options.container == 'body' ? 0 : $parent.offset().left;

                placement = placement == 'bottom' && pos.top   + pos.height  + actualHeight - docScroll > parentHeight  ? 'top'    :
                            placement == 'top'    && pos.top   - docScroll   - actualHeight < 0                         ? 'bottom' :
                            placement == 'right'  && pos.right + actualWidth > parentWidth                              ? 'left'   :
                            placement == 'left'   && pos.left  - actualWidth < parentLeft                               ? 'right'  :
                            placement;

                $tip
                  .removeClass(orgPlacement)
                  .addClass(placement);
            }


            var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight);

            this.applyPlacement(calculatedOffset, placement);            
                     
                
            }).call(this.container());
          /*jshint laxcomma: false, eqeqeq: true*/  
        }            
    });

}(window.jQuery));

/* =========================================================
 * bootstrap-datepicker.js
 * http://www.eyecon.ro/bootstrap-datepicker
 * =========================================================
 * Copyright 2012 Stefan Petre
 * Improvements by Andrew Rowls
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * ========================================================= */

(function( $ ) {

	function UTCDate(){
		return new Date(Date.UTC.apply(Date, arguments));
	}
	function UTCToday(){
		var today = new Date();
		return UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
	}

	// Picker object

	var Datepicker = function(element, options) {
		var that = this;

		this._process_options(options);

		this.element = $(element);
		this.isInline = false;
		this.isInput = this.element.is('input');
		this.component = this.element.is('.date') ? this.element.find('.add-on, .btn') : false;
		this.hasInput = this.component && this.element.find('input').length;
		if(this.component && this.component.length === 0)
			this.component = false;

		this.picker = $(DPGlobal.template);
		this._buildEvents();
		this._attachEvents();

		if(this.isInline) {
			this.picker.addClass('datepicker-inline').appendTo(this.element);
		} else {
			this.picker.addClass('datepicker-dropdown dropdown-menu');
		}

		if (this.o.rtl){
			this.picker.addClass('datepicker-rtl');
			this.picker.find('.prev i, .next i')
						.toggleClass('icon-arrow-left icon-arrow-right');
		}


		this.viewMode = this.o.startView;

		if (this.o.calendarWeeks)
			this.picker.find('tfoot th.today')
						.attr('colspan', function(i, val){
							return parseInt(val) + 1;
						});

		this._allow_update = false;

		this.setStartDate(this.o.startDate);
		this.setEndDate(this.o.endDate);
		this.setDaysOfWeekDisabled(this.o.daysOfWeekDisabled);

		this.fillDow();
		this.fillMonths();

		this._allow_update = true;

		this.update();
		this.showMode();

		if(this.isInline) {
			this.show();
		}
	};

	Datepicker.prototype = {
		constructor: Datepicker,

		_process_options: function(opts){
			// Store raw options for reference
			this._o = $.extend({}, this._o, opts);
			// Processed options
			var o = this.o = $.extend({}, this._o);

			// Check if "de-DE" style date is available, if not language should
			// fallback to 2 letter code eg "de"
			var lang = o.language;
			if (!dates[lang]) {
				lang = lang.split('-')[0];
				if (!dates[lang])
					lang = defaults.language;
			}
			o.language = lang;

			switch(o.startView){
				case 2:
				case 'decade':
					o.startView = 2;
					break;
				case 1:
				case 'year':
					o.startView = 1;
					break;
				default:
					o.startView = 0;
			}

			switch (o.minViewMode) {
				case 1:
				case 'months':
					o.minViewMode = 1;
					break;
				case 2:
				case 'years':
					o.minViewMode = 2;
					break;
				default:
					o.minViewMode = 0;
			}

			o.startView = Math.max(o.startView, o.minViewMode);

			o.weekStart %= 7;
			o.weekEnd = ((o.weekStart + 6) % 7);

			var format = DPGlobal.parseFormat(o.format)
			if (o.startDate !== -Infinity) {
				o.startDate = DPGlobal.parseDate(o.startDate, format, o.language);
			}
			if (o.endDate !== Infinity) {
				o.endDate = DPGlobal.parseDate(o.endDate, format, o.language);
			}

			o.daysOfWeekDisabled = o.daysOfWeekDisabled||[];
			if (!$.isArray(o.daysOfWeekDisabled))
				o.daysOfWeekDisabled = o.daysOfWeekDisabled.split(/[,\s]*/);
			o.daysOfWeekDisabled = $.map(o.daysOfWeekDisabled, function (d) {
				return parseInt(d, 10);
			});
		},
		_events: [],
		_secondaryEvents: [],
		_applyEvents: function(evs){
			for (var i=0, el, ev; i<evs.length; i++){
				el = evs[i][0];
				ev = evs[i][1];
				el.on(ev);
			}
		},
		_unapplyEvents: function(evs){
			for (var i=0, el, ev; i<evs.length; i++){
				el = evs[i][0];
				ev = evs[i][1];
				el.off(ev);
			}
		},
		_buildEvents: function(){
			if (this.isInput) { // single input
				this._events = [
					[this.element, {
						focus: $.proxy(this.show, this),
						keyup: $.proxy(this.update, this),
						keydown: $.proxy(this.keydown, this)
					}]
				];
			}
			else if (this.component && this.hasInput){ // component: input + button
				this._events = [
					// For components that are not readonly, allow keyboard nav
					[this.element.find('input'), {
						focus: $.proxy(this.show, this),
						keyup: $.proxy(this.update, this),
						keydown: $.proxy(this.keydown, this)
					}],
					[this.component, {
						click: $.proxy(this.show, this)
					}]
				];
			}
			else if (this.element.is('div')) {  // inline datepicker
				this.isInline = true;
			}
			else {
				this._events = [
					[this.element, {
						click: $.proxy(this.show, this)
					}]
				];
			}

			this._secondaryEvents = [
				[this.picker, {
					click: $.proxy(this.click, this)
				}],
				[$(window), {
					resize: $.proxy(this.place, this)
				}],
				[$(document), {
					mousedown: $.proxy(function (e) {
						// Clicked outside the datepicker, hide it
						if (!(
							this.element.is(e.target) ||
							this.element.find(e.target).size() ||
							this.picker.is(e.target) ||
							this.picker.find(e.target).size()
						)) {
							this.hide();
						}
					}, this)
				}]
			];
		},
		_attachEvents: function(){
			this._detachEvents();
			this._applyEvents(this._events);
		},
		_detachEvents: function(){
			this._unapplyEvents(this._events);
		},
		_attachSecondaryEvents: function(){
			this._detachSecondaryEvents();
			this._applyEvents(this._secondaryEvents);
		},
		_detachSecondaryEvents: function(){
			this._unapplyEvents(this._secondaryEvents);
		},
		_trigger: function(event, altdate){
			var date = altdate || this.date,
				local_date = new Date(date.getTime() + (date.getTimezoneOffset()*60000));

			this.element.trigger({
				type: event,
				date: local_date,
				format: $.proxy(function(altformat){
					var format = altformat || this.o.format;
					return DPGlobal.formatDate(date, format, this.o.language);
				}, this)
			});
		},

		show: function(e) {
			if (!this.isInline)
				this.picker.appendTo('body');
			this.picker.show();
			this.height = this.component ? this.component.outerHeight() : this.element.outerHeight();
			this.place();
			this._attachSecondaryEvents();
			if (e) {
				e.preventDefault();
			}
			this._trigger('show');
		},

		hide: function(e){
			if(this.isInline) return;
			if (!this.picker.is(':visible')) return;
			this.picker.hide().detach();
			this._detachSecondaryEvents();
			this.viewMode = this.o.startView;
			this.showMode();

			if (
				this.o.forceParse &&
				(
					this.isInput && this.element.val() ||
					this.hasInput && this.element.find('input').val()
				)
			)
				this.setValue();
			this._trigger('hide');
		},

		remove: function() {
			this.hide();
			this._detachEvents();
			this._detachSecondaryEvents();
			this.picker.remove();
			delete this.element.data().datepicker;
			if (!this.isInput) {
				delete this.element.data().date;
			}
		},

		getDate: function() {
			var d = this.getUTCDate();
			return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
		},

		getUTCDate: function() {
			return this.date;
		},

		setDate: function(d) {
			this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
		},

		setUTCDate: function(d) {
			this.date = d;
			this.setValue();
		},

		setValue: function() {
			var formatted = this.getFormattedDate();
			if (!this.isInput) {
				if (this.component){
					this.element.find('input').val(formatted);
				}
			} else {
				this.element.val(formatted);
			}
		},

		getFormattedDate: function(format) {
			if (format === undefined)
				format = this.o.format;
			return DPGlobal.formatDate(this.date, format, this.o.language);
		},

		setStartDate: function(startDate){
			this._process_options({startDate: startDate});
			this.update();
			this.updateNavArrows();
		},

		setEndDate: function(endDate){
			this._process_options({endDate: endDate});
			this.update();
			this.updateNavArrows();
		},

		setDaysOfWeekDisabled: function(daysOfWeekDisabled){
			this._process_options({daysOfWeekDisabled: daysOfWeekDisabled});
			this.update();
			this.updateNavArrows();
		},

		place: function(){
						if(this.isInline) return;
			var zIndex = parseInt(this.element.parents().filter(function() {
							return $(this).css('z-index') != 'auto';
						}).first().css('z-index'))+10;
			var offset = this.component ? this.component.parent().offset() : this.element.offset();
			var height = this.component ? this.component.outerHeight(true) : this.element.outerHeight(true);
			this.picker.css({
				top: offset.top + height,
				left: offset.left,
				zIndex: zIndex
			});
		},

		_allow_update: true,
		update: function(){
			if (!this._allow_update) return;

			var date, fromArgs = false;
			if(arguments && arguments.length && (typeof arguments[0] === 'string' || arguments[0] instanceof Date)) {
				date = arguments[0];
				fromArgs = true;
			} else {
				date = this.isInput ? this.element.val() : this.element.data('date') || this.element.find('input').val();
				delete this.element.data().date;
			}

			this.date = DPGlobal.parseDate(date, this.o.format, this.o.language);

			if(fromArgs) this.setValue();

			if (this.date < this.o.startDate) {
				this.viewDate = new Date(this.o.startDate);
			} else if (this.date > this.o.endDate) {
				this.viewDate = new Date(this.o.endDate);
			} else {
				this.viewDate = new Date(this.date);
			}
			this.fill();
		},

		fillDow: function(){
			var dowCnt = this.o.weekStart,
			html = '<tr>';
			if(this.o.calendarWeeks){
				var cell = '<th class="cw">&nbsp;</th>';
				html += cell;
				this.picker.find('.datepicker-days thead tr:first-child').prepend(cell);
			}
			while (dowCnt < this.o.weekStart + 7) {
				html += '<th class="dow">'+dates[this.o.language].daysMin[(dowCnt++)%7]+'</th>';
			}
			html += '</tr>';
			this.picker.find('.datepicker-days thead').append(html);
		},

		fillMonths: function(){
			var html = '',
			i = 0;
			while (i < 12) {
				html += '<span class="month">'+dates[this.o.language].monthsShort[i++]+'</span>';
			}
			this.picker.find('.datepicker-months td').html(html);
		},

		setRange: function(range){
			if (!range || !range.length)
				delete this.range;
			else
				this.range = $.map(range, function(d){ return d.valueOf(); });
			this.fill();
		},

		getClassNames: function(date){
			var cls = [],
				year = this.viewDate.getUTCFullYear(),
				month = this.viewDate.getUTCMonth(),
				currentDate = this.date.valueOf(),
				today = new Date();
			if (date.getUTCFullYear() < year || (date.getUTCFullYear() == year && date.getUTCMonth() < month)) {
				cls.push('old');
			} else if (date.getUTCFullYear() > year || (date.getUTCFullYear() == year && date.getUTCMonth() > month)) {
				cls.push('new');
			}
			// Compare internal UTC date with local today, not UTC today
			if (this.o.todayHighlight &&
				date.getUTCFullYear() == today.getFullYear() &&
				date.getUTCMonth() == today.getMonth() &&
				date.getUTCDate() == today.getDate()) {
				cls.push('today');
			}
			if (currentDate && date.valueOf() == currentDate) {
				cls.push('active');
			}
			if (date.valueOf() < this.o.startDate || date.valueOf() > this.o.endDate ||
				$.inArray(date.getUTCDay(), this.o.daysOfWeekDisabled) !== -1) {
				cls.push('disabled');
			}
			if (this.range){
				if (date > this.range[0] && date < this.range[this.range.length-1]){
					cls.push('range');
				}
				if ($.inArray(date.valueOf(), this.range) != -1){
					cls.push('selected');
				}
			}
			return cls;
		},

		fill: function() {
			var d = new Date(this.viewDate),
				year = d.getUTCFullYear(),
				month = d.getUTCMonth(),
				startYear = this.o.startDate !== -Infinity ? this.o.startDate.getUTCFullYear() : -Infinity,
				startMonth = this.o.startDate !== -Infinity ? this.o.startDate.getUTCMonth() : -Infinity,
				endYear = this.o.endDate !== Infinity ? this.o.endDate.getUTCFullYear() : Infinity,
				endMonth = this.o.endDate !== Infinity ? this.o.endDate.getUTCMonth() : Infinity,
				currentDate = this.date && this.date.valueOf(),
				tooltip;
			this.picker.find('.datepicker-days thead th.datepicker-switch')
						.text(dates[this.o.language].months[month]+' '+year);
			this.picker.find('tfoot th.today')
						.text(dates[this.o.language].today)
						.toggle(this.o.todayBtn !== false);
			this.picker.find('tfoot th.clear')
						.text(dates[this.o.language].clear)
						.toggle(this.o.clearBtn !== false);
			this.updateNavArrows();
			this.fillMonths();
			var prevMonth = UTCDate(year, month-1, 28,0,0,0,0),
				day = DPGlobal.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
			prevMonth.setUTCDate(day);
			prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.o.weekStart + 7)%7);
			var nextMonth = new Date(prevMonth);
			nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
			nextMonth = nextMonth.valueOf();
			var html = [];
			var clsName;
			while(prevMonth.valueOf() < nextMonth) {
				if (prevMonth.getUTCDay() == this.o.weekStart) {
					html.push('<tr>');
					if(this.o.calendarWeeks){
						// ISO 8601: First week contains first thursday.
						// ISO also states week starts on Monday, but we can be more abstract here.
						var
							// Start of current week: based on weekstart/current date
							ws = new Date(+prevMonth + (this.o.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
							// Thursday of this week
							th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
							// First Thursday of year, year from thursday
							yth = new Date(+(yth = UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
							// Calendar week: ms between thursdays, div ms per day, div 7 days
							calWeek =  (th - yth) / 864e5 / 7 + 1;
						html.push('<td class="cw">'+ calWeek +'</td>');

					}
				}
				clsName = this.getClassNames(prevMonth);
				clsName.push('day');

				var before = this.o.beforeShowDay(prevMonth);
				if (before === undefined)
					before = {};
				else if (typeof(before) === 'boolean')
					before = {enabled: before};
				else if (typeof(before) === 'string')
					before = {classes: before};
				if (before.enabled === false)
					clsName.push('disabled');
				if (before.classes)
					clsName = clsName.concat(before.classes.split(/\s+/));
				if (before.tooltip)
					tooltip = before.tooltip;

				clsName = $.unique(clsName);
				html.push('<td class="'+clsName.join(' ')+'"' + (tooltip ? ' title="'+tooltip+'"' : '') + '>'+prevMonth.getUTCDate() + '</td>');
				if (prevMonth.getUTCDay() == this.o.weekEnd) {
					html.push('</tr>');
				}
				prevMonth.setUTCDate(prevMonth.getUTCDate()+1);
			}
			this.picker.find('.datepicker-days tbody').empty().append(html.join(''));
			var currentYear = this.date && this.date.getUTCFullYear();

			var months = this.picker.find('.datepicker-months')
						.find('th:eq(1)')
							.text(year)
							.end()
						.find('span').removeClass('active');
			if (currentYear && currentYear == year) {
				months.eq(this.date.getUTCMonth()).addClass('active');
			}
			if (year < startYear || year > endYear) {
				months.addClass('disabled');
			}
			if (year == startYear) {
				months.slice(0, startMonth).addClass('disabled');
			}
			if (year == endYear) {
				months.slice(endMonth+1).addClass('disabled');
			}

			html = '';
			year = parseInt(year/10, 10) * 10;
			var yearCont = this.picker.find('.datepicker-years')
								.find('th:eq(1)')
									.text(year + '-' + (year + 9))
									.end()
								.find('td');
			year -= 1;
			for (var i = -1; i < 11; i++) {
				html += '<span class="year'+(i == -1 ? ' old' : i == 10 ? ' new' : '')+(currentYear == year ? ' active' : '')+(year < startYear || year > endYear ? ' disabled' : '')+'">'+year+'</span>';
				year += 1;
			}
			yearCont.html(html);
		},

		updateNavArrows: function() {
			if (!this._allow_update) return;

			var d = new Date(this.viewDate),
				year = d.getUTCFullYear(),
				month = d.getUTCMonth();
			switch (this.viewMode) {
				case 0:
					if (this.o.startDate !== -Infinity && year <= this.o.startDate.getUTCFullYear() && month <= this.o.startDate.getUTCMonth()) {
						this.picker.find('.prev').css({visibility: 'hidden'});
					} else {
						this.picker.find('.prev').css({visibility: 'visible'});
					}
					if (this.o.endDate !== Infinity && year >= this.o.endDate.getUTCFullYear() && month >= this.o.endDate.getUTCMonth()) {
						this.picker.find('.next').css({visibility: 'hidden'});
					} else {
						this.picker.find('.next').css({visibility: 'visible'});
					}
					break;
				case 1:
				case 2:
					if (this.o.startDate !== -Infinity && year <= this.o.startDate.getUTCFullYear()) {
						this.picker.find('.prev').css({visibility: 'hidden'});
					} else {
						this.picker.find('.prev').css({visibility: 'visible'});
					}
					if (this.o.endDate !== Infinity && year >= this.o.endDate.getUTCFullYear()) {
						this.picker.find('.next').css({visibility: 'hidden'});
					} else {
						this.picker.find('.next').css({visibility: 'visible'});
					}
					break;
			}
		},

		click: function(e) {
			e.preventDefault();
			var target = $(e.target).closest('span, td, th');
			if (target.length == 1) {
				switch(target[0].nodeName.toLowerCase()) {
					case 'th':
						switch(target[0].className) {
							case 'datepicker-switch':
								this.showMode(1);
								break;
							case 'prev':
							case 'next':
								var dir = DPGlobal.modes[this.viewMode].navStep * (target[0].className == 'prev' ? -1 : 1);
								switch(this.viewMode){
									case 0:
										this.viewDate = this.moveMonth(this.viewDate, dir);
										break;
									case 1:
									case 2:
										this.viewDate = this.moveYear(this.viewDate, dir);
										break;
								}
								this.fill();
								break;
							case 'today':
								var date = new Date();
								date = UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);

								this.showMode(-2);
								var which = this.o.todayBtn == 'linked' ? null : 'view';
								this._setDate(date, which);
								break;
							case 'clear':
								var element;
								if (this.isInput)
									element = this.element;
								else if (this.component)
									element = this.element.find('input');
								if (element)
									element.val("").change();
								this._trigger('changeDate');
								this.update();
								if (this.o.autoclose)
									this.hide();
								break;
						}
						break;
					case 'span':
						if (!target.is('.disabled')) {
							this.viewDate.setUTCDate(1);
							if (target.is('.month')) {
								var day = 1;
								var month = target.parent().find('span').index(target);
								var year = this.viewDate.getUTCFullYear();
								this.viewDate.setUTCMonth(month);
								this._trigger('changeMonth', this.viewDate);
								if (this.o.minViewMode === 1) {
									this._setDate(UTCDate(year, month, day,0,0,0,0));
								}
							} else {
								var year = parseInt(target.text(), 10)||0;
								var day = 1;
								var month = 0;
								this.viewDate.setUTCFullYear(year);
								this._trigger('changeYear', this.viewDate);
								if (this.o.minViewMode === 2) {
									this._setDate(UTCDate(year, month, day,0,0,0,0));
								}
							}
							this.showMode(-1);
							this.fill();
						}
						break;
					case 'td':
						if (target.is('.day') && !target.is('.disabled')){
							var day = parseInt(target.text(), 10)||1;
							var year = this.viewDate.getUTCFullYear(),
								month = this.viewDate.getUTCMonth();
							if (target.is('.old')) {
								if (month === 0) {
									month = 11;
									year -= 1;
								} else {
									month -= 1;
								}
							} else if (target.is('.new')) {
								if (month == 11) {
									month = 0;
									year += 1;
								} else {
									month += 1;
								}
							}
							this._setDate(UTCDate(year, month, day,0,0,0,0));
						}
						break;
				}
			}
		},

		_setDate: function(date, which){
			if (!which || which == 'date')
				this.date = new Date(date);
			if (!which || which  == 'view')
				this.viewDate = new Date(date);
			this.fill();
			this.setValue();
			this._trigger('changeDate');
			var element;
			if (this.isInput) {
				element = this.element;
			} else if (this.component){
				element = this.element.find('input');
			}
			if (element) {
				element.change();
				if (this.o.autoclose && (!which || which == 'date')) {
					this.hide();
				}
			}
		},

		moveMonth: function(date, dir){
			if (!dir) return date;
			var new_date = new Date(date.valueOf()),
				day = new_date.getUTCDate(),
				month = new_date.getUTCMonth(),
				mag = Math.abs(dir),
				new_month, test;
			dir = dir > 0 ? 1 : -1;
			if (mag == 1){
				test = dir == -1
					// If going back one month, make sure month is not current month
					// (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
					? function(){ return new_date.getUTCMonth() == month; }
					// If going forward one month, make sure month is as expected
					// (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
					: function(){ return new_date.getUTCMonth() != new_month; };
				new_month = month + dir;
				new_date.setUTCMonth(new_month);
				// Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
				if (new_month < 0 || new_month > 11)
					new_month = (new_month + 12) % 12;
			} else {
				// For magnitudes >1, move one month at a time...
				for (var i=0; i<mag; i++)
					// ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
					new_date = this.moveMonth(new_date, dir);
				// ...then reset the day, keeping it in the new month
				new_month = new_date.getUTCMonth();
				new_date.setUTCDate(day);
				test = function(){ return new_month != new_date.getUTCMonth(); };
			}
			// Common date-resetting loop -- if date is beyond end of month, make it
			// end of month
			while (test()){
				new_date.setUTCDate(--day);
				new_date.setUTCMonth(new_month);
			}
			return new_date;
		},

		moveYear: function(date, dir){
			return this.moveMonth(date, dir*12);
		},

		dateWithinRange: function(date){
			return date >= this.o.startDate && date <= this.o.endDate;
		},

		keydown: function(e){
			if (this.picker.is(':not(:visible)')){
				if (e.keyCode == 27) // allow escape to hide and re-show picker
					this.show();
				return;
			}
			var dateChanged = false,
				dir, day, month,
				newDate, newViewDate;
			switch(e.keyCode){
				case 27: // escape
					this.hide();
					e.preventDefault();
					break;
				case 37: // left
				case 39: // right
					if (!this.o.keyboardNavigation) break;
					dir = e.keyCode == 37 ? -1 : 1;
					if (e.ctrlKey){
						newDate = this.moveYear(this.date, dir);
						newViewDate = this.moveYear(this.viewDate, dir);
					} else if (e.shiftKey){
						newDate = this.moveMonth(this.date, dir);
						newViewDate = this.moveMonth(this.viewDate, dir);
					} else {
						newDate = new Date(this.date);
						newDate.setUTCDate(this.date.getUTCDate() + dir);
						newViewDate = new Date(this.viewDate);
						newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
					}
					if (this.dateWithinRange(newDate)){
						this.date = newDate;
						this.viewDate = newViewDate;
						this.setValue();
						this.update();
						e.preventDefault();
						dateChanged = true;
					}
					break;
				case 38: // up
				case 40: // down
					if (!this.o.keyboardNavigation) break;
					dir = e.keyCode == 38 ? -1 : 1;
					if (e.ctrlKey){
						newDate = this.moveYear(this.date, dir);
						newViewDate = this.moveYear(this.viewDate, dir);
					} else if (e.shiftKey){
						newDate = this.moveMonth(this.date, dir);
						newViewDate = this.moveMonth(this.viewDate, dir);
					} else {
						newDate = new Date(this.date);
						newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
						newViewDate = new Date(this.viewDate);
						newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
					}
					if (this.dateWithinRange(newDate)){
						this.date = newDate;
						this.viewDate = newViewDate;
						this.setValue();
						this.update();
						e.preventDefault();
						dateChanged = true;
					}
					break;
				case 13: // enter
					this.hide();
					e.preventDefault();
					break;
				case 9: // tab
					this.hide();
					break;
			}
			if (dateChanged){
				this._trigger('changeDate');
				var element;
				if (this.isInput) {
					element = this.element;
				} else if (this.component){
					element = this.element.find('input');
				}
				if (element) {
					element.change();
				}
			}
		},

		showMode: function(dir) {
			if (dir) {
				this.viewMode = Math.max(this.o.minViewMode, Math.min(2, this.viewMode + dir));
			}
			/*
				vitalets: fixing bug of very special conditions:
				jquery 1.7.1 + webkit + show inline datepicker in bootstrap popover.
				Method show() does not set display css correctly and datepicker is not shown.
				Changed to .css('display', 'block') solve the problem.
				See https://github.com/vitalets/x-editable/issues/37

				In jquery 1.7.2+ everything works fine.
			*/
			//this.picker.find('>div').hide().filter('.datepicker-'+DPGlobal.modes[this.viewMode].clsName).show();
			this.picker.find('>div').hide().filter('.datepicker-'+DPGlobal.modes[this.viewMode].clsName).css('display', 'block');
			this.updateNavArrows();
		}
	};

	var DateRangePicker = function(element, options){
		this.element = $(element);
		this.inputs = $.map(options.inputs, function(i){ return i.jquery ? i[0] : i; });
		delete options.inputs;

		$(this.inputs)
			.datepicker(options)
			.bind('changeDate', $.proxy(this.dateUpdated, this));

		this.pickers = $.map(this.inputs, function(i){ return $(i).data('datepicker'); });
		this.updateDates();
	};
	DateRangePicker.prototype = {
		updateDates: function(){
			this.dates = $.map(this.pickers, function(i){ return i.date; });
			this.updateRanges();
		},
		updateRanges: function(){
			var range = $.map(this.dates, function(d){ return d.valueOf(); });
			$.each(this.pickers, function(i, p){
				p.setRange(range);
			});
		},
		dateUpdated: function(e){
			var dp = $(e.target).data('datepicker'),
				new_date = dp.getUTCDate(),
				i = $.inArray(e.target, this.inputs),
				l = this.inputs.length;
			if (i == -1) return;

			if (new_date < this.dates[i]){
				// Date being moved earlier/left
				while (i>=0 && new_date < this.dates[i]){
					this.pickers[i--].setUTCDate(new_date);
				}
			}
			else if (new_date > this.dates[i]){
				// Date being moved later/right
				while (i<l && new_date > this.dates[i]){
					this.pickers[i++].setUTCDate(new_date);
				}
			}
			this.updateDates();
		},
		remove: function(){
			$.map(this.pickers, function(p){ p.remove(); });
			delete this.element.data().datepicker;
		}
	};

	function opts_from_el(el, prefix){
		// Derive options from element data-attrs
		var data = $(el).data(),
			out = {}, inkey,
			replace = new RegExp('^' + prefix.toLowerCase() + '([A-Z])'),
			prefix = new RegExp('^' + prefix.toLowerCase());
		for (var key in data)
			if (prefix.test(key)){
				inkey = key.replace(replace, function(_,a){ return a.toLowerCase(); });
				out[inkey] = data[key];
			}
		return out;
	}

	function opts_from_locale(lang){
		// Derive options from locale plugins
		var out = {};
		// Check if "de-DE" style date is available, if not language should
		// fallback to 2 letter code eg "de"
		if (!dates[lang]) {
			lang = lang.split('-')[0]
			if (!dates[lang])
				return;
		}
		var d = dates[lang];
		$.each(locale_opts, function(i,k){
			if (k in d)
				out[k] = d[k];
		});
		return out;
	}

	var old = $.fn.datepicker;
	var datepicker = $.fn.datepicker = function ( option ) {
		var args = Array.apply(null, arguments);
		args.shift();
		var internal_return,
			this_return;
		this.each(function () {
			var $this = $(this),
				data = $this.data('datepicker'),
				options = typeof option == 'object' && option;
			if (!data) {
				var elopts = opts_from_el(this, 'date'),
					// Preliminary otions
					xopts = $.extend({}, defaults, elopts, options),
					locopts = opts_from_locale(xopts.language),
					// Options priority: js args, data-attrs, locales, defaults
					opts = $.extend({}, defaults, locopts, elopts, options);
				if ($this.is('.input-daterange') || opts.inputs){
					var ropts = {
						inputs: opts.inputs || $this.find('input').toArray()
					};
					$this.data('datepicker', (data = new DateRangePicker(this, $.extend(opts, ropts))));
				}
				else{
					$this.data('datepicker', (data = new Datepicker(this, opts)));
				}
			}
			if (typeof option == 'string' && typeof data[option] == 'function') {
				internal_return = data[option].apply(data, args);
				if (internal_return !== undefined)
					return false;
			}
		});
		if (internal_return !== undefined)
			return internal_return;
		else
			return this;
	};

	var defaults = $.fn.datepicker.defaults = {
		autoclose: false,
		beforeShowDay: $.noop,
		calendarWeeks: false,
		clearBtn: false,
		daysOfWeekDisabled: [],
		endDate: Infinity,
		forceParse: true,
		format: 'mm/dd/yyyy',
		keyboardNavigation: true,
		language: 'en',
		minViewMode: 0,
		rtl: false,
		startDate: -Infinity,
		startView: 0,
		todayBtn: false,
		todayHighlight: false,
		weekStart: 0
	};
	var locale_opts = $.fn.datepicker.locale_opts = [
		'format',
		'rtl',
		'weekStart'
	];
	$.fn.datepicker.Constructor = Datepicker;
	var dates = $.fn.datepicker.dates = {
		en: {
			days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
			daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
			daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
			months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
			monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
			today: "Today",
			clear: "Clear"
		}
	};

	var DPGlobal = {
		modes: [
			{
				clsName: 'days',
				navFnc: 'Month',
				navStep: 1
			},
			{
				clsName: 'months',
				navFnc: 'FullYear',
				navStep: 1
			},
			{
				clsName: 'years',
				navFnc: 'FullYear',
				navStep: 10
		}],
		isLeapYear: function (year) {
			return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0));
		},
		getDaysInMonth: function (year, month) {
			return [31, (DPGlobal.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month];
		},
		validParts: /dd?|DD?|mm?|MM?|yy(?:yy)?/g,
		nonpunctuation: /[^ -\/:-@\[\u3400-\u9fff-`{-~\t\n\r]+/g,
		parseFormat: function(format){
			// IE treats \0 as a string end in inputs (truncating the value),
			// so it's a bad format delimiter, anyway
			var separators = format.replace(this.validParts, '\0').split('\0'),
				parts = format.match(this.validParts);
			if (!separators || !separators.length || !parts || parts.length === 0){
				throw new Error("Invalid date format.");
			}
			return {separators: separators, parts: parts};
		},
		parseDate: function(date, format, language) {
			if (date instanceof Date) return date;
			if (typeof format === 'string')
				format = DPGlobal.parseFormat(format);
			if (/^[\-+]\d+[dmwy]([\s,]+[\-+]\d+[dmwy])*$/.test(date)) {
				var part_re = /([\-+]\d+)([dmwy])/,
					parts = date.match(/([\-+]\d+)([dmwy])/g),
					part, dir;
				date = new Date();
				for (var i=0; i<parts.length; i++) {
					part = part_re.exec(parts[i]);
					dir = parseInt(part[1]);
					switch(part[2]){
						case 'd':
							date.setUTCDate(date.getUTCDate() + dir);
							break;
						case 'm':
							date = Datepicker.prototype.moveMonth.call(Datepicker.prototype, date, dir);
							break;
						case 'w':
							date.setUTCDate(date.getUTCDate() + dir * 7);
							break;
						case 'y':
							date = Datepicker.prototype.moveYear.call(Datepicker.prototype, date, dir);
							break;
					}
				}
				return UTCDate(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), 0, 0, 0);
			}
			var parts = date && date.match(this.nonpunctuation) || [],
				date = new Date(),
				parsed = {},
				setters_order = ['yyyy', 'yy', 'M', 'MM', 'm', 'mm', 'd', 'dd'],
				setters_map = {
					yyyy: function(d,v){ return d.setUTCFullYear(v); },
					yy: function(d,v){ return d.setUTCFullYear(2000+v); },
					m: function(d,v){
						v -= 1;
						while (v<0) v += 12;
						v %= 12;
						d.setUTCMonth(v);
						while (d.getUTCMonth() != v)
							d.setUTCDate(d.getUTCDate()-1);
						return d;
					},
					d: function(d,v){ return d.setUTCDate(v); }
				},
				val, filtered, part;
			setters_map['M'] = setters_map['MM'] = setters_map['mm'] = setters_map['m'];
			setters_map['dd'] = setters_map['d'];
			date = UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
			var fparts = format.parts.slice();
			// Remove noop parts
			if (parts.length != fparts.length) {
				fparts = $(fparts).filter(function(i,p){
					return $.inArray(p, setters_order) !== -1;
				}).toArray();
			}
			// Process remainder
			if (parts.length == fparts.length) {
				for (var i=0, cnt = fparts.length; i < cnt; i++) {
					val = parseInt(parts[i], 10);
					part = fparts[i];
					if (isNaN(val)) {
						switch(part) {
							case 'MM':
								filtered = $(dates[language].months).filter(function(){
									var m = this.slice(0, parts[i].length),
										p = parts[i].slice(0, m.length);
									return m == p;
								});
								val = $.inArray(filtered[0], dates[language].months) + 1;
								break;
							case 'M':
								filtered = $(dates[language].monthsShort).filter(function(){
									var m = this.slice(0, parts[i].length),
										p = parts[i].slice(0, m.length);
									return m == p;
								});
								val = $.inArray(filtered[0], dates[language].monthsShort) + 1;
								break;
						}
					}
					parsed[part] = val;
				}
				for (var i=0, s; i<setters_order.length; i++){
					s = setters_order[i];
					if (s in parsed && !isNaN(parsed[s]))
						setters_map[s](date, parsed[s]);
				}
			}
			return date;
		},
		formatDate: function(date, format, language){
			if (typeof format === 'string')
				format = DPGlobal.parseFormat(format);
			var val = {
				d: date.getUTCDate(),
				D: dates[language].daysShort[date.getUTCDay()],
				DD: dates[language].days[date.getUTCDay()],
				m: date.getUTCMonth() + 1,
				M: dates[language].monthsShort[date.getUTCMonth()],
				MM: dates[language].months[date.getUTCMonth()],
				yy: date.getUTCFullYear().toString().substring(2),
				yyyy: date.getUTCFullYear()
			};
			val.dd = (val.d < 10 ? '0' : '') + val.d;
			val.mm = (val.m < 10 ? '0' : '') + val.m;
			var date = [],
				seps = $.extend([], format.separators);
			for (var i=0, cnt = format.parts.length; i <= cnt; i++) {
				if (seps.length)
					date.push(seps.shift());
				date.push(val[format.parts[i]]);
			}
			return date.join('');
		},
		headTemplate: '<thead>'+
							'<tr>'+
								'<th class="prev"><i class="icon-arrow-left"/></th>'+
								'<th colspan="5" class="datepicker-switch"></th>'+
								'<th class="next"><i class="icon-arrow-right"/></th>'+
							'</tr>'+
						'</thead>',
		contTemplate: '<tbody><tr><td colspan="7"></td></tr></tbody>',
		footTemplate: '<tfoot><tr><th colspan="7" class="today"></th></tr><tr><th colspan="7" class="clear"></th></tr></tfoot>'
	};
	DPGlobal.template = '<div class="datepicker">'+
							'<div class="datepicker-days">'+
								'<table class=" table-condensed">'+
									DPGlobal.headTemplate+
									'<tbody></tbody>'+
									DPGlobal.footTemplate+
								'</table>'+
							'</div>'+
							'<div class="datepicker-months">'+
								'<table class="table-condensed">'+
									DPGlobal.headTemplate+
									DPGlobal.contTemplate+
									DPGlobal.footTemplate+
								'</table>'+
							'</div>'+
							'<div class="datepicker-years">'+
								'<table class="table-condensed">'+
									DPGlobal.headTemplate+
									DPGlobal.contTemplate+
									DPGlobal.footTemplate+
								'</table>'+
							'</div>'+
						'</div>';

	$.fn.datepicker.DPGlobal = DPGlobal;


	/* DATEPICKER NO CONFLICT
	* =================== */

	$.fn.datepicker.noConflict = function(){
		$.fn.datepicker = old;
		return this;
	};


	/* DATEPICKER DATA-API
	* ================== */

	$(document).on(
		'focus.datepicker.data-api click.datepicker.data-api',
		'[data-provide="datepicker"]',
		function(e){
			var $this = $(this);
			if ($this.data('datepicker')) return;
			e.preventDefault();
			// component click requires us to explicitly show it
			datepicker.call($this, 'show');
		}
	);
	$(function(){
		//$('[data-provide="datepicker-inline"]').datepicker();
        //vit: changed to support noConflict()
        datepicker.call($('[data-provide="datepicker-inline"]'));
	});

}( window.jQuery ));

/**
Bootstrap-datepicker.  
Description and examples: https://github.com/eternicode/bootstrap-datepicker.  
For **i18n** you should include js file from here: https://github.com/eternicode/bootstrap-datepicker/tree/master/js/locales
and set `language` option.  
Since 1.4.0 date has different appearance in **popup** and **inline** modes. 

@class date
@extends abstractinput
@final
@example
<a href="#" id="dob" data-type="date" data-pk="1" data-url="/post" data-title="Select date">15/05/1984</a>
<script>
$(function(){
    $('#dob').editable({
        format: 'yyyy-mm-dd',    
        viewformat: 'dd/mm/yyyy',    
        datepicker: {
                weekStart: 1
           }
        }
    });
});
</script>
**/
(function ($) {
    "use strict";
    
    //store bootstrap-datepicker as bdateicker to exclude conflict with jQuery UI one
    $.fn.bdatepicker = $.fn.datepicker.noConflict();
    if(!$.fn.datepicker) { //if there were no other datepickers, keep also original name
        $.fn.datepicker = $.fn.bdatepicker;    
    }    
    
    var Date = function (options) {
        this.init('date', options, Date.defaults);
        this.initPicker(options, Date.defaults);
    };

    $.fn.editableutils.inherit(Date, $.fn.editabletypes.abstractinput);    
    
    $.extend(Date.prototype, {
        initPicker: function(options, defaults) {
            //'format' is set directly from settings or data-* attributes

            //by default viewformat equals to format
            if(!this.options.viewformat) {
                this.options.viewformat = this.options.format;
            }
            
            //try parse datepicker config defined as json string in data-datepicker
            options.datepicker = $.fn.editableutils.tryParseJson(options.datepicker, true);
            
            //overriding datepicker config (as by default jQuery extend() is not recursive)
            //since 1.4 datepicker internally uses viewformat instead of format. Format is for submit only
            this.options.datepicker = $.extend({}, defaults.datepicker, options.datepicker, {
                format: this.options.viewformat
            });
            
            //language
            this.options.datepicker.language = this.options.datepicker.language || 'en'; 

            //store DPglobal
            this.dpg = $.fn.bdatepicker.DPGlobal; 

            //store parsed formats
            this.parsedFormat = this.dpg.parseFormat(this.options.format);
            this.parsedViewFormat = this.dpg.parseFormat(this.options.viewformat);            
        },
        
        render: function () {
            this.$input.bdatepicker(this.options.datepicker);
            
            //"clear" link
            if(this.options.clear) {
                this.$clear = $('<a href="#"></a>').html(this.options.clear).click($.proxy(function(e){
                    e.preventDefault();
                    e.stopPropagation();
                    this.clear();
                }, this));
                
                this.$tpl.parent().append($('<div class="editable-clear">').append(this.$clear));  
            }                
        },
        
        value2html: function(value, element) {
           var text = value ? this.dpg.formatDate(value, this.parsedViewFormat, this.options.datepicker.language) : '';
           Date.superclass.value2html.call(this, text, element); 
        },

        html2value: function(html) {
            return this.parseDate(html, this.parsedViewFormat);
        },   

        value2str: function(value) {
            return value ? this.dpg.formatDate(value, this.parsedFormat, this.options.datepicker.language) : '';
        }, 

        str2value: function(str) {
            return this.parseDate(str, this.parsedFormat);
        }, 

        value2submit: function(value) {
            return this.value2str(value);
        },                    

        value2input: function(value) {
            this.$input.bdatepicker('update', value);
        },

        input2value: function() { 
            return this.$input.data('datepicker').date;
        },       

        activate: function() {
        },

        clear:  function() {
            this.$input.data('datepicker').date = null;
            this.$input.find('.active').removeClass('active');
            if(!this.options.showbuttons) {
                this.$input.closest('form').submit(); 
            }
        },

        autosubmit: function() {
            this.$input.on('mouseup', '.day', function(e){
                if($(e.currentTarget).is('.old') || $(e.currentTarget).is('.new')) {
                    return;
                }
                var $form = $(this).closest('form');
                setTimeout(function() {
                    $form.submit();
                }, 200);
            });
           //changedate is not suitable as it triggered when showing datepicker. see #149
           /*
           this.$input.on('changeDate', function(e){
               var $form = $(this).closest('form');
               setTimeout(function() {
                   $form.submit();
               }, 200);
           });
           */
       },
       
       /*
        For incorrect date bootstrap-datepicker returns current date that is not suitable
        for datefield.
        This function returns null for incorrect date.  
       */
       parseDate: function(str, format) {
           var date = null, formattedBack;
           if(str) {
               date = this.dpg.parseDate(str, format, this.options.datepicker.language);
               if(typeof str === 'string') {
                   formattedBack = this.dpg.formatDate(date, format, this.options.datepicker.language);
                   if(str !== formattedBack) {
                       date = null;
                   }
               }
           }
           return date;
       }

    });

    Date.defaults = $.extend({}, $.fn.editabletypes.abstractinput.defaults, {
        /**
        @property tpl 
        @default <div></div>
        **/         
        tpl:'<div class="editable-date well"></div>',
        /**
        @property inputclass 
        @default null
        **/
        inputclass: null,
        /**
        Format used for sending value to server. Also applied when converting date from <code>data-value</code> attribute.<br>
        Possible tokens are: <code>d, dd, m, mm, yy, yyyy</code>  

        @property format 
        @type string
        @default yyyy-mm-dd
        **/
        format:'yyyy-mm-dd',
        /**
        Format used for displaying date. Also applied when converting date from element's text on init.   
        If not specified equals to <code>format</code>

        @property viewformat 
        @type string
        @default null
        **/
        viewformat: null,
        /**
        Configuration of datepicker.
        Full list of options: http://bootstrap-datepicker.readthedocs.org/en/latest/options.html

        @property datepicker 
        @type object
        @default {
            weekStart: 0,
            startView: 0,
            minViewMode: 0,
            autoclose: false
        }
        **/
        datepicker:{
            weekStart: 0,
            startView: 0,
            minViewMode: 0,
            autoclose: false
        },
        /**
        Text shown as clear date button. 
        If <code>false</code> clear button will not be rendered.

        @property clear 
        @type boolean|string
        @default 'x clear'
        **/
        clear: '&times; clear'
    });

    $.fn.editabletypes.date = Date;

}(window.jQuery));

/**
Bootstrap datefield input - modification for inline mode.
Shows normal <input type="text"> and binds popup datepicker.  
Automatically shown in inline mode.

@class datefield
@extends date

@since 1.4.0
**/
(function ($) {
    "use strict";
    
    var DateField = function (options) {
        this.init('datefield', options, DateField.defaults);
        this.initPicker(options, DateField.defaults);
    };

    $.fn.editableutils.inherit(DateField, $.fn.editabletypes.date);    
    
    $.extend(DateField.prototype, {
        render: function () {
            this.$input = this.$tpl.find('input');
            this.setClass();
            this.setAttr('placeholder');
    
            //bootstrap-datepicker is set `bdateicker` to exclude conflict with jQuery UI one. (in date.js)        
            this.$tpl.bdatepicker(this.options.datepicker);
            
            //need to disable original event handlers
            this.$input.off('focus keydown');
            
            //update value of datepicker
            this.$input.keyup($.proxy(function(){
               this.$tpl.removeData('date');
               this.$tpl.bdatepicker('update');
            }, this));
            
        },   
        
       value2input: function(value) {
           this.$input.val(value ? this.dpg.formatDate(value, this.parsedViewFormat, this.options.datepicker.language) : '');
           this.$tpl.bdatepicker('update');
       },
        
       input2value: function() { 
           return this.html2value(this.$input.val());
       },              
        
       activate: function() {
           $.fn.editabletypes.text.prototype.activate.call(this);
       },
       
       autosubmit: function() {
         //reset autosubmit to empty  
       }
    });
    
    DateField.defaults = $.extend({}, $.fn.editabletypes.date.defaults, {
        /**
        @property tpl 
        **/         
        tpl:'<div class="input-append date"><input type="text"/><span class="add-on"><i class="icon-th"></i></span></div>',
        /**
        @property inputclass 
        @default 'input-small'
        **/         
        inputclass: 'input-small',
        
        /* datepicker config */
        datepicker: {
            weekStart: 0,
            startView: 0,
            minViewMode: 0,
            autoclose: true
        }
    });
    
    $.fn.editabletypes.datefield = DateField;

}(window.jQuery));
/**
Bootstrap-datetimepicker.  
Based on [smalot bootstrap-datetimepicker plugin](https://github.com/smalot/bootstrap-datetimepicker). 
Before usage you should manually include dependent js and css:

    <link href="css/datetimepicker.css" rel="stylesheet" type="text/css"></link> 
    <script src="js/bootstrap-datetimepicker.js"></script>

For **i18n** you should include js file from here: https://github.com/smalot/bootstrap-datetimepicker/tree/master/js/locales
and set `language` option.  

@class datetime
@extends abstractinput
@final
@since 1.4.4
@example
<a href="#" id="last_seen" data-type="datetime" data-pk="1" data-url="/post" title="Select date & time">15/03/2013 12:45</a>
<script>
$(function(){
    $('#last_seen').editable({
        format: 'yyyy-mm-dd hh:ii',    
        viewformat: 'dd/mm/yyyy hh:ii',    
        datetimepicker: {
                weekStart: 1
           }
        }
    });
});
</script>
**/
(function ($) {
    "use strict";

    var DateTime = function (options) {
        this.init('datetime', options, DateTime.defaults);
        this.initPicker(options, DateTime.defaults);
    };

    $.fn.editableutils.inherit(DateTime, $.fn.editabletypes.abstractinput);

    $.extend(DateTime.prototype, {
        initPicker: function(options, defaults) {
            //'format' is set directly from settings or data-* attributes

            //by default viewformat equals to format
            if(!this.options.viewformat) {
                this.options.viewformat = this.options.format;
            }
            
            //try parse datetimepicker config defined as json string in data-datetimepicker
            options.datetimepicker = $.fn.editableutils.tryParseJson(options.datetimepicker, true);

            //overriding datetimepicker config (as by default jQuery extend() is not recursive)
            //since 1.4 datetimepicker internally uses viewformat instead of format. Format is for submit only
            this.options.datetimepicker = $.extend({}, defaults.datetimepicker, options.datetimepicker, {
                format: this.options.viewformat
            });

            //language
            this.options.datetimepicker.language = this.options.datetimepicker.language || 'en'; 

            //store DPglobal
            this.dpg = $.fn.datetimepicker.DPGlobal; 

            //store parsed formats
            this.parsedFormat = this.dpg.parseFormat(this.options.format, this.options.formatType);
            this.parsedViewFormat = this.dpg.parseFormat(this.options.viewformat, this.options.formatType);
        },

        render: function () {
            this.$input.datetimepicker(this.options.datetimepicker);

            //adjust container position when viewMode changes
            //see https://github.com/smalot/bootstrap-datetimepicker/pull/80
            this.$input.on('changeMode', function(e) {
                var f = $(this).closest('form').parent();
                //timeout here, otherwise container changes position before form has new size
                setTimeout(function(){
                    f.triggerHandler('resize');
                }, 0);
            });

            //"clear" link
            if(this.options.clear) {
                this.$clear = $('<a href="#"></a>').html(this.options.clear).click($.proxy(function(e){
                    e.preventDefault();
                    e.stopPropagation();
                    this.clear();
                }, this));

                this.$tpl.parent().append($('<div class="editable-clear">').append(this.$clear));  
            }
        },

        value2html: function(value, element) {
            //formatDate works with UTCDate!
            var text = value ? this.dpg.formatDate(this.toUTC(value), this.parsedViewFormat, this.options.datetimepicker.language, this.options.formatType) : '';
            if(element) {
                DateTime.superclass.value2html.call(this, text, element);
            } else {
                return text;
            }
        },

        html2value: function(html) {
            //parseDate return utc date!
            var value = this.parseDate(html, this.parsedViewFormat); 
            return value ? this.fromUTC(value) : null;
        },

        value2str: function(value) {
            //formatDate works with UTCDate!
            return value ? this.dpg.formatDate(this.toUTC(value), this.parsedFormat, this.options.datetimepicker.language, this.options.formatType) : '';
       },

       str2value: function(str) {
           //parseDate return utc date!
           var value = this.parseDate(str, this.parsedFormat);
           return value ? this.fromUTC(value) : null;
       },

       value2submit: function(value) {
           return this.value2str(value);
       },

       value2input: function(value) {
           if(value) {
             this.$input.data('datetimepicker').setDate(value);
           }
       },

       input2value: function() { 
           //date may be cleared, in that case getDate() triggers error
           var dt = this.$input.data('datetimepicker');
           return dt.date ? dt.getDate() : null;
       },

       activate: function() {
       },

       clear: function() {
          this.$input.data('datetimepicker').date = null;
          this.$input.find('.active').removeClass('active');
          if(!this.options.showbuttons) {
             this.$input.closest('form').submit(); 
          }          
       },

       autosubmit: function() {
           this.$input.on('mouseup', '.minute', function(e){
               var $form = $(this).closest('form');
               setTimeout(function() {
                   $form.submit();
               }, 200);
           });
       },

       //convert date from local to utc
       toUTC: function(value) {
         return value ? new Date(value.valueOf() - value.getTimezoneOffset() * 60000) : value;  
       },

       //convert date from utc to local
       fromUTC: function(value) {
         return value ? new Date(value.valueOf() + value.getTimezoneOffset() * 60000) : value;  
       },

       /*
        For incorrect date bootstrap-datetimepicker returns current date that is not suitable
        for datetimefield.
        This function returns null for incorrect date.  
       */
       parseDate: function(str, format) {
           var date = null, formattedBack;
           if(str) {
               date = this.dpg.parseDate(str, format, this.options.datetimepicker.language, this.options.formatType);
               if(typeof str === 'string') {
                   formattedBack = this.dpg.formatDate(date, format, this.options.datetimepicker.language, this.options.formatType);
                   if(str !== formattedBack) {
                       date = null;
                   } 
               }
           }
           return date;
       }

    });

    DateTime.defaults = $.extend({}, $.fn.editabletypes.abstractinput.defaults, {
        /**
        @property tpl 
        @default <div></div>
        **/         
        tpl:'<div class="editable-date well"></div>',
        /**
        @property inputclass 
        @default null
        **/
        inputclass: null,
        /**
        Format used for sending value to server. Also applied when converting date from <code>data-value</code> attribute.<br>
        Possible tokens are: <code>d, dd, m, mm, yy, yyyy, h, i</code>  
        
        @property format 
        @type string
        @default yyyy-mm-dd hh:ii
        **/         
        format:'yyyy-mm-dd hh:ii',
        formatType:'standard',
        /**
        Format used for displaying date. Also applied when converting date from element's text on init.   
        If not specified equals to <code>format</code>
        
        @property viewformat 
        @type string
        @default null
        **/
        viewformat: null,
        /**
        Configuration of datetimepicker.
        Full list of options: https://github.com/smalot/bootstrap-datetimepicker

        @property datetimepicker 
        @type object
        @default { }
        **/
        datetimepicker:{
            todayHighlight: false,
            autoclose: false
        },
        /**
        Text shown as clear date button. 
        If <code>false</code> clear button will not be rendered.

        @property clear 
        @type boolean|string
        @default 'x clear'
        **/
        clear: '&times; clear'
    });

    $.fn.editabletypes.datetime = DateTime;

}(window.jQuery));
/**
Bootstrap datetimefield input - datetime input for inline mode.
Shows normal <input type="text"> and binds popup datetimepicker.  
Automatically shown in inline mode.

@class datetimefield
@extends datetime

**/
(function ($) {
    "use strict";
    
    var DateTimeField = function (options) {
        this.init('datetimefield', options, DateTimeField.defaults);
        this.initPicker(options, DateTimeField.defaults);
    };

    $.fn.editableutils.inherit(DateTimeField, $.fn.editabletypes.datetime);
    
    $.extend(DateTimeField.prototype, {
        render: function () {
            this.$input = this.$tpl.find('input');
            this.setClass();
            this.setAttr('placeholder');
            
            this.$tpl.datetimepicker(this.options.datetimepicker);
            
            //need to disable original event handlers
            this.$input.off('focus keydown');
            
            //update value of datepicker
            this.$input.keyup($.proxy(function(){
               this.$tpl.removeData('date');
               this.$tpl.datetimepicker('update');
            }, this));
            
        },   
      
       value2input: function(value) {
           this.$input.val(this.value2html(value));
           this.$tpl.datetimepicker('update');
       },
        
       input2value: function() { 
           return this.html2value(this.$input.val());
       },              
        
       activate: function() {
           $.fn.editabletypes.text.prototype.activate.call(this);
       },
       
       autosubmit: function() {
         //reset autosubmit to empty  
       }
    });
    
    DateTimeField.defaults = $.extend({}, $.fn.editabletypes.datetime.defaults, {
        /**
        @property tpl 
        **/         
        tpl:'<div class="input-append date"><input type="text"/><span class="add-on"><i class="icon-th"></i></span></div>',
        /**
        @property inputclass 
        @default 'input-medium'
        **/         
        inputclass: 'input-medium',
        
        /* datetimepicker config */
        datetimepicker:{
            todayHighlight: false,
            autoclose: true
        }
    });
    
    $.fn.editabletypes.datetimefield = DateTimeField;

}(window.jQuery));;
/*!
 * Braintree End-to-End Encryption Library
 * https://www.braintreepayments.com
 * Copyright (c) 2009-2014 Braintree, a division of PayPal, Inc.
 *
 * JSBN
 * Copyright (c) 2005  Tom Wu
 *
 * Both Licensed under the MIT License.
 * http://opensource.org/licenses/MIT
 *
 * ASN.1 JavaScript decoder
 * Copyright (c) 2008-2009 Lapo Luchini <lapo@lapo.it>
 * Licensed under the ISC License.
 * http://opensource.org/licenses/ISC
 */
(function () {
    // ASN.1 JavaScript decoder
    // Copyright (c) 2008-2009 Lapo Luchini <lapo@lapo.it>
    // Permission to use, copy, modify, and/or distribute this software for any
    // purpose with or without fee is hereby granted, provided that the above
    // copyright notice and this permission notice appear in all copies.
    // 
    // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    function Stream(enc, pos) {
        if (enc instanceof Stream) {
            this.enc = enc.enc;
            this.pos = enc.pos;
        }
        else {
            this.enc = enc;
            this.pos = pos;
        }
    }
    Stream.prototype.get = function (pos) {
        if (pos == undefined)
            pos = this.pos++;
        if (pos >= this.enc.length)
            throw 'Requesting byte offset ' + pos + ' on a stream of length ' + this.enc.length;
        return this.enc[pos];
    };
    Stream.prototype.hexDigits = "0123456789ABCDEF";
    Stream.prototype.hexByte = function (b) {
        return this.hexDigits.charAt((b >> 4) & 0xF) + this.hexDigits.charAt(b & 0xF);
    };
    Stream.prototype.hexDump = function (start, end) {
        var s = "";
        for (var i = start; i < end; ++i) {
            s += this.hexByte(this.get(i));
            switch (i & 0xF) {
                case 0x7:
                    s += "  ";
                    break;
                case 0xF:
                    s += "\n";
                    break;
                default: s += " ";
            }
        }
        return s;
    };
    Stream.prototype.parseStringISO = function (start, end) {
        var s = "";
        for (var i = start; i < end; ++i)
            s += String.fromCharCode(this.get(i));
        return s;
    };
    Stream.prototype.parseStringUTF = function (start, end) {
        var s = "", c = 0;
        for (var i = start; i < end;) {
            var c = this.get(i++);
            if (c < 128)
                s += String.fromCharCode(c);
            else if ((c > 191) && (c < 224))
                s += String.fromCharCode(((c & 0x1F) << 6) | (this.get(i++) & 0x3F));
            else
                s += String.fromCharCode(((c & 0x0F) << 12) | ((this.get(i++) & 0x3F) << 6) | (this.get(i++) & 0x3F));
        }
        return s;
    };
    Stream.prototype.reTime = /^((?:1[89]|2\d)?\d\d)(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])([01]\d|2[0-3])(?:([0-5]\d)(?:([0-5]\d)(?:[.,](\d{1,3}))?)?)?(Z|[-+](?:[0]\d|1[0-2])([0-5]\d)?)?$/;
    Stream.prototype.parseTime = function (start, end) {
        var s = this.parseStringISO(start, end);
        var m = this.reTime.exec(s);
        if (!m)
            return "Unrecognized time: " + s;
        s = m[1] + "-" + m[2] + "-" + m[3] + " " + m[4];
        if (m[5]) {
            s += ":" + m[5];
            if (m[6]) {
                s += ":" + m[6];
                if (m[7])
                    s += "." + m[7];
            }
        }
        if (m[8]) {
            s += " UTC";
            if (m[8] != 'Z') {
                s += m[8];
                if (m[9])
                    s += ":" + m[9];
            }
        }
        return s;
    };
    Stream.prototype.parseInteger = function (start, end) {
        //TODO support negative numbers
        var len = end - start;
        if (len > 4) {
            len <<= 3;
            var s = this.get(start);
            if (s == 0)
                len -= 8;
            else
                while (s < 128) {
                    s <<= 1;
                    --len;
                }
            return "(" + len + " bit)";
        }
        var n = 0;
        for (var i = start; i < end; ++i)
            n = (n << 8) | this.get(i);
        return n;
    };
    Stream.prototype.parseBitString = function (start, end) {
        var unusedBit = this.get(start);
        var lenBit = ((end - start - 1) << 3) - unusedBit;
        var s = "(" + lenBit + " bit)";
        if (lenBit <= 20) {
            var skip = unusedBit;
            s += " ";
            for (var i = end - 1; i > start; --i) {
                var b = this.get(i);
                for (var j = skip; j < 8; ++j)
                    s += (b >> j) & 1 ? "1" : "0";
                skip = 0;
            }
        }
        return s;
    };
    Stream.prototype.parseOctetString = function (start, end) {
        var len = end - start;
        var s = "(" + len + " byte) ";
        if (len > 20)
            end = start + 20;
        for (var i = start; i < end; ++i)
            s += this.hexByte(this.get(i));
        if (len > 20)
            s += String.fromCharCode(8230); // ellipsis
        return s;
    };
    Stream.prototype.parseOID = function (start, end) {
        var s, n = 0, bits = 0;
        for (var i = start; i < end; ++i) {
            var v = this.get(i);
            n = (n << 7) | (v & 0x7F);
            bits += 7;
            if (!(v & 0x80)) {
                if (s == undefined)
                    s = parseInt(n / 40) + "." + (n % 40);
                else
                    s += "." + ((bits >= 31) ? "bigint" : n);
                n = bits = 0;
            }
            s += String.fromCharCode();
        }
        return s;
    };
    function ASN1(stream, header, length, tag, sub) {
        this.stream = stream;
        this.header = header;
        this.length = length;
        this.tag = tag;
        this.sub = sub;
    }
    ASN1.prototype.typeName = function () {
        if (this.tag == undefined)
            return "unknown";
        var tagClass = this.tag >> 6;
        var tagConstructed = (this.tag >> 5) & 1;
        var tagNumber = this.tag & 0x1F;
        switch (tagClass) {
            case 0:
                switch (tagNumber) {
                    case 0x00: return "EOC";
                    case 0x01: return "BOOLEAN";
                    case 0x02: return "INTEGER";
                    case 0x03: return "BIT_STRING";
                    case 0x04: return "OCTET_STRING";
                    case 0x05: return "NULL";
                    case 0x06: return "OBJECT_IDENTIFIER";
                    case 0x07: return "ObjectDescriptor";
                    case 0x08: return "EXTERNAL";
                    case 0x09: return "REAL";
                    case 0x0A: return "ENUMERATED";
                    case 0x0B: return "EMBEDDED_PDV";
                    case 0x0C: return "UTF8String";
                    case 0x10: return "SEQUENCE";
                    case 0x11: return "SET";
                    case 0x12: return "NumericString";
                    case 0x13: return "PrintableString"; // ASCII subset
                    case 0x14: return "TeletexString"; // aka T61String
                    case 0x15: return "VideotexString";
                    case 0x16: return "IA5String"; // ASCII
                    case 0x17: return "UTCTime";
                    case 0x18: return "GeneralizedTime";
                    case 0x19: return "GraphicString";
                    case 0x1A: return "VisibleString"; // ASCII subset
                    case 0x1B: return "GeneralString";
                    case 0x1C: return "UniversalString";
                    case 0x1E: return "BMPString";
                    default: return "Universal_" + tagNumber.toString(16);
                }
            case 1: return "Application_" + tagNumber.toString(16);
            case 2: return "[" + tagNumber + "]"; // Context
            case 3: return "Private_" + tagNumber.toString(16);
        }
    };
    ASN1.prototype.content = function () {
        if (this.tag == undefined)
            return null;
        var tagClass = this.tag >> 6;
        if (tagClass != 0)
            return (this.sub == null) ? null : "(" + this.sub.length + ")";
        var tagNumber = this.tag & 0x1F;
        var content = this.posContent();
        var len = Math.abs(this.length);
        switch (tagNumber) {
            case 0x01:
                return (this.stream.get(content) == 0) ? "false" : "true";
            case 0x02:
                return this.stream.parseInteger(content, content + len);
            case 0x03:
                return this.sub ? "(" + this.sub.length + " elem)" :
                    this.stream.parseBitString(content, content + len);
            case 0x04:
                return this.sub ? "(" + this.sub.length + " elem)" :
                    this.stream.parseOctetString(content, content + len);
            //case 0x05: // NULL
            case 0x06:
                return this.stream.parseOID(content, content + len);
            //case 0x07: // ObjectDescriptor
            //case 0x08: // EXTERNAL
            //case 0x09: // REAL
            //case 0x0A: // ENUMERATED
            //case 0x0B: // EMBEDDED_PDV
            case 0x10: // SEQUENCE
            case 0x11:
                return "(" + this.sub.length + " elem)";
            case 0x0C:
                return this.stream.parseStringUTF(content, content + len);
            case 0x12: // NumericString
            case 0x13: // PrintableString
            case 0x14: // TeletexString
            case 0x15: // VideotexString
            case 0x16: // IA5String
            //case 0x19: // GraphicString
            case 0x1A:
                //case 0x1B: // GeneralString
                //case 0x1C: // UniversalString
                //case 0x1E: // BMPString
                return this.stream.parseStringISO(content, content + len);
            case 0x17: // UTCTime
            case 0x18:
                return this.stream.parseTime(content, content + len);
        }
        return null;
    };
    ASN1.prototype.toString = function () {
        return this.typeName() + "@" + this.stream.pos + "[header:" + this.header + ",length:" + this.length + ",sub:" + ((this.sub == null) ? 'null' : this.sub.length) + "]";
    };
    ASN1.prototype.print = function (indent) {
        if (indent == undefined)
            indent = '';
        document.writeln(indent + this);
        if (this.sub != null) {
            indent += '  ';
            for (var i = 0, max = this.sub.length; i < max; ++i)
                this.sub[i].print(indent);
        }
    };
    ASN1.prototype.toPrettyString = function (indent) {
        if (indent == undefined)
            indent = '';
        var s = indent + this.typeName() + " @" + this.stream.pos;
        if (this.length >= 0)
            s += "+";
        s += this.length;
        if (this.tag & 0x20)
            s += " (constructed)";
        else if (((this.tag == 0x03) || (this.tag == 0x04)) && (this.sub != null))
            s += " (encapsulates)";
        s += "\n";
        if (this.sub != null) {
            indent += '  ';
            for (var i = 0, max = this.sub.length; i < max; ++i)
                s += this.sub[i].toPrettyString(indent);
        }
        return s;
    };
    ASN1.prototype.posStart = function () {
        return this.stream.pos;
    };
    ASN1.prototype.posContent = function () {
        return this.stream.pos + this.header;
    };
    ASN1.prototype.posEnd = function () {
        return this.stream.pos + this.header + Math.abs(this.length);
    };
    ASN1.decodeLength = function (stream) {
        var buf = stream.get();
        var len = buf & 0x7F;
        if (len == buf)
            return len;
        if (len > 3)
            throw "Length over 24 bits not supported at position " + (stream.pos - 1);
        if (len == 0)
            return -1; // undefined
        buf = 0;
        for (var i = 0; i < len; ++i)
            buf = (buf << 8) | stream.get();
        return buf;
    };
    ASN1.hasContent = function (tag, len, stream) {
        if (tag & 0x20)
            return true;
        if ((tag < 0x03) || (tag > 0x04))
            return false;
        var p = new Stream(stream);
        if (tag == 0x03)
            p.get(); // BitString unused bits, must be in [0, 7]
        var subTag = p.get();
        if ((subTag >> 6) & 0x01)
            return false;
        try {
            var subLength = ASN1.decodeLength(p);
            return ((p.pos - stream.pos) + subLength == len);
        }
        catch (exception) {
            return false;
        }
    };
    ASN1.decode = function (stream) {
        if (!(stream instanceof Stream))
            stream = new Stream(stream, 0);
        var streamStart = new Stream(stream);
        var tag = stream.get();
        var len = ASN1.decodeLength(stream);
        var header = stream.pos - streamStart.pos;
        var sub = null;
        if (ASN1.hasContent(tag, len, stream)) {
            // it has content, so we decode it
            var start = stream.pos;
            if (tag == 0x03)
                stream.get(); // skip BitString unused bits, must be in [0, 7]
            sub = [];
            if (len >= 0) {
                // definite length
                var end = start + len;
                while (stream.pos < end)
                    sub[sub.length] = ASN1.decode(stream);
                if (stream.pos != end)
                    throw "Content size is not correct for container starting at offset " + start;
            }
            else {
                // undefined length
                try {
                    for (;;) {
                        var s = ASN1.decode(stream);
                        if (s.tag == 0)
                            break;
                        sub[sub.length] = s;
                    }
                    len = start - stream.pos;
                }
                catch (e) {
                    throw "Exception while decoding undefined length content: " + e;
                }
            }
        }
        else
            stream.pos += len; // skip content
        return new ASN1(streamStart, header, len, tag, sub);
    };
    var b64map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    var b64padchar = "=";
    function hex2b64(h) {
        var i;
        var c;
        var ret = "";
        for (i = 0; i + 3 <= h.length; i += 3) {
            c = parseInt(h.substring(i, i + 3), 16);
            ret += b64map.charAt(c >> 6) + b64map.charAt(c & 63);
        }
        if (i + 1 == h.length) {
            c = parseInt(h.substring(i, i + 1), 16);
            ret += b64map.charAt(c << 2);
        }
        else if (i + 2 == h.length) {
            c = parseInt(h.substring(i, i + 2), 16);
            ret += b64map.charAt(c >> 2) + b64map.charAt((c & 3) << 4);
        }
        while ((ret.length & 3) > 0)
            ret += b64padchar;
        return ret;
    }
    // convert a base64 string to hex
    function b64tohex(s) {
        var ret = "";
        var i;
        var k = 0; // b64 state, 0-3
        var slop;
        var v;
        for (i = 0; i < s.length; ++i) {
            if (s.charAt(i) == b64padchar)
                break;
            v = b64map.indexOf(s.charAt(i));
            if (v < 0)
                continue;
            if (k == 0) {
                ret += int2char(v >> 2);
                slop = v & 3;
                k = 1;
            }
            else if (k == 1) {
                ret += int2char((slop << 2) | (v >> 4));
                slop = v & 0xf;
                k = 2;
            }
            else if (k == 2) {
                ret += int2char(slop);
                ret += int2char(v >> 2);
                slop = v & 3;
                k = 3;
            }
            else {
                ret += int2char((slop << 2) | (v >> 4));
                ret += int2char(v & 0xf);
                k = 0;
            }
        }
        if (k == 1)
            ret += int2char(slop << 2);
        return ret;
    }
    // convert a base64 string to a byte/number array
    function b64toBA(s) {
        //piggyback on b64tohex for now, optimize later
        var h = b64tohex(s);
        var i;
        var a = new Array();
        for (i = 0; 2 * i < h.length; ++i) {
            a[i] = parseInt(h.substring(2 * i, 2 * i + 2), 16);
        }
        return a;
    }
    // Copyright (c) 2005  Tom Wu
    // All Rights Reserved.
    // See "LICENSE" for details.
    // Basic JavaScript BN library - subset useful for RSA encryption.
    // Bits per digit
    var dbits;
    // JavaScript engine analysis
    var canary = 0xdeadbeefcafe;
    var j_lm = ((canary & 0xffffff) == 0xefcafe);
    // (public) Constructor
    function BigInteger(a, b, c) {
        if (a != null)
            if ("number" == typeof a)
                this.fromNumber(a, b, c);
            else if (b == null && "string" != typeof a)
                this.fromString(a, 256);
            else
                this.fromString(a, b);
    }
    // return new, unset BigInteger
    function nbi() { return new BigInteger(null); }
    // am: Compute w_j += (x*this_i), propagate carries,
    // c is initial carry, returns final carry.
    // c < 3*dvalue, x < 2*dvalue, this_i < dvalue
    // We need to select the fastest one that works in this environment.
    // am1: use a single mult and divide to get the high bits,
    // max digit bits should be 26 because
    // max internal value = 2*dvalue^2-2*dvalue (< 2^53)
    function am1(i, x, w, j, c, n) {
        while (--n >= 0) {
            var v = x * this[i++] + w[j] + c;
            c = Math.floor(v / 0x4000000);
            w[j++] = v & 0x3ffffff;
        }
        return c;
    }
    // am2 avoids a big mult-and-extract completely.
    // Max digit bits should be <= 30 because we do bitwise ops
    // on values up to 2*hdvalue^2-hdvalue-1 (< 2^31)
    function am2(i, x, w, j, c, n) {
        var xl = x & 0x7fff, xh = x >> 15;
        while (--n >= 0) {
            var l = this[i] & 0x7fff;
            var h = this[i++] >> 15;
            var m = xh * l + h * xl;
            l = xl * l + ((m & 0x7fff) << 15) + w[j] + (c & 0x3fffffff);
            c = (l >>> 30) + (m >>> 15) + xh * h + (c >>> 30);
            w[j++] = l & 0x3fffffff;
        }
        return c;
    }
    // Alternately, set max digit bits to 28 since some
    // browsers slow down when dealing with 32-bit numbers.
    function am3(i, x, w, j, c, n) {
        var xl = x & 0x3fff, xh = x >> 14;
        while (--n >= 0) {
            var l = this[i] & 0x3fff;
            var h = this[i++] >> 14;
            var m = xh * l + h * xl;
            l = xl * l + ((m & 0x3fff) << 14) + w[j] + c;
            c = (l >> 28) + (m >> 14) + xh * h;
            w[j++] = l & 0xfffffff;
        }
        return c;
    }
    if (j_lm && (navigator.appName == "Microsoft Internet Explorer")) {
        BigInteger.prototype.am = am2;
        dbits = 30;
    }
    else if (j_lm && (navigator.appName != "Netscape")) {
        BigInteger.prototype.am = am1;
        dbits = 26;
    }
    else {
        BigInteger.prototype.am = am3;
        dbits = 28;
    }
    BigInteger.prototype.DB = dbits;
    BigInteger.prototype.DM = ((1 << dbits) - 1);
    BigInteger.prototype.DV = (1 << dbits);
    var BI_FP = 52;
    BigInteger.prototype.FV = Math.pow(2, BI_FP);
    BigInteger.prototype.F1 = BI_FP - dbits;
    BigInteger.prototype.F2 = 2 * dbits - BI_FP;
    // Digit conversions
    var BI_RM = "0123456789abcdefghijklmnopqrstuvwxyz";
    var BI_RC = new Array();
    var rr, vv;
    rr = "0".charCodeAt(0);
    for (vv = 0; vv <= 9; ++vv)
        BI_RC[rr++] = vv;
    rr = "a".charCodeAt(0);
    for (vv = 10; vv < 36; ++vv)
        BI_RC[rr++] = vv;
    rr = "A".charCodeAt(0);
    for (vv = 10; vv < 36; ++vv)
        BI_RC[rr++] = vv;
    function int2char(n) { return BI_RM.charAt(n); }
    function intAt(s, i) {
        var c = BI_RC[s.charCodeAt(i)];
        return (c == null) ? -1 : c;
    }
    // (protected) copy this to r
    function bnpCopyTo(r) {
        for (var i = this.t - 1; i >= 0; --i)
            r[i] = this[i];
        r.t = this.t;
        r.s = this.s;
    }
    // (protected) set from integer value x, -DV <= x < DV
    function bnpFromInt(x) {
        this.t = 1;
        this.s = (x < 0) ? -1 : 0;
        if (x > 0)
            this[0] = x;
        else if (x < -1)
            this[0] = x + this.DV;
        else
            this.t = 0;
    }
    // return bigint initialized to value
    function nbv(i) { var r = nbi(); r.fromInt(i); return r; }
    // (protected) set from string and radix
    function bnpFromString(s, b) {
        var k;
        if (b == 16)
            k = 4;
        else if (b == 8)
            k = 3;
        else if (b == 256)
            k = 8; // byte array
        else if (b == 2)
            k = 1;
        else if (b == 32)
            k = 5;
        else if (b == 4)
            k = 2;
        else {
            this.fromRadix(s, b);
            return;
        }
        this.t = 0;
        this.s = 0;
        var i = s.length, mi = false, sh = 0;
        while (--i >= 0) {
            var x = (k == 8) ? s[i] & 0xff : intAt(s, i);
            if (x < 0) {
                if (s.charAt(i) == "-")
                    mi = true;
                continue;
            }
            mi = false;
            if (sh == 0)
                this[this.t++] = x;
            else if (sh + k > this.DB) {
                this[this.t - 1] |= (x & ((1 << (this.DB - sh)) - 1)) << sh;
                this[this.t++] = (x >> (this.DB - sh));
            }
            else
                this[this.t - 1] |= x << sh;
            sh += k;
            if (sh >= this.DB)
                sh -= this.DB;
        }
        if (k == 8 && (s[0] & 0x80) != 0) {
            this.s = -1;
            if (sh > 0)
                this[this.t - 1] |= ((1 << (this.DB - sh)) - 1) << sh;
        }
        this.clamp();
        if (mi)
            BigInteger.ZERO.subTo(this, this);
    }
    // (protected) clamp off excess high words
    function bnpClamp() {
        var c = this.s & this.DM;
        while (this.t > 0 && this[this.t - 1] == c)
            --this.t;
    }
    // (public) return string representation in given radix
    function bnToString(b) {
        if (this.s < 0)
            return "-" + this.negate().toString(b);
        var k;
        if (b == 16)
            k = 4;
        else if (b == 8)
            k = 3;
        else if (b == 2)
            k = 1;
        else if (b == 32)
            k = 5;
        else if (b == 4)
            k = 2;
        else
            return this.toRadix(b);
        var km = (1 << k) - 1, d, m = false, r = "", i = this.t;
        var p = this.DB - (i * this.DB) % k;
        if (i-- > 0) {
            if (p < this.DB && (d = this[i] >> p) > 0) {
                m = true;
                r = int2char(d);
            }
            while (i >= 0) {
                if (p < k) {
                    d = (this[i] & ((1 << p) - 1)) << (k - p);
                    d |= this[--i] >> (p += this.DB - k);
                }
                else {
                    d = (this[i] >> (p -= k)) & km;
                    if (p <= 0) {
                        p += this.DB;
                        --i;
                    }
                }
                if (d > 0)
                    m = true;
                if (m)
                    r += int2char(d);
            }
        }
        return m ? r : "0";
    }
    // (public) -this
    function bnNegate() { var r = nbi(); BigInteger.ZERO.subTo(this, r); return r; }
    // (public) |this|
    function bnAbs() { return (this.s < 0) ? this.negate() : this; }
    // (public) return + if this > a, - if this < a, 0 if equal
    function bnCompareTo(a) {
        var r = this.s - a.s;
        if (r != 0)
            return r;
        var i = this.t;
        r = i - a.t;
        if (r != 0)
            return (this.s < 0) ? -r : r;
        while (--i >= 0)
            if ((r = this[i] - a[i]) != 0)
                return r;
        return 0;
    }
    // returns bit length of the integer x
    function nbits(x) {
        var r = 1, t;
        if ((t = x >>> 16) != 0) {
            x = t;
            r += 16;
        }
        if ((t = x >> 8) != 0) {
            x = t;
            r += 8;
        }
        if ((t = x >> 4) != 0) {
            x = t;
            r += 4;
        }
        if ((t = x >> 2) != 0) {
            x = t;
            r += 2;
        }
        if ((t = x >> 1) != 0) {
            x = t;
            r += 1;
        }
        return r;
    }
    // (public) return the number of bits in "this"
    function bnBitLength() {
        if (this.t <= 0)
            return 0;
        return this.DB * (this.t - 1) + nbits(this[this.t - 1] ^ (this.s & this.DM));
    }
    // (protected) r = this << n*DB
    function bnpDLShiftTo(n, r) {
        var i;
        for (i = this.t - 1; i >= 0; --i)
            r[i + n] = this[i];
        for (i = n - 1; i >= 0; --i)
            r[i] = 0;
        r.t = this.t + n;
        r.s = this.s;
    }
    // (protected) r = this >> n*DB
    function bnpDRShiftTo(n, r) {
        for (var i = n; i < this.t; ++i)
            r[i - n] = this[i];
        r.t = Math.max(this.t - n, 0);
        r.s = this.s;
    }
    // (protected) r = this << n
    function bnpLShiftTo(n, r) {
        var bs = n % this.DB;
        var cbs = this.DB - bs;
        var bm = (1 << cbs) - 1;
        var ds = Math.floor(n / this.DB), c = (this.s << bs) & this.DM, i;
        for (i = this.t - 1; i >= 0; --i) {
            r[i + ds + 1] = (this[i] >> cbs) | c;
            c = (this[i] & bm) << bs;
        }
        for (i = ds - 1; i >= 0; --i)
            r[i] = 0;
        r[ds] = c;
        r.t = this.t + ds + 1;
        r.s = this.s;
        r.clamp();
    }
    // (protected) r = this >> n
    function bnpRShiftTo(n, r) {
        r.s = this.s;
        var ds = Math.floor(n / this.DB);
        if (ds >= this.t) {
            r.t = 0;
            return;
        }
        var bs = n % this.DB;
        var cbs = this.DB - bs;
        var bm = (1 << bs) - 1;
        r[0] = this[ds] >> bs;
        for (var i = ds + 1; i < this.t; ++i) {
            r[i - ds - 1] |= (this[i] & bm) << cbs;
            r[i - ds] = this[i] >> bs;
        }
        if (bs > 0)
            r[this.t - ds - 1] |= (this.s & bm) << cbs;
        r.t = this.t - ds;
        r.clamp();
    }
    // (protected) r = this - a
    function bnpSubTo(a, r) {
        var i = 0, c = 0, m = Math.min(a.t, this.t);
        while (i < m) {
            c += this[i] - a[i];
            r[i++] = c & this.DM;
            c >>= this.DB;
        }
        if (a.t < this.t) {
            c -= a.s;
            while (i < this.t) {
                c += this[i];
                r[i++] = c & this.DM;
                c >>= this.DB;
            }
            c += this.s;
        }
        else {
            c += this.s;
            while (i < a.t) {
                c -= a[i];
                r[i++] = c & this.DM;
                c >>= this.DB;
            }
            c -= a.s;
        }
        r.s = (c < 0) ? -1 : 0;
        if (c < -1)
            r[i++] = this.DV + c;
        else if (c > 0)
            r[i++] = c;
        r.t = i;
        r.clamp();
    }
    // (protected) r = this * a, r != this,a (HAC 14.12)
    // "this" should be the larger one if appropriate.
    function bnpMultiplyTo(a, r) {
        var x = this.abs(), y = a.abs();
        var i = x.t;
        r.t = i + y.t;
        while (--i >= 0)
            r[i] = 0;
        for (i = 0; i < y.t; ++i)
            r[i + x.t] = x.am(0, y[i], r, i, 0, x.t);
        r.s = 0;
        r.clamp();
        if (this.s != a.s)
            BigInteger.ZERO.subTo(r, r);
    }
    // (protected) r = this^2, r != this (HAC 14.16)
    function bnpSquareTo(r) {
        var x = this.abs();
        var i = r.t = 2 * x.t;
        while (--i >= 0)
            r[i] = 0;
        for (i = 0; i < x.t - 1; ++i) {
            var c = x.am(i, x[i], r, 2 * i, 0, 1);
            if ((r[i + x.t] += x.am(i + 1, 2 * x[i], r, 2 * i + 1, c, x.t - i - 1)) >= x.DV) {
                r[i + x.t] -= x.DV;
                r[i + x.t + 1] = 1;
            }
        }
        if (r.t > 0)
            r[r.t - 1] += x.am(i, x[i], r, 2 * i, 0, 1);
        r.s = 0;
        r.clamp();
    }
    // (protected) divide this by m, quotient and remainder to q, r (HAC 14.20)
    // r != q, this != m.  q or r may be null.
    function bnpDivRemTo(m, q, r) {
        var pm = m.abs();
        if (pm.t <= 0)
            return;
        var pt = this.abs();
        if (pt.t < pm.t) {
            if (q != null)
                q.fromInt(0);
            if (r != null)
                this.copyTo(r);
            return;
        }
        if (r == null)
            r = nbi();
        var y = nbi(), ts = this.s, ms = m.s;
        var nsh = this.DB - nbits(pm[pm.t - 1]); // normalize modulus
        if (nsh > 0) {
            pm.lShiftTo(nsh, y);
            pt.lShiftTo(nsh, r);
        }
        else {
            pm.copyTo(y);
            pt.copyTo(r);
        }
        var ys = y.t;
        var y0 = y[ys - 1];
        if (y0 == 0)
            return;
        var yt = y0 * (1 << this.F1) + ((ys > 1) ? y[ys - 2] >> this.F2 : 0);
        var d1 = this.FV / yt, d2 = (1 << this.F1) / yt, e = 1 << this.F2;
        var i = r.t, j = i - ys, t = (q == null) ? nbi() : q;
        y.dlShiftTo(j, t);
        if (r.compareTo(t) >= 0) {
            r[r.t++] = 1;
            r.subTo(t, r);
        }
        BigInteger.ONE.dlShiftTo(ys, t);
        t.subTo(y, y); // "negative" y so we can replace sub with am later
        while (y.t < ys)
            y[y.t++] = 0;
        while (--j >= 0) {
            // Estimate quotient digit
            var qd = (r[--i] == y0) ? this.DM : Math.floor(r[i] * d1 + (r[i - 1] + e) * d2);
            if ((r[i] += y.am(0, qd, r, j, 0, ys)) < qd) {
                y.dlShiftTo(j, t);
                r.subTo(t, r);
                while (r[i] < --qd)
                    r.subTo(t, r);
            }
        }
        if (q != null) {
            r.drShiftTo(ys, q);
            if (ts != ms)
                BigInteger.ZERO.subTo(q, q);
        }
        r.t = ys;
        r.clamp();
        if (nsh > 0)
            r.rShiftTo(nsh, r); // Denormalize remainder
        if (ts < 0)
            BigInteger.ZERO.subTo(r, r);
    }
    // (public) this mod a
    function bnMod(a) {
        var r = nbi();
        this.abs().divRemTo(a, null, r);
        if (this.s < 0 && r.compareTo(BigInteger.ZERO) > 0)
            a.subTo(r, r);
        return r;
    }
    // Modular reduction using "classic" algorithm
    function Classic(m) { this.m = m; }
    function cConvert(x) {
        if (x.s < 0 || x.compareTo(this.m) >= 0)
            return x.mod(this.m);
        else
            return x;
    }
    function cRevert(x) { return x; }
    function cReduce(x) { x.divRemTo(this.m, null, x); }
    function cMulTo(x, y, r) { x.multiplyTo(y, r); this.reduce(r); }
    function cSqrTo(x, r) { x.squareTo(r); this.reduce(r); }
    Classic.prototype.convert = cConvert;
    Classic.prototype.revert = cRevert;
    Classic.prototype.reduce = cReduce;
    Classic.prototype.mulTo = cMulTo;
    Classic.prototype.sqrTo = cSqrTo;
    // (protected) return "-1/this % 2^DB"; useful for Mont. reduction
    // justification:
    //         xy == 1 (mod m)
    //         xy =  1+km
    //   xy(2-xy) = (1+km)(1-km)
    // x[y(2-xy)] = 1-k^2m^2
    // x[y(2-xy)] == 1 (mod m^2)
    // if y is 1/x mod m, then y(2-xy) is 1/x mod m^2
    // should reduce x and y(2-xy) by m^2 at each step to keep size bounded.
    // JS multiply "overflows" differently from C/C++, so care is needed here.
    function bnpInvDigit() {
        if (this.t < 1)
            return 0;
        var x = this[0];
        if ((x & 1) == 0)
            return 0;
        var y = x & 3; // y == 1/x mod 2^2
        y = (y * (2 - (x & 0xf) * y)) & 0xf; // y == 1/x mod 2^4
        y = (y * (2 - (x & 0xff) * y)) & 0xff; // y == 1/x mod 2^8
        y = (y * (2 - (((x & 0xffff) * y) & 0xffff))) & 0xffff; // y == 1/x mod 2^16
        // last step - calculate inverse mod DV directly;
        // assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints
        y = (y * (2 - x * y % this.DV)) % this.DV; // y == 1/x mod 2^dbits
        // we really want the negative inverse, and -DV < y < DV
        return (y > 0) ? this.DV - y : -y;
    }
    // Montgomery reduction
    function Montgomery(m) {
        this.m = m;
        this.mp = m.invDigit();
        this.mpl = this.mp & 0x7fff;
        this.mph = this.mp >> 15;
        this.um = (1 << (m.DB - 15)) - 1;
        this.mt2 = 2 * m.t;
    }
    // xR mod m
    function montConvert(x) {
        var r = nbi();
        x.abs().dlShiftTo(this.m.t, r);
        r.divRemTo(this.m, null, r);
        if (x.s < 0 && r.compareTo(BigInteger.ZERO) > 0)
            this.m.subTo(r, r);
        return r;
    }
    // x/R mod m
    function montRevert(x) {
        var r = nbi();
        x.copyTo(r);
        this.reduce(r);
        return r;
    }
    // x = x/R mod m (HAC 14.32)
    function montReduce(x) {
        while (x.t <= this.mt2)
            x[x.t++] = 0;
        for (var i = 0; i < this.m.t; ++i) {
            // faster way of calculating u0 = x[i]*mp mod DV
            var j = x[i] & 0x7fff;
            var u0 = (j * this.mpl + (((j * this.mph + (x[i] >> 15) * this.mpl) & this.um) << 15)) & x.DM;
            // use am to combine the multiply-shift-add into one call
            j = i + this.m.t;
            x[j] += this.m.am(0, u0, x, i, 0, this.m.t);
            // propagate carry
            while (x[j] >= x.DV) {
                x[j] -= x.DV;
                x[++j]++;
            }
        }
        x.clamp();
        x.drShiftTo(this.m.t, x);
        if (x.compareTo(this.m) >= 0)
            x.subTo(this.m, x);
    }
    // r = "x^2/R mod m"; x != r
    function montSqrTo(x, r) { x.squareTo(r); this.reduce(r); }
    // r = "xy/R mod m"; x,y != r
    function montMulTo(x, y, r) { x.multiplyTo(y, r); this.reduce(r); }
    Montgomery.prototype.convert = montConvert;
    Montgomery.prototype.revert = montRevert;
    Montgomery.prototype.reduce = montReduce;
    Montgomery.prototype.mulTo = montMulTo;
    Montgomery.prototype.sqrTo = montSqrTo;
    // (protected) true iff this is even
    function bnpIsEven() { return ((this.t > 0) ? (this[0] & 1) : this.s) == 0; }
    // (protected) this^e, e < 2^32, doing sqr and mul with "r" (HAC 14.79)
    function bnpExp(e, z) {
        if (e > 0xffffffff || e < 1)
            return BigInteger.ONE;
        var r = nbi(), r2 = nbi(), g = z.convert(this), i = nbits(e) - 1;
        g.copyTo(r);
        while (--i >= 0) {
            z.sqrTo(r, r2);
            if ((e & (1 << i)) > 0)
                z.mulTo(r2, g, r);
            else {
                var t = r;
                r = r2;
                r2 = t;
            }
        }
        return z.revert(r);
    }
    // (public) this^e % m, 0 <= e < 2^32
    function bnModPowInt(e, m) {
        var z;
        if (e < 256 || m.isEven())
            z = new Classic(m);
        else
            z = new Montgomery(m);
        return this.exp(e, z);
    }
    // protected
    BigInteger.prototype.copyTo = bnpCopyTo;
    BigInteger.prototype.fromInt = bnpFromInt;
    BigInteger.prototype.fromString = bnpFromString;
    BigInteger.prototype.clamp = bnpClamp;
    BigInteger.prototype.dlShiftTo = bnpDLShiftTo;
    BigInteger.prototype.drShiftTo = bnpDRShiftTo;
    BigInteger.prototype.lShiftTo = bnpLShiftTo;
    BigInteger.prototype.rShiftTo = bnpRShiftTo;
    BigInteger.prototype.subTo = bnpSubTo;
    BigInteger.prototype.multiplyTo = bnpMultiplyTo;
    BigInteger.prototype.squareTo = bnpSquareTo;
    BigInteger.prototype.divRemTo = bnpDivRemTo;
    BigInteger.prototype.invDigit = bnpInvDigit;
    BigInteger.prototype.isEven = bnpIsEven;
    BigInteger.prototype.exp = bnpExp;
    // public
    BigInteger.prototype.toString = bnToString;
    BigInteger.prototype.negate = bnNegate;
    BigInteger.prototype.abs = bnAbs;
    BigInteger.prototype.compareTo = bnCompareTo;
    BigInteger.prototype.bitLength = bnBitLength;
    BigInteger.prototype.mod = bnMod;
    BigInteger.prototype.modPowInt = bnModPowInt;
    // "constants"
    BigInteger.ZERO = nbv(0);
    BigInteger.ONE = nbv(1);
    // Depends on jsbn.js and rng.js
    // Version 1.1: support utf-8 encoding in pkcs1pad2
    // convert a (hex) string to a bignum object
    function parseBigInt(str, r) {
        return new BigInteger(str, r);
    }
    function linebrk(s, n) {
        var ret = "";
        var i = 0;
        while (i + n < s.length) {
            ret += s.substring(i, i + n) + "\n";
            i += n;
        }
        return ret + s.substring(i, s.length);
    }
    function byte2Hex(b) {
        if (b < 0x10)
            return "0" + b.toString(16);
        else
            return b.toString(16);
    }
    // PKCS#1 (type 2, random) pad input string s to n bytes, and return a bigint
    function pkcs1pad2(s, n) {
        if (n < s.length + 11) {
            throw new Error("Message too long for RSA");
        }
        var ba = new Array();
        var i = s.length - 1;
        while (i >= 0 && n > 0) {
            var c = s.charCodeAt(i--);
            if (c < 128) {
                ba[--n] = c;
            }
            else if ((c > 127) && (c < 2048)) {
                ba[--n] = (c & 63) | 128;
                ba[--n] = (c >> 6) | 192;
            }
            else {
                ba[--n] = (c & 63) | 128;
                ba[--n] = ((c >> 6) & 63) | 128;
                ba[--n] = (c >> 12) | 224;
            }
        }
        ba[--n] = 0;
        var randomByte = 0;
        var random = 0;
        var shift = 0;
        while (n > 2) {
            if (shift == 0) {
                random = sjcl.random.randomWords(1, 0)[0];
            }
            randomByte = (random >> shift) & 0xff;
            shift = (shift + 8) % 32;
            if (randomByte != 0) {
                ba[--n] = randomByte;
            }
        }
        ba[--n] = 2;
        ba[--n] = 0;
        return new BigInteger(ba);
    }
    // "empty" RSA key constructor
    function RSAKey() {
        this.n = null;
        this.e = 0;
        this.d = null;
        this.p = null;
        this.q = null;
        this.dmp1 = null;
        this.dmq1 = null;
        this.coeff = null;
    }
    // Set the public key fields N and e from hex strings
    function RSASetPublic(N, E) {
        if (N != null && E != null && N.length > 0 && E.length > 0) {
            this.n = parseBigInt(N, 16);
            this.e = parseInt(E, 16);
        }
        else
            throw new Error("Invalid RSA public key");
    }
    // Perform raw public operation on "x": return x^e (mod n)
    function RSADoPublic(x) {
        return x.modPowInt(this.e, this.n);
    }
    // Return the PKCS#1 RSA encryption of "text" as an even-length hex string
    function RSAEncrypt(text) {
        var m = pkcs1pad2(text, (this.n.bitLength() + 7) >> 3);
        if (m == null)
            return null;
        var c = this.doPublic(m);
        if (c == null)
            return null;
        var h = c.toString(16);
        if ((h.length & 1) == 0)
            return h;
        else
            return "0" + h;
    }
    // Return the PKCS#1 RSA encryption of "text" as a Base64-encoded string
    //function RSAEncryptB64(text) {
    //  var h = this.encrypt(text);
    //  if(h) return hex2b64(h); else return null;
    //}
    // protected
    RSAKey.prototype.doPublic = RSADoPublic;
    // public
    RSAKey.prototype.setPublic = RSASetPublic;
    RSAKey.prototype.encrypt = RSAEncrypt;
    //RSAKey.prototype.encrypt_b64 = RSAEncryptB64;
    /** @fileOverview Javascript cryptography implementation.
     *
     * Crush to remove comments, shorten variable names and
     * generally reduce transmission size.
     *
     * @author Emily Stark
     * @author Mike Hamburg
     * @author Dan Boneh
     */
    "use strict";
    /*jslint indent: 2, bitwise: false, nomen: false, plusplus: false, white: false, regexp: false */
    /*global document, window, escape, unescape */
    /** @namespace The Stanford Javascript Crypto Library, top-level namespace. */
    var sjcl = {
        /** @namespace Symmetric ciphers. */
        cipher: {},
        /** @namespace Hash functions.  Right now only SHA256 is implemented. */
        hash: {},
        /** @namespace Key exchange functions.  Right now only SRP is implemented. */
        keyexchange: {},
        /** @namespace Block cipher modes of operation. */
        mode: {},
        /** @namespace Miscellaneous.  HMAC and PBKDF2. */
        misc: {},
        /**
         * @namespace Bit array encoders and decoders.
         *
         * @description
         * The members of this namespace are functions which translate between
         * SJCL's bitArrays and other objects (usually strings).  Because it
         * isn't always clear which direction is encoding and which is decoding,
         * the method names are "fromBits" and "toBits".
         */
        codec: {},
        /** @namespace Exceptions. */
        exception: {
            /** @class Ciphertext is corrupt. */
            corrupt: function (message) {
                this.toString = function () { return "CORRUPT: " + this.message; };
                this.message = message;
            },
            /** @class Invalid parameter. */
            invalid: function (message) {
                this.toString = function () { return "INVALID: " + this.message; };
                this.message = message;
            },
            /** @class Bug or missing feature in SJCL. */
            bug: function (message) {
                this.toString = function () { return "BUG: " + this.message; };
                this.message = message;
            },
            /** @class Something isn't ready. */
            notReady: function (message) {
                this.toString = function () { return "NOT READY: " + this.message; };
                this.message = message;
            }
        }
    };
    if (typeof module != 'undefined' && module.exports) {
        module.exports = sjcl;
    }
    /** @fileOverview Low-level AES implementation.
     *
     * This file contains a low-level implementation of AES, optimized for
     * size and for efficiency on several browsers.  It is based on
     * OpenSSL's aes_core.c, a public-domain implementation by Vincent
     * Rijmen, Antoon Bosselaers and Paulo Barreto.
     *
     * An older version of this implementation is available in the public
     * domain, but this one is (c) Emily Stark, Mike Hamburg, Dan Boneh,
     * Stanford University 2008-2010 and BSD-licensed for liability
     * reasons.
     *
     * @author Emily Stark
     * @author Mike Hamburg
     * @author Dan Boneh
     */
    /**
     * Schedule out an AES key for both encryption and decryption.  This
     * is a low-level class.  Use a cipher mode to do bulk encryption.
     *
     * @constructor
     * @param {Array} key The key as an array of 4, 6 or 8 words.
     *
     * @class Advanced Encryption Standard (low-level interface)
     */
    sjcl.cipher.aes = function (key) {
        if (!this._tables[0][0][0]) {
            this._precompute();
        }
        var i, j, tmp, encKey, decKey, sbox = this._tables[0][4], decTable = this._tables[1], keyLen = key.length, rcon = 1;
        if (keyLen !== 4 && keyLen !== 6 && keyLen !== 8) {
            throw new sjcl.exception.invalid("invalid aes key size");
        }
        this._key = [encKey = key.slice(0), decKey = []];
        // schedule encryption keys
        for (i = keyLen; i < 4 * keyLen + 28; i++) {
            tmp = encKey[i - 1];
            // apply sbox
            if (i % keyLen === 0 || (keyLen === 8 && i % keyLen === 4)) {
                tmp = sbox[tmp >>> 24] << 24 ^ sbox[tmp >> 16 & 255] << 16 ^ sbox[tmp >> 8 & 255] << 8 ^ sbox[tmp & 255];
                // shift rows and add rcon
                if (i % keyLen === 0) {
                    tmp = tmp << 8 ^ tmp >>> 24 ^ rcon << 24;
                    rcon = rcon << 1 ^ (rcon >> 7) * 283;
                }
            }
            encKey[i] = encKey[i - keyLen] ^ tmp;
        }
        // schedule decryption keys
        for (j = 0; i; j++, i--) {
            tmp = encKey[j & 3 ? i : i - 4];
            if (i <= 4 || j < 4) {
                decKey[j] = tmp;
            }
            else {
                decKey[j] = decTable[0][sbox[tmp >>> 24]] ^
                    decTable[1][sbox[tmp >> 16 & 255]] ^
                    decTable[2][sbox[tmp >> 8 & 255]] ^
                    decTable[3][sbox[tmp & 255]];
            }
        }
    };
    sjcl.cipher.aes.prototype = {
        // public
        /* Something like this might appear here eventually
        name: "AES",
        blockSize: 4,
        keySizes: [4,6,8],
        */
        /**
         * Encrypt an array of 4 big-endian words.
         * @param {Array} data The plaintext.
         * @return {Array} The ciphertext.
         */
        encrypt: function (data) { return this._crypt(data, 0); },
        /**
         * Decrypt an array of 4 big-endian words.
         * @param {Array} data The ciphertext.
         * @return {Array} The plaintext.
         */
        decrypt: function (data) { return this._crypt(data, 1); },
        /**
         * The expanded S-box and inverse S-box tables.  These will be computed
         * on the client so that we don't have to send them down the wire.
         *
         * There are two tables, _tables[0] is for encryption and
         * _tables[1] is for decryption.
         *
         * The first 4 sub-tables are the expanded S-box with MixColumns.  The
         * last (_tables[01][4]) is the S-box itself.
         *
         * @private
         */
        _tables: [[[], [], [], [], []], [[], [], [], [], []]],
        /**
         * Expand the S-box tables.
         *
         * @private
         */
        _precompute: function () {
            var encTable = this._tables[0], decTable = this._tables[1], sbox = encTable[4], sboxInv = decTable[4], i, x, xInv, d = [], th = [], x2, x4, x8, s, tEnc, tDec;
            // Compute double and third tables
            for (i = 0; i < 256; i++) {
                th[(d[i] = i << 1 ^ (i >> 7) * 283) ^ i] = i;
            }
            for (x = xInv = 0; !sbox[x]; x ^= x2 || 1, xInv = th[xInv] || 1) {
                // Compute sbox
                s = xInv ^ xInv << 1 ^ xInv << 2 ^ xInv << 3 ^ xInv << 4;
                s = s >> 8 ^ s & 255 ^ 99;
                sbox[x] = s;
                sboxInv[s] = x;
                // Compute MixColumns
                x8 = d[x4 = d[x2 = d[x]]];
                tDec = x8 * 0x1010101 ^ x4 * 0x10001 ^ x2 * 0x101 ^ x * 0x1010100;
                tEnc = d[s] * 0x101 ^ s * 0x1010100;
                for (i = 0; i < 4; i++) {
                    encTable[i][x] = tEnc = tEnc << 24 ^ tEnc >>> 8;
                    decTable[i][s] = tDec = tDec << 24 ^ tDec >>> 8;
                }
            }
            // Compactify.  Considerable speedup on Firefox.
            for (i = 0; i < 5; i++) {
                encTable[i] = encTable[i].slice(0);
                decTable[i] = decTable[i].slice(0);
            }
        },
        /**
         * Encryption and decryption core.
         * @param {Array} input Four words to be encrypted or decrypted.
         * @param dir The direction, 0 for encrypt and 1 for decrypt.
         * @return {Array} The four encrypted or decrypted words.
         * @private
         */
        _crypt: function (input, dir) {
            if (input.length !== 4) {
                throw new sjcl.exception.invalid("invalid aes block size");
            }
            var key = this._key[dir], 
            // state variables a,b,c,d are loaded with pre-whitened data
            a = input[0] ^ key[0], b = input[dir ? 3 : 1] ^ key[1], c = input[2] ^ key[2], d = input[dir ? 1 : 3] ^ key[3], a2, b2, c2, nInnerRounds = key.length / 4 - 2, i, kIndex = 4, out = [0, 0, 0, 0], table = this._tables[dir], 
            // load up the tables
            t0 = table[0], t1 = table[1], t2 = table[2], t3 = table[3], sbox = table[4];
            // Inner rounds.  Cribbed from OpenSSL.
            for (i = 0; i < nInnerRounds; i++) {
                a2 = t0[a >>> 24] ^ t1[b >> 16 & 255] ^ t2[c >> 8 & 255] ^ t3[d & 255] ^ key[kIndex];
                b2 = t0[b >>> 24] ^ t1[c >> 16 & 255] ^ t2[d >> 8 & 255] ^ t3[a & 255] ^ key[kIndex + 1];
                c2 = t0[c >>> 24] ^ t1[d >> 16 & 255] ^ t2[a >> 8 & 255] ^ t3[b & 255] ^ key[kIndex + 2];
                d = t0[d >>> 24] ^ t1[a >> 16 & 255] ^ t2[b >> 8 & 255] ^ t3[c & 255] ^ key[kIndex + 3];
                kIndex += 4;
                a = a2;
                b = b2;
                c = c2;
            }
            // Last round.
            for (i = 0; i < 4; i++) {
                out[dir ? 3 & -i : i] =
                    sbox[a >>> 24] << 24 ^
                        sbox[b >> 16 & 255] << 16 ^
                        sbox[c >> 8 & 255] << 8 ^
                        sbox[d & 255] ^
                        key[kIndex++];
                a2 = a;
                a = b;
                b = c;
                c = d;
                d = a2;
            }
            return out;
        }
    };
    /** @fileOverview Arrays of bits, encoded as arrays of Numbers.
     *
     * @author Emily Stark
     * @author Mike Hamburg
     * @author Dan Boneh
     */
    /** @namespace Arrays of bits, encoded as arrays of Numbers.
     *
     * @description
     * <p>
     * These objects are the currency accepted by SJCL's crypto functions.
     * </p>
     *
     * <p>
     * Most of our crypto primitives operate on arrays of 4-byte words internally,
     * but many of them can take arguments that are not a multiple of 4 bytes.
     * This library encodes arrays of bits (whose size need not be a multiple of 8
     * bits) as arrays of 32-bit words.  The bits are packed, big-endian, into an
     * array of words, 32 bits at a time.  Since the words are double-precision
     * floating point numbers, they fit some extra data.  We use this (in a private,
     * possibly-changing manner) to encode the number of bits actually  present
     * in the last word of the array.
     * </p>
     *
     * <p>
     * Because bitwise ops clear this out-of-band data, these arrays can be passed
     * to ciphers like AES which want arrays of words.
     * </p>
     */
    sjcl.bitArray = {
        /**
         * Array slices in units of bits.
         * @param {bitArray} a The array to slice.
         * @param {Number} bstart The offset to the start of the slice, in bits.
         * @param {Number} bend The offset to the end of the slice, in bits.  If this is undefined,
         * slice until the end of the array.
         * @return {bitArray} The requested slice.
         */
        bitSlice: function (a, bstart, bend) {
            a = sjcl.bitArray._shiftRight(a.slice(bstart / 32), 32 - (bstart & 31)).slice(1);
            return (bend === undefined) ? a : sjcl.bitArray.clamp(a, bend - bstart);
        },
        /**
         * Extract a number packed into a bit array.
         * @param {bitArray} a The array to slice.
         * @param {Number} bstart The offset to the start of the slice, in bits.
         * @param {Number} length The length of the number to extract.
         * @return {Number} The requested slice.
         */
        extract: function (a, bstart, blength) {
            // FIXME: this Math.floor is not necessary at all, but for some reason
            // seems to suppress a bug in the Chromium JIT.
            var x, sh = Math.floor((-bstart - blength) & 31);
            if ((bstart + blength - 1 ^ bstart) & -32) {
                // it crosses a boundary
                x = (a[bstart / 32 | 0] << (32 - sh)) ^ (a[bstart / 32 + 1 | 0] >>> sh);
            }
            else {
                // within a single word
                x = a[bstart / 32 | 0] >>> sh;
            }
            return x & ((1 << blength) - 1);
        },
        /**
         * Concatenate two bit arrays.
         * @param {bitArray} a1 The first array.
         * @param {bitArray} a2 The second array.
         * @return {bitArray} The concatenation of a1 and a2.
         */
        concat: function (a1, a2) {
            if (a1.length === 0 || a2.length === 0) {
                return a1.concat(a2);
            }
            var out, i, last = a1[a1.length - 1], shift = sjcl.bitArray.getPartial(last);
            if (shift === 32) {
                return a1.concat(a2);
            }
            else {
                return sjcl.bitArray._shiftRight(a2, shift, last | 0, a1.slice(0, a1.length - 1));
            }
        },
        /**
         * Find the length of an array of bits.
         * @param {bitArray} a The array.
         * @return {Number} The length of a, in bits.
         */
        bitLength: function (a) {
            var l = a.length, x;
            if (l === 0) {
                return 0;
            }
            x = a[l - 1];
            return (l - 1) * 32 + sjcl.bitArray.getPartial(x);
        },
        /**
         * Truncate an array.
         * @param {bitArray} a The array.
         * @param {Number} len The length to truncate to, in bits.
         * @return {bitArray} A new array, truncated to len bits.
         */
        clamp: function (a, len) {
            if (a.length * 32 < len) {
                return a;
            }
            a = a.slice(0, Math.ceil(len / 32));
            var l = a.length;
            len = len & 31;
            if (l > 0 && len) {
                a[l - 1] = sjcl.bitArray.partial(len, a[l - 1] & 0x80000000 >> (len - 1), 1);
            }
            return a;
        },
        /**
         * Make a partial word for a bit array.
         * @param {Number} len The number of bits in the word.
         * @param {Number} x The bits.
         * @param {Number} [0] _end Pass 1 if x has already been shifted to the high side.
         * @return {Number} The partial word.
         */
        partial: function (len, x, _end) {
            if (len === 32) {
                return x;
            }
            return (_end ? x | 0 : x << (32 - len)) + len * 0x10000000000;
        },
        /**
         * Get the number of bits used by a partial word.
         * @param {Number} x The partial word.
         * @return {Number} The number of bits used by the partial word.
         */
        getPartial: function (x) {
            return Math.round(x / 0x10000000000) || 32;
        },
        /**
         * Compare two arrays for equality in a predictable amount of time.
         * @param {bitArray} a The first array.
         * @param {bitArray} b The second array.
         * @return {boolean} true if a == b; false otherwise.
         */
        equal: function (a, b) {
            if (sjcl.bitArray.bitLength(a) !== sjcl.bitArray.bitLength(b)) {
                return false;
            }
            var x = 0, i;
            for (i = 0; i < a.length; i++) {
                x |= a[i] ^ b[i];
            }
            return (x === 0);
        },
        /** Shift an array right.
         * @param {bitArray} a The array to shift.
         * @param {Number} shift The number of bits to shift.
         * @param {Number} [carry=0] A byte to carry in
         * @param {bitArray} [out=[]] An array to prepend to the output.
         * @private
         */
        _shiftRight: function (a, shift, carry, out) {
            var i, last2 = 0, shift2;
            if (out === undefined) {
                out = [];
            }
            for (; shift >= 32; shift -= 32) {
                out.push(carry);
                carry = 0;
            }
            if (shift === 0) {
                return out.concat(a);
            }
            for (i = 0; i < a.length; i++) {
                out.push(carry | a[i] >>> shift);
                carry = a[i] << (32 - shift);
            }
            last2 = a.length ? a[a.length - 1] : 0;
            shift2 = sjcl.bitArray.getPartial(last2);
            out.push(sjcl.bitArray.partial(shift + shift2 & 31, (shift + shift2 > 32) ? carry : out.pop(), 1));
            return out;
        },
        /** xor a block of 4 words together.
         * @private
         */
        _xor4: function (x, y) {
            return [x[0] ^ y[0], x[1] ^ y[1], x[2] ^ y[2], x[3] ^ y[3]];
        }
    };
    /** @fileOverview Bit array codec implementations.
     *
     * @author Emily Stark
     * @author Mike Hamburg
     * @author Dan Boneh
     */
    /** @namespace Hexadecimal */
    sjcl.codec.hex = {
        /** Convert from a bitArray to a hex string. */
        fromBits: function (arr) {
            var out = "", i, x;
            for (i = 0; i < arr.length; i++) {
                out += ((arr[i] | 0) + 0xF00000000000).toString(16).substr(4);
            }
            return out.substr(0, sjcl.bitArray.bitLength(arr) / 4); //.replace(/(.{8})/g, "$1 ");
        },
        /** Convert from a hex string to a bitArray. */
        toBits: function (str) {
            var i, out = [], len;
            str = str.replace(/\s|0x/g, "");
            len = str.length;
            str = str + "00000000";
            for (i = 0; i < str.length; i += 8) {
                out.push(parseInt(str.substr(i, 8), 16) ^ 0);
            }
            return sjcl.bitArray.clamp(out, len * 4);
        }
    };
    /** @fileOverview Bit array codec implementations.
     *
     * @author Emily Stark
     * @author Mike Hamburg
     * @author Dan Boneh
     */
    /** @namespace UTF-8 strings */
    sjcl.codec.utf8String = {
        /** Convert from a bitArray to a UTF-8 string. */
        fromBits: function (arr) {
            var out = "", bl = sjcl.bitArray.bitLength(arr), i, tmp;
            for (i = 0; i < bl / 8; i++) {
                if ((i & 3) === 0) {
                    tmp = arr[i / 4];
                }
                out += String.fromCharCode(tmp >>> 24);
                tmp <<= 8;
            }
            return decodeURIComponent(escape(out));
        },
        /** Convert from a UTF-8 string to a bitArray. */
        toBits: function (str) {
            str = unescape(encodeURIComponent(str));
            var out = [], i, tmp = 0;
            for (i = 0; i < str.length; i++) {
                tmp = tmp << 8 | str.charCodeAt(i);
                if ((i & 3) === 3) {
                    out.push(tmp);
                    tmp = 0;
                }
            }
            if (i & 3) {
                out.push(sjcl.bitArray.partial(8 * (i & 3), tmp));
            }
            return out;
        }
    };
    /** @fileOverview Bit array codec implementations.
     *
     * @author Emily Stark
     * @author Mike Hamburg
     * @author Dan Boneh
     */
    /** @namespace Base64 encoding/decoding */
    sjcl.codec.base64 = {
        /** The base64 alphabet.
         * @private
         */
        _chars: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
        /** Convert from a bitArray to a base64 string. */
        fromBits: function (arr, _noEquals, _url) {
            var out = "", i, bits = 0, c = sjcl.codec.base64._chars, ta = 0, bl = sjcl.bitArray.bitLength(arr);
            if (_url)
                c = c.substr(0, 62) + '-_';
            for (i = 0; out.length * 6 < bl;) {
                out += c.charAt((ta ^ arr[i] >>> bits) >>> 26);
                if (bits < 6) {
                    ta = arr[i] << (6 - bits);
                    bits += 26;
                    i++;
                }
                else {
                    ta <<= 6;
                    bits -= 6;
                }
            }
            while ((out.length & 3) && !_noEquals) {
                out += "=";
            }
            return out;
        },
        /** Convert from a base64 string to a bitArray */
        toBits: function (str, _url) {
            str = str.replace(/\s|=/g, '');
            var out = [], i, bits = 0, c = sjcl.codec.base64._chars, ta = 0, x;
            if (_url)
                c = c.substr(0, 62) + '-_';
            for (i = 0; i < str.length; i++) {
                x = c.indexOf(str.charAt(i));
                if (x < 0) {
                    throw new sjcl.exception.invalid("this isn't base64!");
                }
                if (bits > 26) {
                    bits -= 26;
                    out.push(ta ^ x >>> bits);
                    ta = x << (32 - bits);
                }
                else {
                    bits += 6;
                    ta ^= x << (32 - bits);
                }
            }
            if (bits & 56) {
                out.push(sjcl.bitArray.partial(bits & 56, ta, 1));
            }
            return out;
        }
    };
    sjcl.codec.base64url = {
        fromBits: function (arr) { return sjcl.codec.base64.fromBits(arr, 1, 1); },
        toBits: function (str) { return sjcl.codec.base64.toBits(str, 1); }
    };
    /** @fileOverview CBC mode implementation
     *
     * @author Emily Stark
     * @author Mike Hamburg
     * @author Dan Boneh
     */
    /** @namespace
     * Dangerous: CBC mode with PKCS#5 padding.
     *
     * @author Emily Stark
     * @author Mike Hamburg
     * @author Dan Boneh
     */
    if (sjcl.beware === undefined) {
        sjcl.beware = {};
    }
    sjcl.beware["CBC mode is dangerous because it doesn't protect message integrity."] = function () {
        sjcl.mode.cbc = {
            /** The name of the mode.
             * @constant
             */
            name: "cbc",
            /** Encrypt in CBC mode with PKCS#5 padding.
             * @param {Object} prp The block cipher.  It must have a block size of 16 bytes.
             * @param {bitArray} plaintext The plaintext data.
             * @param {bitArray} iv The initialization value.
             * @param {bitArray} [adata=[]] The authenticated data.  Must be empty.
             * @return The encrypted data, an array of bytes.
             * @throws {sjcl.exception.invalid} if the IV isn't exactly 128 bits, or if any adata is specified.
             */
            encrypt: function (prp, plaintext, iv, adata) {
                if (adata && adata.length) {
                    throw new sjcl.exception.invalid("cbc can't authenticate data");
                }
                if (sjcl.bitArray.bitLength(iv) !== 128) {
                    throw new sjcl.exception.invalid("cbc iv must be 128 bits");
                }
                var i, w = sjcl.bitArray, xor = w._xor4, bl = w.bitLength(plaintext), bp = 0, output = [];
                if (bl & 7) {
                    throw new sjcl.exception.invalid("pkcs#5 padding only works for multiples of a byte");
                }
                for (i = 0; bp + 128 <= bl; i += 4, bp += 128) {
                    /* Encrypt a non-final block */
                    iv = prp.encrypt(xor(iv, plaintext.slice(i, i + 4)));
                    output.splice(i, 0, iv[0], iv[1], iv[2], iv[3]);
                }
                /* Construct the pad. */
                bl = (16 - ((bl >> 3) & 15)) * 0x1010101;
                /* Pad and encrypt. */
                iv = prp.encrypt(xor(iv, w.concat(plaintext, [bl, bl, bl, bl]).slice(i, i + 4)));
                output.splice(i, 0, iv[0], iv[1], iv[2], iv[3]);
                return output;
            },
            /** Decrypt in CBC mode.
             * @param {Object} prp The block cipher.  It must have a block size of 16 bytes.
             * @param {bitArray} ciphertext The ciphertext data.
             * @param {bitArray} iv The initialization value.
             * @param {bitArray} [adata=[]] The authenticated data.  It must be empty.
             * @return The decrypted data, an array of bytes.
             * @throws {sjcl.exception.invalid} if the IV isn't exactly 128 bits, or if any adata is specified.
             * @throws {sjcl.exception.corrupt} if if the message is corrupt.
             */
            decrypt: function (prp, ciphertext, iv, adata) {
                if (adata && adata.length) {
                    throw new sjcl.exception.invalid("cbc can't authenticate data");
                }
                if (sjcl.bitArray.bitLength(iv) !== 128) {
                    throw new sjcl.exception.invalid("cbc iv must be 128 bits");
                }
                if ((sjcl.bitArray.bitLength(ciphertext) & 127) || !ciphertext.length) {
                    throw new sjcl.exception.corrupt("cbc ciphertext must be a positive multiple of the block size");
                }
                var i, w = sjcl.bitArray, xor = w._xor4, bi, bo, output = [];
                adata = adata || [];
                for (i = 0; i < ciphertext.length; i += 4) {
                    bi = ciphertext.slice(i, i + 4);
                    bo = xor(iv, prp.decrypt(bi));
                    output.splice(i, 0, bo[0], bo[1], bo[2], bo[3]);
                    iv = bi;
                }
                /* check and remove the pad */
                bi = output[i - 1] & 255;
                if (bi == 0 || bi > 16) {
                    throw new sjcl.exception.corrupt("pkcs#5 padding corrupt");
                }
                bo = bi * 0x1010101;
                if (!w.equal(w.bitSlice([bo, bo, bo, bo], 0, bi * 8), w.bitSlice(output, output.length * 32 - bi * 8, output.length * 32))) {
                    throw new sjcl.exception.corrupt("pkcs#5 padding corrupt");
                }
                return w.bitSlice(output, 0, output.length * 32 - bi * 8);
            }
        };
    };
    /** @fileOverview HMAC implementation.
     *
     * @author Emily Stark
     * @author Mike Hamburg
     * @author Dan Boneh
     */
    /** HMAC with the specified hash function.
     * @constructor
     * @param {bitArray} key the key for HMAC.
     * @param {Object} [hash=sjcl.hash.sha256] The hash function to use.
     */
    sjcl.misc.hmac = function (key, Hash) {
        this._hash = Hash = Hash || sjcl.hash.sha256;
        var exKey = [[], []], i, bs = Hash.prototype.blockSize / 32;
        this._baseHash = [new Hash(), new Hash()];
        if (key.length > bs) {
            key = Hash.hash(key);
        }
        for (i = 0; i < bs; i++) {
            exKey[0][i] = key[i] ^ 0x36363636;
            exKey[1][i] = key[i] ^ 0x5C5C5C5C;
        }
        this._baseHash[0].update(exKey[0]);
        this._baseHash[1].update(exKey[1]);
    };
    /** HMAC with the specified hash function.  Also called encrypt since it's a prf.
     * @param {bitArray|String} data The data to mac.
     * @param {Codec} [encoding] the encoding function to use.
     */
    sjcl.misc.hmac.prototype.encrypt = sjcl.misc.hmac.prototype.mac = function (data, encoding) {
        var w = new (this._hash)(this._baseHash[0]).update(data, encoding).finalize();
        return new (this._hash)(this._baseHash[1]).update(w).finalize();
    };
    /** @fileOverview Javascript SHA-256 implementation.
     *
     * An older version of this implementation is available in the public
     * domain, but this one is (c) Emily Stark, Mike Hamburg, Dan Boneh,
     * Stanford University 2008-2010 and BSD-licensed for liability
     * reasons.
     *
     * Special thanks to Aldo Cortesi for pointing out several bugs in
     * this code.
     *
     * @author Emily Stark
     * @author Mike Hamburg
     * @author Dan Boneh
     */
    /**
     * Context for a SHA-256 operation in progress.
     * @constructor
     * @class Secure Hash Algorithm, 256 bits.
     */
    sjcl.hash.sha256 = function (hash) {
        if (!this._key[0]) {
            this._precompute();
        }
        if (hash) {
            this._h = hash._h.slice(0);
            this._buffer = hash._buffer.slice(0);
            this._length = hash._length;
        }
        else {
            this.reset();
        }
    };
    /**
     * Hash a string or an array of words.
     * @static
     * @param {bitArray|String} data the data to hash.
     * @return {bitArray} The hash value, an array of 16 big-endian words.
     */
    sjcl.hash.sha256.hash = function (data) {
        return (new sjcl.hash.sha256()).update(data).finalize();
    };
    sjcl.hash.sha256.prototype = {
        /**
         * The hash's block size, in bits.
         * @constant
         */
        blockSize: 512,
        /**
         * Reset the hash state.
         * @return this
         */
        reset: function () {
            this._h = this._init.slice(0);
            this._buffer = [];
            this._length = 0;
            return this;
        },
        /**
         * Input several words to the hash.
         * @param {bitArray|String} data the data to hash.
         * @return this
         */
        update: function (data) {
            if (typeof data === "string") {
                data = sjcl.codec.utf8String.toBits(data);
            }
            var i, b = this._buffer = sjcl.bitArray.concat(this._buffer, data), ol = this._length, nl = this._length = ol + sjcl.bitArray.bitLength(data);
            for (i = 512 + ol & -512; i <= nl; i += 512) {
                this._block(b.splice(0, 16));
            }
            return this;
        },
        /**
         * Complete hashing and output the hash value.
         * @return {bitArray} The hash value, an array of 16 big-endian words.
         */
        finalize: function () {
            var i, b = this._buffer, h = this._h;
            // Round out and push the buffer
            b = sjcl.bitArray.concat(b, [sjcl.bitArray.partial(1, 1)]);
            // Round out the buffer to a multiple of 16 words, less the 2 length words.
            for (i = b.length + 2; i & 15; i++) {
                b.push(0);
            }
            // append the length
            b.push(Math.floor(this._length / 0x100000000));
            b.push(this._length | 0);
            while (b.length) {
                this._block(b.splice(0, 16));
            }
            this.reset();
            return h;
        },
        /**
         * The SHA-256 initialization vector, to be precomputed.
         * @private
         */
        _init: [],
        /*
        _init:[0x6a09e667,0xbb67ae85,0x3c6ef372,0xa54ff53a,0x510e527f,0x9b05688c,0x1f83d9ab,0x5be0cd19],
        */
        /**
         * The SHA-256 hash key, to be precomputed.
         * @private
         */
        _key: [],
        /*
        _key:
          [0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
           0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
           0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
           0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
           0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
           0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
           0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
           0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2],
        */
        /**
         * Function to precompute _init and _key.
         * @private
         */
        _precompute: function () {
            var i = 0, prime = 2, factor;
            function frac(x) { return (x - Math.floor(x)) * 0x100000000 | 0; }
            outer: for (; i < 64; prime++) {
                for (factor = 2; factor * factor <= prime; factor++) {
                    if (prime % factor === 0) {
                        // not a prime
                        continue outer;
                    }
                }
                if (i < 8) {
                    this._init[i] = frac(Math.pow(prime, 1 / 2));
                }
                this._key[i] = frac(Math.pow(prime, 1 / 3));
                i++;
            }
        },
        /**
         * Perform one cycle of SHA-256.
         * @param {bitArray} words one block of words.
         * @private
         */
        _block: function (words) {
            var i, tmp, a, b, w = words.slice(0), h = this._h, k = this._key, h0 = h[0], h1 = h[1], h2 = h[2], h3 = h[3], h4 = h[4], h5 = h[5], h6 = h[6], h7 = h[7];
            /* Rationale for placement of |0 :
             * If a value can overflow is original 32 bits by a factor of more than a few
             * million (2^23 ish), there is a possibility that it might overflow the
             * 53-bit mantissa and lose precision.
             *
             * To avoid this, we clamp back to 32 bits by |'ing with 0 on any value that
             * propagates around the loop, and on the hash state h[].  I don't believe
             * that the clamps on h4 and on h0 are strictly necessary, but it's close
             * (for h4 anyway), and better safe than sorry.
             *
             * The clamps on h[] are necessary for the output to be correct even in the
             * common case and for short inputs.
             */
            for (i = 0; i < 64; i++) {
                // load up the input word for this round
                if (i < 16) {
                    tmp = w[i];
                }
                else {
                    a = w[(i + 1) & 15];
                    b = w[(i + 14) & 15];
                    tmp = w[i & 15] = ((a >>> 7 ^ a >>> 18 ^ a >>> 3 ^ a << 25 ^ a << 14) +
                        (b >>> 17 ^ b >>> 19 ^ b >>> 10 ^ b << 15 ^ b << 13) +
                        w[i & 15] + w[(i + 9) & 15]) | 0;
                }
                tmp = (tmp + h7 + (h4 >>> 6 ^ h4 >>> 11 ^ h4 >>> 25 ^ h4 << 26 ^ h4 << 21 ^ h4 << 7) + (h6 ^ h4 & (h5 ^ h6)) + k[i]); // | 0;
                // shift register
                h7 = h6;
                h6 = h5;
                h5 = h4;
                h4 = h3 + tmp | 0;
                h3 = h2;
                h2 = h1;
                h1 = h0;
                h0 = (tmp + ((h1 & h2) ^ (h3 & (h1 ^ h2))) + (h1 >>> 2 ^ h1 >>> 13 ^ h1 >>> 22 ^ h1 << 30 ^ h1 << 19 ^ h1 << 10)) | 0;
            }
            h[0] = h[0] + h0 | 0;
            h[1] = h[1] + h1 | 0;
            h[2] = h[2] + h2 | 0;
            h[3] = h[3] + h3 | 0;
            h[4] = h[4] + h4 | 0;
            h[5] = h[5] + h5 | 0;
            h[6] = h[6] + h6 | 0;
            h[7] = h[7] + h7 | 0;
        }
    };
    /** @fileOverview Random number generator.
     *
     * @author Emily Stark
     * @author Mike Hamburg
     * @author Dan Boneh
     */
    /** @namespace Random number generator
     *
     * @description
     * <p>
     * This random number generator is a derivative of Ferguson and Schneier's
     * generator Fortuna.  It collects entropy from various events into several
     * pools, implemented by streaming SHA-256 instances.  It differs from
     * ordinary Fortuna in a few ways, though.
     * </p>
     *
     * <p>
     * Most importantly, it has an entropy estimator.  This is present because
     * there is a strong conflict here between making the generator available
     * as soon as possible, and making sure that it doesn't "run on empty".
     * In Fortuna, there is a saved state file, and the system is likely to have
     * time to warm up.
     * </p>
     *
     * <p>
     * Second, because users are unlikely to stay on the page for very long,
     * and to speed startup time, the number of pools increases logarithmically:
     * a new pool is created when the previous one is actually used for a reseed.
     * This gives the same asymptotic guarantees as Fortuna, but gives more
     * entropy to early reseeds.
     * </p>
     *
     * <p>
     * The entire mechanism here feels pretty klunky.  Furthermore, there are
     * several improvements that should be made, including support for
     * dedicated cryptographic functions that may be present in some browsers;
     * state files in local storage; cookies containing randomness; etc.  So
     * look for improvements in future versions.
     * </p>
     */
    sjcl.random = {
        /** Generate several random words, and return them in an array
         * @param {Number} nwords The number of words to generate.
         */
        randomWords: function (nwords, paranoia) {
            var out = [], i, readiness = this.isReady(paranoia), g;
            if (readiness === this._NOT_READY) {
                throw new sjcl.exception.notReady("generator isn't seeded");
            }
            else if (readiness & this._REQUIRES_RESEED) {
                this._reseedFromPools(!(readiness & this._READY));
            }
            for (i = 0; i < nwords; i += 4) {
                if ((i + 1) % this._MAX_WORDS_PER_BURST === 0) {
                    this._gate();
                }
                g = this._gen4words();
                out.push(g[0], g[1], g[2], g[3]);
            }
            this._gate();
            return out.slice(0, nwords);
        },
        setDefaultParanoia: function (paranoia) {
            this._defaultParanoia = paranoia;
        },
        /**
         * Add entropy to the pools.
         * @param data The entropic value.  Should be a 32-bit integer, array of 32-bit integers, or string
         * @param {Number} estimatedEntropy The estimated entropy of data, in bits
         * @param {String} source The source of the entropy, eg "mouse"
         */
        addEntropy: function (data, estimatedEntropy, source) {
            source = source || "user";
            var id, i, tmp, t = (new Date()).valueOf(), robin = this._robins[source], oldReady = this.isReady(), err = 0;
            id = this._collectorIds[source];
            if (id === undefined) {
                id = this._collectorIds[source] = this._collectorIdNext++;
            }
            if (robin === undefined) {
                robin = this._robins[source] = 0;
            }
            this._robins[source] = (this._robins[source] + 1) % this._pools.length;
            switch (typeof (data)) {
                case "number":
                    if (estimatedEntropy === undefined) {
                        estimatedEntropy = 1;
                    }
                    this._pools[robin].update([id, this._eventId++, 1, estimatedEntropy, t, 1, data | 0]);
                    break;
                case "object":
                    var objName = Object.prototype.toString.call(data);
                    if (objName === "[object Uint32Array]") {
                        tmp = [];
                        for (i = 0; i < data.length; i++) {
                            tmp.push(data[i]);
                        }
                        data = tmp;
                    }
                    else {
                        if (objName !== "[object Array]") {
                            err = 1;
                        }
                        for (i = 0; i < data.length && !err; i++) {
                            if (typeof (data[i]) != "number") {
                                err = 1;
                            }
                        }
                    }
                    if (!err) {
                        if (estimatedEntropy === undefined) {
                            /* horrible entropy estimator */
                            estimatedEntropy = 0;
                            for (i = 0; i < data.length; i++) {
                                tmp = data[i];
                                while (tmp > 0) {
                                    estimatedEntropy++;
                                    tmp = tmp >>> 1;
                                }
                            }
                        }
                        this._pools[robin].update([id, this._eventId++, 2, estimatedEntropy, t, data.length].concat(data));
                    }
                    break;
                case "string":
                    if (estimatedEntropy === undefined) {
                        /* English text has just over 1 bit per character of entropy.
                         * But this might be HTML or something, and have far less
                         * entropy than English...  Oh well, let's just say one bit.
                         */
                        estimatedEntropy = data.length;
                    }
                    this._pools[robin].update([id, this._eventId++, 3, estimatedEntropy, t, data.length]);
                    this._pools[robin].update(data);
                    break;
                default:
                    err = 1;
            }
            if (err) {
                throw new sjcl.exception.bug("random: addEntropy only supports number, array of numbers or string");
            }
            /* record the new strength */
            this._poolEntropy[robin] += estimatedEntropy;
            this._poolStrength += estimatedEntropy;
            /* fire off events */
            if (oldReady === this._NOT_READY) {
                if (this.isReady() !== this._NOT_READY) {
                    this._fireEvent("seeded", Math.max(this._strength, this._poolStrength));
                }
                this._fireEvent("progress", this.getProgress());
            }
        },
        /** Is the generator ready? */
        isReady: function (paranoia) {
            var entropyRequired = this._PARANOIA_LEVELS[(paranoia !== undefined) ? paranoia : this._defaultParanoia];
            if (this._strength && this._strength >= entropyRequired) {
                return (this._poolEntropy[0] > this._BITS_PER_RESEED && (new Date()).valueOf() > this._nextReseed) ?
                    this._REQUIRES_RESEED | this._READY :
                    this._READY;
            }
            else {
                return (this._poolStrength >= entropyRequired) ?
                    this._REQUIRES_RESEED | this._NOT_READY :
                    this._NOT_READY;
            }
        },
        /** Get the generator's progress toward readiness, as a fraction */
        getProgress: function (paranoia) {
            var entropyRequired = this._PARANOIA_LEVELS[paranoia ? paranoia : this._defaultParanoia];
            if (this._strength >= entropyRequired) {
                return 1.0;
            }
            else {
                return (this._poolStrength > entropyRequired) ?
                    1.0 :
                    this._poolStrength / entropyRequired;
            }
        },
        /** start the built-in entropy collectors */
        startCollectors: function () {
            if (this._collectorsStarted) {
                return;
            }
            if (window.addEventListener) {
                window.addEventListener("load", this._loadTimeCollector, false);
                window.addEventListener("mousemove", this._mouseCollector, false);
            }
            else if (document.attachEvent) {
                document.attachEvent("onload", this._loadTimeCollector);
                document.attachEvent("onmousemove", this._mouseCollector);
            }
            else {
                throw new sjcl.exception.bug("can't attach event");
            }
            this._collectorsStarted = true;
        },
        /** stop the built-in entropy collectors */
        stopCollectors: function () {
            if (!this._collectorsStarted) {
                return;
            }
            if (window.removeEventListener) {
                window.removeEventListener("load", this._loadTimeCollector, false);
                window.removeEventListener("mousemove", this._mouseCollector, false);
            }
            else if (window.detachEvent) {
                window.detachEvent("onload", this._loadTimeCollector);
                window.detachEvent("onmousemove", this._mouseCollector);
            }
            this._collectorsStarted = false;
        },
        /* use a cookie to store entropy.
        useCookie: function (all_cookies) {
            throw new sjcl.exception.bug("random: useCookie is unimplemented");
        },*/
        /** add an event listener for progress or seeded-ness. */
        addEventListener: function (name, callback) {
            this._callbacks[name][this._callbackI++] = callback;
        },
        /** remove an event listener for progress or seeded-ness */
        removeEventListener: function (name, cb) {
            var i, j, cbs = this._callbacks[name], jsTemp = [];
            /* I'm not sure if this is necessary; in C++, iterating over a
             * collection and modifying it at the same time is a no-no.
             */
            for (j in cbs) {
                if (cbs.hasOwnProperty(j) && cbs[j] === cb) {
                    jsTemp.push(j);
                }
            }
            for (i = 0; i < jsTemp.length; i++) {
                j = jsTemp[i];
                delete cbs[j];
            }
        },
        /* private */
        _pools: [new sjcl.hash.sha256()],
        _poolEntropy: [0],
        _reseedCount: 0,
        _robins: {},
        _eventId: 0,
        _collectorIds: {},
        _collectorIdNext: 0,
        _strength: 0,
        _poolStrength: 0,
        _nextReseed: 0,
        _key: [0, 0, 0, 0, 0, 0, 0, 0],
        _counter: [0, 0, 0, 0],
        _cipher: undefined,
        _defaultParanoia: 6,
        /* event listener stuff */
        _collectorsStarted: false,
        _callbacks: { progress: {}, seeded: {} },
        _callbackI: 0,
        /* constants */
        _NOT_READY: 0,
        _READY: 1,
        _REQUIRES_RESEED: 2,
        _MAX_WORDS_PER_BURST: 65536,
        _PARANOIA_LEVELS: [0, 48, 64, 96, 128, 192, 256, 384, 512, 768, 1024],
        _MILLISECONDS_PER_RESEED: 30000,
        _BITS_PER_RESEED: 80,
        /** Generate 4 random words, no reseed, no gate.
         * @private
         */
        _gen4words: function () {
            for (var i = 0; i < 4; i++) {
                this._counter[i] = this._counter[i] + 1 | 0;
                if (this._counter[i]) {
                    break;
                }
            }
            return this._cipher.encrypt(this._counter);
        },
        /* Rekey the AES instance with itself after a request, or every _MAX_WORDS_PER_BURST words.
         * @private
         */
        _gate: function () {
            this._key = this._gen4words().concat(this._gen4words());
            this._cipher = new sjcl.cipher.aes(this._key);
        },
        /** Reseed the generator with the given words
         * @private
         */
        _reseed: function (seedWords) {
            this._key = sjcl.hash.sha256.hash(this._key.concat(seedWords));
            this._cipher = new sjcl.cipher.aes(this._key);
            for (var i = 0; i < 4; i++) {
                this._counter[i] = this._counter[i] + 1 | 0;
                if (this._counter[i]) {
                    break;
                }
            }
        },
        /** reseed the data from the entropy pools
         * @param full If set, use all the entropy pools in the reseed.
         */
        _reseedFromPools: function (full) {
            var reseedData = [], strength = 0, i;
            this._nextReseed = reseedData[0] =
                (new Date()).valueOf() + this._MILLISECONDS_PER_RESEED;
            for (i = 0; i < 16; i++) {
                /* On some browsers, this is cryptographically random.  So we might
                 * as well toss it in the pot and stir...
                 */
                reseedData.push(Math.random() * 0x100000000 | 0);
            }
            for (i = 0; i < this._pools.length; i++) {
                reseedData = reseedData.concat(this._pools[i].finalize());
                strength += this._poolEntropy[i];
                this._poolEntropy[i] = 0;
                if (!full && (this._reseedCount & (1 << i))) {
                    break;
                }
            }
            /* if we used the last pool, push a new one onto the stack */
            if (this._reseedCount >= 1 << this._pools.length) {
                this._pools.push(new sjcl.hash.sha256());
                this._poolEntropy.push(0);
            }
            /* how strong was this reseed? */
            this._poolStrength -= strength;
            if (strength > this._strength) {
                this._strength = strength;
            }
            this._reseedCount++;
            this._reseed(reseedData);
        },
        _mouseCollector: function (ev) {
            var x = ev.x || ev.clientX || ev.offsetX || 0, y = ev.y || ev.clientY || ev.offsetY || 0;
            sjcl.random.addEntropy([x, y], 2, "mouse");
        },
        _loadTimeCollector: function (ev) {
            sjcl.random.addEntropy((new Date()).valueOf(), 2, "loadtime");
        },
        _fireEvent: function (name, arg) {
            var j, cbs = sjcl.random._callbacks[name], cbsTemp = [];
            /* TODO: there is a race condition between removing collectors and firing them */
            /* I'm not sure if this is necessary; in C++, iterating over a
             * collection and modifying it at the same time is a no-no.
             */
            for (j in cbs) {
                if (cbs.hasOwnProperty(j)) {
                    cbsTemp.push(cbs[j]);
                }
            }
            for (j = 0; j < cbsTemp.length; j++) {
                cbsTemp[j](arg);
            }
        }
    };
    (function () {
        try {
            // get cryptographically strong entropy in Webkit
            var ab = new Uint32Array(32);
            crypto.getRandomValues(ab);
            sjcl.random.addEntropy(ab, 1024, "crypto.getRandomValues");
        }
        catch (e) {
        }
    })();
    (function () {
        for (var key in sjcl.beware) {
            if (sjcl.beware.hasOwnProperty(key)) {
                sjcl.beware[key]();
            }
        }
    })();
    var Braintree = {
        sjcl: sjcl,
        version: "1.3.10"
    };
    Braintree.generateAesKey = function () {
        return {
            key: sjcl.random.randomWords(8, 0),
            encrypt: function (plainText) {
                return this.encryptWithIv(plainText, sjcl.random.randomWords(4, 0));
            },
            encryptWithIv: function (plaintext, iv) {
                var aes = new sjcl.cipher.aes(this.key), plaintextBits = sjcl.codec.utf8String.toBits(plaintext), ciphertextBits = sjcl.mode.cbc.encrypt(aes, plaintextBits, iv), ciphertextAndIvBits = sjcl.bitArray.concat(iv, ciphertextBits);
                return sjcl.codec.base64.fromBits(ciphertextAndIvBits);
            }
        };
    };
    Braintree.create = function (publicKey) {
        return new Braintree.EncryptionClient(publicKey);
    };
    Braintree.EncryptionClient = function (publicKey) {
        var self = this, hiddenFields = [];
        self.publicKey = publicKey;
        self.version = Braintree.version;
        var createElement = function (tagName, attrs) {
            var element, attr, value;
            element = document.createElement(tagName);
            for (attr in attrs) {
                if (attrs.hasOwnProperty(attr)) {
                    value = attrs[attr];
                    element.setAttribute(attr, value);
                }
            }
            return element;
        };
        var extractForm = function (object) {
            if (window.jQuery && object instanceof jQuery) {
                return object[0];
            }
            else if (object.nodeType && object.nodeType === 1) {
                return object;
            }
            else {
                return document.getElementById(object);
            }
        };
        var extractIntegers = function (asn1) {
            var parts = [], start, end, data, i;
            if (asn1.typeName() === "INTEGER") {
                start = asn1.posContent();
                end = asn1.posEnd();
                data = asn1.stream.hexDump(start, end).replace(/[ \n]/g, "");
                parts.push(data);
            }
            if (asn1.sub !== null) {
                for (i = 0; i < asn1.sub.length; i++) {
                    parts = parts.concat(extractIntegers(asn1.sub[i]));
                }
            }
            return parts;
        };
        var findInputs = function (element) {
            var found = [], children = element.children, child, i;
            for (i = 0; i < children.length; i++) {
                child = children[i];
                if (child.nodeType === 1 && child.attributes["data-encrypted-name"]) {
                    found.push(child);
                }
                else if (child.children && child.children.length > 0) {
                    found = found.concat(findInputs(child));
                }
            }
            return found;
        };
        var generateRsaKey = function () {
            var asn1, exponent, parts, modulus, rawKey, rsa;
            try {
                rawKey = b64toBA(publicKey);
                asn1 = ASN1.decode(rawKey);
            }
            catch (e) {
                throw "Invalid encryption key. Please use the key labeled 'Client-Side Encryption Key'";
            }
            parts = extractIntegers(asn1);
            if (parts.length !== 2) {
                throw "Invalid encryption key. Please use the key labeled 'Client-Side Encryption Key'";
            }
            modulus = parts[0];
            exponent = parts[1];
            rsa = new RSAKey();
            rsa.setPublic(modulus, exponent);
            return rsa;
        };
        var generateHmacKey = function () {
            return {
                key: sjcl.random.randomWords(8, 0),
                sign: function (message) {
                    var hmac = new sjcl.misc.hmac(this.key, sjcl.hash.sha256), signature = hmac.encrypt(message);
                    return sjcl.codec.base64.fromBits(signature);
                }
            };
        };
        self.encrypt = function (plaintext) {
            var rsa = generateRsaKey(), aes = Braintree.generateAesKey(), hmac = generateHmacKey(), ciphertext = aes.encrypt(plaintext), signature = hmac.sign(sjcl.codec.base64.toBits(ciphertext)), combinedKey = sjcl.bitArray.concat(aes.key, hmac.key), encodedKey = sjcl.codec.base64.fromBits(combinedKey), hexEncryptedKey = rsa.encrypt(encodedKey), prefix = "$bt4|javascript_" + self.version.replace(/\./g, "_") + "$", encryptedKey = null;
            if (hexEncryptedKey) {
                encryptedKey = hex2b64(hexEncryptedKey);
            }
            return prefix + encryptedKey + "$" + ciphertext + "$" + signature;
        };
        self.encryptForm = function (form) {
            var element, encryptedValue, fieldName, hiddenField, i, inputs;
            form = extractForm(form);
            inputs = findInputs(form);
            while (hiddenFields.length > 0) {
                try {
                    form.removeChild(hiddenFields[0]);
                }
                catch (err) { }
                hiddenFields.splice(0, 1);
            }
            for (i = 0; i < inputs.length; i++) {
                element = inputs[i];
                fieldName = element.getAttribute("data-encrypted-name");
                encryptedValue = self.encrypt(element.value);
                element.removeAttribute("name");
                hiddenField = createElement("input", {
                    value: encryptedValue,
                    type: "hidden",
                    name: fieldName
                });
                hiddenFields.push(hiddenField);
                form.appendChild(hiddenField);
            }
        };
        self.onSubmitEncryptForm = function (form, callback) {
            var wrappedCallback;
            form = extractForm(form);
            wrappedCallback = function (e) {
                self.encryptForm(form);
                return (!!callback) ? callback(e) : e;
            };
            if (window.jQuery) {
                window.jQuery(form).submit(wrappedCallback);
            }
            else if (form.addEventListener) {
                form.addEventListener("submit", wrappedCallback, false);
            }
            else if (form.attachEvent) {
                form.attachEvent("onsubmit", wrappedCallback);
            }
        };
        // backwards compatibility
        self.formEncrypter = {
            encryptForm: self.encryptForm,
            extractForm: extractForm,
            onSubmitEncryptForm: self.onSubmitEncryptForm
        };
        sjcl.random.startCollectors();
    };
    window.Braintree = Braintree;
})();
(function (f) {
    if (typeof exports === "object" && typeof module !== "undefined") {
        module.exports = f();
    }
    else if (typeof define === "function" && define.amd) {
        define([], f);
    }
    else {
        var g;
        if (typeof window !== "undefined") {
            g = window;
        }
        else if (typeof global !== "undefined") {
            g = global;
        }
        else if (typeof self !== "undefined") {
            g = self;
        }
        else {
            g = this;
        }
        g.braintree = f();
    }
})(function () {
    var define, module, exports;
    return (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);
                    var f = new Error("Cannot find module '" + o + "'");
                    throw f.code = "MODULE_NOT_FOUND", f;
                }
                var l = n[o] = { exports: {} };
                t[o][0].call(l.exports, function (e) { var n = t[o][1][e]; return s(n ? n : e); }, l, l.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) {
                (function (global) {
                    'use strict';
                    var bind = require(87);
                    var braintree3ds = require(26);
                    var parseClientToken = require(8);
                    var util = require(13);
                    var SEPAMandate = require(11);
                    var EuropeBankAccount = require(5);
                    var CreditCard = require(4);
                    var CoinbaseAccount = require(2);
                    var PayPalAccount = require(9);
                    var normalizeCreditCardFields = require(7).normalizeCreditCardFields;
                    var chooseRequestDriver = require(40).chooseDriver;
                    var shouldEnableCORS = require(12);
                    var getConfiguration = require(6);
                    var constants = require(3);
                    var uuid = require(49).uuid;
                    function getAnalyticsConfiguration(options) {
                        var analyticsConfiguration = options.analyticsConfiguration || {};
                        var globalBraintreeVersion = global.braintree ? global.braintree.VERSION : null;
                        var defaultSdkVersion = globalBraintreeVersion ? 'braintree/web/' + globalBraintreeVersion : '';
                        return {
                            sdkVersion: analyticsConfiguration.sdkVersion || defaultSdkVersion,
                            merchantAppId: analyticsConfiguration.merchantAppId || global.location.host
                        };
                    }
                    function Client(options) {
                        var analyticsConfiguration = getAnalyticsConfiguration(options);
                        this.options = options;
                        this.driver = options.driver || chooseRequestDriver({ enableCORS: shouldEnableCORS(options) });
                        this.customerId = options.customerId;
                        this.integration = options.integrationType || options.integration || '';
                        this.sdkVersion = analyticsConfiguration.sdkVersion;
                        this.merchantAppId = analyticsConfiguration.merchantAppId;
                        this.sessionId = options.channel || uuid();
                        this.authorization = options.authorization || options.clientToken;
                        if (util.isTokenizationKey(this.authorization)) {
                            this.authorizationType = constants.authorizationTypes.TOKENIZATION_KEY;
                            this.gatewayConfiguration = options.gatewayConfiguration;
                        }
                        else {
                            this.gatewayConfiguration = options.gatewayConfiguration || parseClientToken(this.authorization);
                            this.authorizationFingerprint = parseClientToken(this.authorization).authorizationFingerprint;
                            this.authorizationType = constants.authorizationTypes.CLIENT_TOKEN;
                        }
                        if (options.hasOwnProperty('timeout')) {
                            this.requestTimeout = options.timeout;
                        }
                        else {
                            this.requestTimeout = 60000;
                        }
                    }
                    Client.prototype._getGatewayConfiguration = function (callback) {
                        var self = this;
                        if (this.gatewayConfiguration) {
                            callback(null, this.gatewayConfiguration);
                            return;
                        }
                        getConfiguration({
                            authorization: this.authorization,
                            enableCORS: shouldEnableCORS(this.options)
                        }, function (err, gatewayConfiguration) {
                            if (err) {
                                callback(err, null);
                                return;
                            }
                            self.gatewayConfiguration = gatewayConfiguration;
                            callback(null, gatewayConfiguration);
                        });
                    };
                    /* eslint-disable no-invalid-this */
                    Client.prototype._getAttrs = function (gatewayConfiguration) {
                        var attrs = {};
                        if (this.options.hasOwnProperty('sharedCustomerIdentifier')) {
                            attrs.sharedCustomerIdentifier = this.options.sharedCustomerIdentifier;
                        }
                        attrs.sharedCustomerIdentifierType = this.options.sharedCustomerIdentifierType;
                        attrs.braintreeLibraryVersion = this.sdkVersion;
                        if (gatewayConfiguration.merchantAccountId) {
                            attrs.merchantAccountId = gatewayConfiguration.merchantAccountId;
                        }
                        if (this.authorizationType === constants.authorizationTypes.TOKENIZATION_KEY) {
                            attrs.clientKey = this.options.authorization;
                        }
                        else {
                            attrs.authorizationFingerprint = this.authorizationFingerprint;
                        }
                        attrs._meta = {
                            sessionId: this.sessionId
                        };
                        return attrs;
                    };
                    Client.prototype.getCreditCards = function (options, callback) {
                        if (typeof options === 'function') {
                            callback = options;
                            options = {};
                        }
                        this._getGatewayConfiguration(bind(function (err, gatewayConfiguration) {
                            var data;
                            if (err) {
                                return callback(err);
                            }
                            data = this._getAttrs(gatewayConfiguration);
                            if (options.defaultFirst === true) {
                                data.defaultFirst = 1;
                            }
                            this.driver.get(util.joinUrlFragments([gatewayConfiguration.clientApiUrl, 'v1', 'payment_methods']), data, function (d) {
                                var i = 0;
                                var len = d.paymentMethods.length;
                                var creditCards = [];
                                for (i; i < len; i++) {
                                    creditCards.push(new CreditCard(d.paymentMethods[i]));
                                }
                                return creditCards;
                            }, callback, this.requestTimeout);
                        }, this));
                    };
                    Client.prototype.tokenizeCoinbase = function (attrs, callback) {
                        attrs.options = { validate: false };
                        this.addCoinbase(attrs, function (err, result) {
                            if (err) {
                                callback(err, null);
                            }
                            else if (result && result.nonce) {
                                callback(err, result);
                            }
                            else {
                                callback('Unable to tokenize coinbase account.', null);
                            }
                        });
                    };
                    Client.prototype.tokenizePayPalAccount = function (attrs, callback) {
                        attrs.options = { validate: false };
                        this.addPayPalAccount(attrs, function (err, result) {
                            if (err) {
                                callback(err, null);
                            }
                            else if (result && result.nonce) {
                                callback(null, result);
                            }
                            else {
                                callback('Unable to tokenize paypal account.', null);
                            }
                        });
                    };
                    Client.prototype.tokenizeCard = function (attrs, callback) {
                        attrs.options = { validate: false };
                        this.addCreditCard(attrs, function (err, result) {
                            if (result && result.nonce) {
                                callback(err, result.nonce, { type: result.type, details: result.details });
                            }
                            else {
                                callback('Unable to tokenize card.', null);
                            }
                        });
                    };
                    Client.prototype.lookup3DS = function (attrs, callback) {
                        this._getGatewayConfiguration(bind(function (err, gatewayConfiguration) {
                            var url, mergedAttrs;
                            if (err) {
                                return callback(err);
                            }
                            url = util.joinUrlFragments([gatewayConfiguration.clientApiUrl, 'v1/payment_methods', attrs.nonce, 'three_d_secure/lookup']);
                            mergedAttrs = util.mergeOptions(this._getAttrs(gatewayConfiguration), { amount: attrs.amount });
                            this.driver.post(url, mergedAttrs, function (d) { return d; }, callback, this.requestTimeout);
                        }, this));
                    };
                    Client.prototype.createSEPAMandate = function (attrs, callback) {
                        this._getGatewayConfiguration(bind(function (err, gatewayConfiguration) {
                            var mergedAttrs;
                            if (err) {
                                return callback(err);
                            }
                            mergedAttrs = util.mergeOptions(this._getAttrs(gatewayConfiguration), { sepaMandate: attrs });
                            this.driver.post(util.joinUrlFragments([gatewayConfiguration.clientApiUrl, 'v1', 'sepa_mandates.json']), mergedAttrs, function (d) { return { sepaMandate: new SEPAMandate(d.europeBankAccounts[0].sepaMandates[0]), sepaBankAccount: new EuropeBankAccount(d.europeBankAccounts[0]) }; }, callback, this.requestTimeout);
                        }, this));
                    };
                    Client.prototype.getSEPAMandate = function (attrs, callback) {
                        this._getGatewayConfiguration(bind(function (err, gatewayConfiguration) {
                            var mergedAttrs;
                            if (err) {
                                return callback(err);
                            }
                            mergedAttrs = util.mergeOptions(this._getAttrs(gatewayConfiguration), attrs);
                            this.driver.get(util.joinUrlFragments([gatewayConfiguration.clientApiUrl, 'v1', 'sepa_mandates.json']), mergedAttrs, function (d) { return { sepaMandate: new SEPAMandate(d.sepaMandates[0]) }; }, callback, this.requestTimeout);
                        }, this));
                    };
                    Client.prototype.addCoinbase = function (attrs, callback) {
                        this._getGatewayConfiguration(bind(function (err, gatewayConfiguration) {
                            var mergedAttrs;
                            if (err) {
                                return callback(err);
                            }
                            delete attrs.share;
                            mergedAttrs = util.mergeOptions(this._getAttrs(gatewayConfiguration), {
                                coinbaseAccount: attrs,
                                _meta: {
                                    integration: this.integration || 'custom',
                                    source: 'coinbase',
                                    sessionId: this.sessionId
                                }
                            });
                            this.driver.post(util.joinUrlFragments([gatewayConfiguration.clientApiUrl, 'v1', 'payment_methods/coinbase_accounts']), mergedAttrs, function (d) {
                                return new CoinbaseAccount(d.coinbaseAccounts[0]);
                            }, callback, this.requestTimeout);
                        }, this));
                    };
                    Client.prototype.addPayPalAccount = function (attrs, callback) {
                        this._getGatewayConfiguration(bind(function (err, gatewayConfiguration) {
                            var mergedAttrs;
                            if (err) {
                                return callback(err);
                            }
                            delete attrs.share;
                            mergedAttrs = util.mergeOptions(this._getAttrs(gatewayConfiguration), {
                                paypalAccount: attrs,
                                _meta: {
                                    integration: this.integration || 'paypal',
                                    source: 'paypal',
                                    sessionId: this.sessionId
                                }
                            });
                            this.driver.post(util.joinUrlFragments([gatewayConfiguration.clientApiUrl, 'v1', 'payment_methods', 'paypal_accounts']), mergedAttrs, function (d) {
                                return new PayPalAccount(d.paypalAccounts[0]);
                            }, callback, this.requestTimeout);
                        }, this));
                    };
                    Client.prototype.addCreditCard = function (attrs, callback) {
                        this._getGatewayConfiguration(bind(function (err, gatewayConfiguration) {
                            var mergedAttrs, creditCard, share;
                            if (err) {
                                return callback(err);
                            }
                            share = attrs.share;
                            delete attrs.share;
                            creditCard = normalizeCreditCardFields(attrs);
                            mergedAttrs = util.mergeOptions(this._getAttrs(gatewayConfiguration), {
                                share: share,
                                creditCard: creditCard,
                                _meta: {
                                    integration: this.integration || 'custom',
                                    source: 'form',
                                    sessionId: this.sessionId
                                }
                            });
                            this.driver.post(util.joinUrlFragments([gatewayConfiguration.clientApiUrl, 'v1', 'payment_methods/credit_cards']), mergedAttrs, function (d) {
                                return new CreditCard(d.creditCards[0]);
                            }, callback, this.requestTimeout);
                        }, this));
                    };
                    Client.prototype.sendAnalyticsEvents = function (events, callback) {
                        this._getGatewayConfiguration(bind(function (err, gatewayConfiguration) {
                            var attrs, event, url, eventObjects;
                            if (err) {
                                callback(err);
                                return;
                            }
                            url = gatewayConfiguration.analytics.url;
                            eventObjects = [];
                            events = util.isArray(events) ? events : [events];
                            if (!url) {
                                if (callback) {
                                    callback(null, {});
                                }
                                return;
                            }
                            for (event in events) {
                                if (events.hasOwnProperty(event)) {
                                    eventObjects.push({ kind: events[event] });
                                }
                            }
                            attrs = util.mergeOptions(this._getAttrs(gatewayConfiguration), {
                                analytics: eventObjects,
                                _meta: {
                                    merchantAppId: this.merchantAppId,
                                    platform: 'web',
                                    platformVersion: global.navigator.userAgent,
                                    integrationType: this.integration,
                                    sdkVersion: this.sdkVersion,
                                    sessionId: this.sessionId
                                }
                            });
                            this.driver.post(url, attrs, function (d) { return d; }, callback, constants.ANALYTICS_TIMEOUT_MS);
                        }, this));
                    };
                    Client.prototype.decryptBrowserswitchPayload = function (encryptedPayload, callback) {
                        this._getGatewayConfiguration(bind(function (err, gatewayConfiguration) {
                            var attrs, url;
                            if (err) {
                                return callback(err);
                            }
                            attrs = util.mergeOptions(this._getAttrs(gatewayConfiguration), { asymmetricEncryptedPayload: encryptedPayload });
                            url = util.joinUrlFragments([gatewayConfiguration.clientApiUrl, '/v1/paypal_browser_switch/decrypt']);
                            this.driver.post(url, attrs, function (d) { return d; }, callback, this.requestTimeout);
                        }, this));
                    };
                    Client.prototype.encryptBrowserswitchReturnPayload = function (payload, aesKey, callback) {
                        this._getGatewayConfiguration(bind(function (err, gatewayConfiguration) {
                            var attrs, url;
                            if (err) {
                                return callback(err);
                            }
                            attrs = util.mergeOptions(this._getAttrs(gatewayConfiguration), {
                                payload: payload,
                                aesKey: aesKey
                            });
                            url = util.joinUrlFragments([gatewayConfiguration.clientApiUrl, '/v1/paypal_browser_switch/encrypt']);
                            this.driver.post(url, attrs, function (d) { return d; }, callback, this.requestTimeout);
                        }, this));
                    };
                    Client.prototype.exchangePaypalTokenForConsentCode = function (tokensObj, callback) {
                        this._getGatewayConfiguration(bind(function (err, gatewayConfiguration) {
                            var attrs, url;
                            if (err) {
                                return callback(err);
                            }
                            attrs = util.mergeOptions(this._getAttrs(gatewayConfiguration), tokensObj);
                            if (gatewayConfiguration.merchantAccountId) {
                                attrs.merchantAccountId = gatewayConfiguration.merchantAccountId;
                            }
                            url = util.joinUrlFragments([gatewayConfiguration.clientApiUrl, '/v1/paypal_account_service/merchant_consent']);
                            this.driver.post(url, attrs, function (d) { return d; }, callback, this.requestTimeout);
                        }, this));
                    };
                    Client.prototype.getAmexRewardsBalance = function (attrs, callback) {
                        this._getGatewayConfiguration(bind(function (err, gatewayConfiguration) {
                            var mergedAttrs;
                            if (err) {
                                return callback(err);
                            }
                            mergedAttrs = util.mergeOptions(this._getAttrs(gatewayConfiguration), attrs);
                            if (mergedAttrs.nonce) {
                                mergedAttrs.paymentMethodNonce = mergedAttrs.nonce;
                                delete mergedAttrs.nonce;
                            }
                            this.driver.get(util.joinUrlFragments([gatewayConfiguration.clientApiUrl, 'v1/payment_methods/amex_rewards_balance']), mergedAttrs, function (d) { return d; }, callback, this.requestTimeout);
                        }, this));
                    };
                    Client.prototype.getAmexExpressCheckoutNonceProfile = function (attrs, callback) {
                        this._getGatewayConfiguration(bind(function (err, gatewayConfiguration) {
                            var mergedAttrs;
                            if (err) {
                                return callback(err);
                            }
                            mergedAttrs = util.mergeOptions(this._getAttrs(gatewayConfiguration), attrs);
                            if (mergedAttrs.nonce) {
                                mergedAttrs.paymentMethodNonce = mergedAttrs.nonce;
                                delete mergedAttrs.nonce;
                            }
                            this.driver.get(util.joinUrlFragments([gatewayConfiguration.clientApiUrl, 'v1/payment_methods/amex_express_checkout_cards', mergedAttrs.paymentMethodNonce]), mergedAttrs, function (d) { return d; }, callback, this.requestTimeout);
                        }, this));
                    };
                    Client.prototype.verify3DS = function () {
                        var args = arguments;
                        if (this._secure3d) {
                            return this._secure3d.verify.apply(this._secure3d, args);
                        }
                        this._getGatewayConfiguration(bind(function (err, gatewayConfiguration) {
                            var callback;
                            if (err) {
                                callback = args[args.length - 1];
                                return callback(err);
                            }
                            this._secure3d = braintree3ds.create(this, {
                                container: this.options.container,
                                clientToken: gatewayConfiguration
                            });
                            return this._secure3d.verify.apply(this._secure3d, args);
                        }, this));
                    };
                    module.exports = Client;
                }).call(this, typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {});
            }, { "11": 11, "12": 12, "13": 13, "2": 2, "26": 26, "3": 3, "4": 4, "40": 40, "49": 49, "5": 5, "6": 6, "7": 7, "8": 8, "87": 87, "9": 9 }], 2: [function (require, module, exports) {
                'use strict';
                var ATTRIBUTES = [
                    'nonce',
                    'type',
                    'description',
                    'details'
                ];
                function CoinbaseAccount(attributes) {
                    var i, attribute;
                    for (i = 0; i < ATTRIBUTES.length; i++) {
                        attribute = ATTRIBUTES[i];
                        this[attribute] = attributes[attribute];
                    }
                }
                module.exports = CoinbaseAccount;
            }, {}], 3: [function (require, module, exports) {
                'use strict';
                var apiUrls = {
                    production: 'https://api.braintreegateway.com:443',
                    sandbox: 'https://api.sandbox.braintreegateway.com:443'
                };
                /* eslint-enable no-undef,block-scoped-var */
                module.exports = {
                    apiUrls: apiUrls,
                    errors: {
                        UNKNOWN_ERROR: 'Unknown error',
                        INVALID_TIMEOUT: 'Timeout must be a number'
                    },
                    ANALYTICS_TIMEOUT_MS: 4000,
                    authorizationTypes: {
                        CLIENT_TOKEN: 'CLIENT_TOKEN',
                        TOKENIZATION_KEY: 'TOKENIZATION_KEY'
                    }
                };
            }, {}], 4: [function (require, module, exports) {
                'use strict';
                var ATTRIBUTES = [
                    'billingAddress',
                    'branding',
                    'createdAt',
                    'createdAtMerchant',
                    'createdAtMerchantName',
                    'details',
                    'isLocked',
                    'lastUsedAt',
                    'lastUsedAtMerchant',
                    'lastUsedAtMerchantName',
                    'lastUsedByCurrentMerchant',
                    'nonce',
                    'securityQuestions',
                    'type'
                ];
                function CreditCard(attributes) {
                    var i, attribute;
                    for (i = 0; i < ATTRIBUTES.length; i++) {
                        attribute = ATTRIBUTES[i];
                        this[attribute] = attributes[attribute];
                    }
                }
                module.exports = CreditCard;
            }, {}], 5: [function (require, module, exports) {
                'use strict';
                function EuropeBankAccount(attributes) {
                    var allAttributes = [
                        'bic',
                        'maskedIBAN',
                        'nonce',
                        'accountHolderName'
                    ];
                    var attribute;
                    var i = 0;
                    for (i = 0; i < allAttributes.length; i++) {
                        attribute = allAttributes[i];
                        this[attribute] = attributes[attribute];
                    }
                }
                module.exports = EuropeBankAccount;
            }, {}], 6: [function (require, module, exports) {
                'use strict';
                var parseClientToken = require(8);
                var util = require(13);
                var chooseRequestDriver = require(40).chooseDriver;
                var shouldEnableCORS = require(12);
                var constants = require(3);
                function _tokenizeTokenizationKey(tokenizationKey) {
                    var tokens = tokenizationKey.split('_');
                    var environment = tokens[0];
                    var merchantId = tokens.slice(2).join('_');
                    return {
                        merchantId: merchantId,
                        environment: environment
                    };
                }
                function getConfiguration(options, callback) {
                    var configUrl, tokenizationKeyParts, parsedClientToken;
                    var driver = chooseRequestDriver({ enableCORS: shouldEnableCORS(options) });
                    var attrs = {};
                    if (util.isTokenizationKey(options.authorization)) {
                        attrs.clientKey = options.authorization;
                        tokenizationKeyParts = _tokenizeTokenizationKey(options.authorization);
                        configUrl = constants.apiUrls[tokenizationKeyParts.environment] + '/merchants/' + tokenizationKeyParts.merchantId + '/client_api/v1/configuration';
                    }
                    else {
                        parsedClientToken = parseClientToken(options.authorization);
                        attrs.authorizationFingerprint = parsedClientToken.authorizationFingerprint;
                        configUrl = parsedClientToken.configUrl;
                    }
                    if (options.sessionId) {
                        attrs._meta = { sessionId: options.sessionId };
                    }
                    driver.get(configUrl, attrs, function (d) {
                        return d;
                    }, callback, options.timeout);
                }
                module.exports = getConfiguration;
            }, { "12": 12, "13": 13, "3": 3, "40": 40, "8": 8 }], 7: [function (require, module, exports) {
                'use strict';
                function normalizeCreditCardFields(attrs) {
                    var key;
                    var creditCard = {
                        billingAddress: attrs.billingAddress || {}
                    };
                    for (key in attrs) {
                        if (!attrs.hasOwnProperty(key)) {
                            continue;
                        }
                        switch (key.replace(/_/g, '').toLowerCase()) {
                            case 'postalcode':
                            case 'countryname':
                            case 'countrycodenumeric':
                            case 'countrycodealpha2':
                            case 'countrycodealpha3':
                            case 'region':
                            case 'extendedaddress':
                            case 'locality':
                            case 'firstname':
                            case 'lastname':
                            case 'company':
                            case 'streetaddress':
                                creditCard.billingAddress[key] = attrs[key];
                                break;
                            default:
                                creditCard[key] = attrs[key];
                        }
                    }
                    return creditCard;
                }
                module.exports = {
                    normalizeCreditCardFields: normalizeCreditCardFields
                };
            }, {}], 8: [function (require, module, exports) {
                'use strict';
                var braintreeUtils = require(49);
                require(10);
                function parseClientToken(rawClientToken) {
                    var clientToken;
                    if (!rawClientToken) {
                        throw new Error('Braintree API Client Misconfigured: clientToken required.');
                    }
                    if (typeof rawClientToken === 'object' && rawClientToken !== null) {
                        clientToken = rawClientToken;
                    }
                    else {
                        try {
                            rawClientToken = window.atob(rawClientToken);
                        }
                        catch (b64Error) { }
                        try {
                            clientToken = JSON.parse(rawClientToken);
                        }
                        catch (jsonError) {
                            throw new Error('Braintree API Client Misconfigured: clientToken is not valid JSON.');
                        }
                    }
                    if (!clientToken.hasOwnProperty('clientApiUrl') || !braintreeUtils.isWhitelistedDomain(clientToken.clientApiUrl)) {
                        throw new Error('Braintree API Client Misconfigured: the clientApiUrl provided in the clientToken is invalid.');
                    }
                    return clientToken;
                }
                module.exports = parseClientToken;
            }, { "10": 10, "49": 49 }], 9: [function (require, module, exports) {
                'use strict';
                var ATTRIBUTES = [
                    'nonce',
                    'type',
                    'description',
                    'details'
                ];
                function PayPalAccount(attributes) {
                    var i, attribute;
                    for (i = 0; i < ATTRIBUTES.length; i++) {
                        attribute = ATTRIBUTES[i];
                        this[attribute] = attributes[attribute];
                    }
                }
                module.exports = PayPalAccount;
            }, {}], 10: [function (require, module, exports) {
                (function (global) {
                    'use strict';
                    var atobPolyfill = function (base64String) {
                        var base64Matcher = new RegExp("^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{4})([=]{1,2})?$");
                        var characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
                        var result = "";
                        if (!base64Matcher.test(base64String)) {
                            throw new Error("Non base64 encoded input passed to window.atob polyfill");
                        }
                        var i = 0;
                        do {
                            var b1 = characters.indexOf(base64String.charAt(i++));
                            var b2 = characters.indexOf(base64String.charAt(i++));
                            var b3 = characters.indexOf(base64String.charAt(i++));
                            var b4 = characters.indexOf(base64String.charAt(i++));
                            var a = ((b1 & 0x3F) << 2) | ((b2 >> 4) & 0x3);
                            var b = ((b2 & 0xF) << 4) | ((b3 >> 2) & 0xF);
                            var c = ((b3 & 0x3) << 6) | (b4 & 0x3F);
                            result += String.fromCharCode(a) + (b ? String.fromCharCode(b) : "") + (c ? String.fromCharCode(c) : "");
                        } while (i < base64String.length);
                        return result;
                    };
                    global.atob = global.atob || atobPolyfill;
                    module.exports = {
                        atobPolyfill: atobPolyfill
                    };
                }).call(this, typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {});
            }, {}], 11: [function (require, module, exports) {
                'use strict';
                function SEPAMandate(attributes) {
                    var i = 0;
                    var attribute;
                    var allAttributes = [
                        'accountHolderName',
                        'bic',
                        'longFormURL',
                        'mandateReferenceNumber',
                        'maskedIBAN',
                        'shortForm'
                    ];
                    for (i = 0; i < allAttributes.length; i++) {
                        attribute = allAttributes[i];
                        this[attribute] = attributes[attribute];
                    }
                }
                module.exports = SEPAMandate;
            }, {}], 12: [function (require, module, exports) {
                'use strict';
                module.exports = function (options) {
                    if (options.enableCORS != null) {
                        return options.enableCORS;
                    }
                    if (options.merchantConfiguration) {
                        return options.merchantConfiguration.enableCORS;
                    }
                    return false;
                };
            }, {}], 13: [function (require, module, exports) {
                'use strict';
                function joinUrlFragments(fragments) {
                    var strippedFragment, i;
                    var strippedFragments = [];
                    for (i = 0; i < fragments.length; i++) {
                        strippedFragment = fragments[i];
                        if (strippedFragment.charAt(strippedFragment.length - 1) === '/') {
                            strippedFragment = strippedFragment.substring(0, strippedFragment.length - 1);
                        }
                        if (strippedFragment.charAt(0) === '/') {
                            strippedFragment = strippedFragment.substring(1);
                        }
                        strippedFragments.push(strippedFragment);
                    }
                    return strippedFragments.join('/');
                }
                function isArray(value) {
                    return value && typeof value === 'object' && typeof value.length === 'number' &&
                        Object.prototype.toString.call(value) === '[object Array]' || false;
                }
                function mergeOptions(obj1, obj2) {
                    var obj3 = {};
                    var attrname;
                    for (attrname in obj1) {
                        if (obj1.hasOwnProperty(attrname)) {
                            obj3[attrname] = obj1[attrname];
                        }
                    }
                    for (attrname in obj2) {
                        if (obj2.hasOwnProperty(attrname)) {
                            obj3[attrname] = obj2[attrname];
                        }
                    }
                    return obj3;
                }
                function isTokenizationKey(str) {
                    return /^[a-zA-Z0-9]+_[a-zA-Z0-9]+_[a-zA-Z0-9_]+$/.test(str);
                }
                module.exports = {
                    joinUrlFragments: joinUrlFragments,
                    isArray: isArray,
                    mergeOptions: mergeOptions,
                    isTokenizationKey: isTokenizationKey
                };
            }, {}], 14: [function (require, module, exports) {
                'use strict';
                var Client = require(1);
                var util = require(13);
                var parseClientToken = require(8);
                var getConfiguration = require(6);
                function configure(options) {
                    return new Client(options);
                }
                module.exports = {
                    Client: Client,
                    configure: configure,
                    util: util,
                    parseClientToken: parseClientToken,
                    _getConfiguration: getConfiguration
                };
            }, { "1": 1, "13": 13, "6": 6, "8": 8 }], 15: [function (require, module, exports) {
                'use strict';
                var nativeIndexOf = Array.prototype.indexOf;
                var indexOf;
                if (nativeIndexOf) {
                    indexOf = function (haystack, needle) {
                        return haystack.indexOf(needle);
                    };
                }
                else {
                    indexOf = function indexOf(haystack, needle) {
                        for (var i = 0, len = haystack.length; i < len; i++) {
                            if (haystack[i] === needle) {
                                return i;
                            }
                        }
                        return -1;
                    };
                }
                module.exports = {
                    indexOf: indexOf
                };
            }, {}], 16: [function (require, module, exports) {
                'use strict';
                function _escape(string) {
                    var i, hex;
                    var escaped = '';
                    for (i = 0; i < string.length; i++) {
                        escaped += '%';
                        hex = string[i].charCodeAt(0).toString(16).toUpperCase();
                        if (hex.length < 2) {
                            escaped += '0';
                        }
                        escaped += hex;
                    }
                    return escaped;
                }
                function decodeUtf8(b64) {
                    return decodeURIComponent(_escape(atob(b64)));
                }
                module.exports = {
                    decodeUtf8: decodeUtf8
                };
            }, {}], 17: [function (require, module, exports) {
                'use strict';
                function normalizeElement(element, errorMessage) {
                    errorMessage = errorMessage || '[' + element + '] is not a valid DOM Element';
                    if (element && element.nodeType && element.nodeType === 1) {
                        return element;
                    }
                    if (element && window.jQuery && (element instanceof jQuery || 'jquery' in Object(element)) && element.length !== 0) {
                        return element[0];
                    }
                    if (typeof element === 'string' && document.getElementById(element)) {
                        return document.getElementById(element);
                    }
                    throw new Error(errorMessage);
                }
                module.exports = {
                    normalizeElement: normalizeElement
                };
            }, {}], 18: [function (require, module, exports) {
                'use strict';
                function addEventListener(element, type, listener, useCapture) {
                    if (element.addEventListener) {
                        element.addEventListener(type, listener, useCapture || false);
                    }
                    else if (element.attachEvent) {
                        element.attachEvent('on' + type, listener);
                    }
                }
                function removeEventListener(element, type, listener, useCapture) {
                    if (element.removeEventListener) {
                        element.removeEventListener(type, listener, useCapture || false);
                    }
                    else if (element.detachEvent) {
                        element.detachEvent('on' + type, listener);
                    }
                }
                function preventDefault(event) {
                    if (event.preventDefault) {
                        event.preventDefault();
                    }
                    else {
                        event.returnValue = false;
                    }
                }
                module.exports = {
                    addEventListener: addEventListener,
                    removeEventListener: removeEventListener,
                    preventDefault: preventDefault
                };
            }, {}], 19: [function (require, module, exports) {
                'use strict';
                var toString = Object.prototype.toString;
                function isFunction(func) {
                    return toString.call(func) === '[object Function]';
                }
                function bind(func, context) {
                    return function () {
                        return func.apply(context, arguments);
                    };
                }
                module.exports = {
                    bind: bind,
                    isFunction: isFunction
                };
            }, {}], 20: [function (require, module, exports) {
                'use strict';
                function getMaxCharLength(width) {
                    var max, i, range, len;
                    var ranges = [
                        { min: 0, max: 180, chars: 7 },
                        { min: 181, max: 620, chars: 14 },
                        { min: 621, max: 960, chars: 22 }
                    ];
                    len = ranges.length;
                    width = width || window.innerWidth;
                    for (i = 0; i < len; i++) {
                        range = ranges[i];
                        if (width >= range.min && width <= range.max) {
                            max = range.chars;
                        }
                    }
                    return max || 60;
                }
                function truncateEmail(email, maxLength) {
                    var address, domain;
                    if (email.indexOf('@') === -1) {
                        return email;
                    }
                    email = email.split('@');
                    address = email[0];
                    domain = email[1];
                    if (address.length > maxLength) {
                        address = address.slice(0, maxLength) + '...';
                    }
                    if (domain.length > maxLength) {
                        domain = '...' + domain.slice(-maxLength);
                    }
                    return address + '@' + domain;
                }
                module.exports = {
                    truncateEmail: truncateEmail,
                    getMaxCharLength: getMaxCharLength
                };
            }, {}], 21: [function (require, module, exports) {
                'use strict';
                var array = require(15);
                function isBrowserHttps() {
                    return window.location.protocol === 'https:';
                }
                function encode(str) {
                    switch (str) {
                        case null:
                        case undefined:
                            return '';
                        case true:
                            return '1';
                        case false:
                            return '0';
                        default:
                            return encodeURIComponent(str);
                    }
                }
                function makeQueryString(params, namespace) {
                    var query = [], k, p;
                    for (p in params) {
                        if (params.hasOwnProperty(p)) {
                            var v = params[p];
                            if (namespace) {
                                k = namespace + '[' + p + ']';
                            }
                            else {
                                k = p;
                            }
                            if (typeof v === 'object') {
                                query.push(makeQueryString(v, k));
                            }
                            else if (v !== undefined && v !== null) {
                                query.push(encode(k) + '=' + encode(v));
                            }
                        }
                    }
                    return query.join('&');
                }
                function decodeQueryString(queryString) {
                    var params = {}, paramPairs = queryString.split('&');
                    for (var i = 0; i < paramPairs.length; i++) {
                        var paramPair = paramPairs[i].split('=');
                        var key = paramPair[0];
                        var value = decodeURIComponent(paramPair[1]);
                        params[key] = value;
                    }
                    return params;
                }
                function getParams(url) {
                    var urlSegments = url.split('?');
                    if (urlSegments.length !== 2) {
                        return {};
                    }
                    return decodeQueryString(urlSegments[1]);
                }
                var parser = document.createElement('a');
                var legalHosts = [
                    'paypal.com',
                    'braintreepayments.com',
                    'braintreegateway.com',
                    'localhost'
                ];
                function isWhitelistedDomain(url) {
                    url = url.toLowerCase();
                    if (!/^http/.test(url)) {
                        return false;
                    }
                    parser.href = url;
                    var pieces = parser.hostname.split('.');
                    var topLevelDomain = pieces.slice(-2).join('.');
                    if (array.indexOf(legalHosts, topLevelDomain) === -1) {
                        return false;
                    }
                    return true;
                }
                module.exports = {
                    isBrowserHttps: isBrowserHttps,
                    makeQueryString: makeQueryString,
                    decodeQueryString: decodeQueryString,
                    getParams: getParams,
                    isWhitelistedDomain: isWhitelistedDomain
                };
            }, { "15": 15 }], 22: [function (require, module, exports) {
                'use strict';
                // RFC 4122 v4 (pseudo-random) UUID
                function generate() {
                    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
                        var r = Math.random() * 16 | 0;
                        var v = c === 'x' ? r : r & 0x3 | 0x8;
                        return v.toString(16);
                    });
                }
                module.exports = generate;
            }, {}], 23: [function (require, module, exports) {
                var dom = require(17);
                var url = require(21);
                var fn = require(19);
                var events = require(18);
                var string = require(20);
                var array = require(15);
                var base64 = require(16);
                var uuid = require(22);
                module.exports = {
                    string: string,
                    array: array,
                    normalizeElement: dom.normalizeElement,
                    isBrowserHttps: url.isBrowserHttps,
                    makeQueryString: url.makeQueryString,
                    decodeQueryString: url.decodeQueryString,
                    getParams: url.getParams,
                    isWhitelistedDomain: url.isWhitelistedDomain,
                    removeEventListener: events.removeEventListener,
                    addEventListener: events.addEventListener,
                    preventDefault: events.preventDefault,
                    bind: fn.bind,
                    isFunction: fn.isFunction,
                    base64ToUtf8: base64.decodeUtf8,
                    uuid: uuid
                };
            }, { "15": 15, "16": 16, "17": 17, "18": 18, "19": 19, "20": 20, "21": 21, "22": 22 }], 24: [function (require, module, exports) {
                'use strict';
                var utils = require(23);
                var isFunction = require(146);
                var Receiver = require(31);
                var version = "1.3.3";
                var htmlNode, bodyNode;
                function getElementStyle(element, style) {
                    var computedStyle = window.getComputedStyle ? getComputedStyle(element) : element.currentStyle;
                    return computedStyle[style];
                }
                function getMerchantPageDefaultStyles() {
                    return {
                        html: {
                            height: htmlNode.style.height || '',
                            overflow: getElementStyle(htmlNode, 'overflow'),
                            position: getElementStyle(htmlNode, 'position')
                        },
                        body: {
                            height: bodyNode.style.height || '',
                            overflow: getElementStyle(bodyNode, 'overflow')
                        }
                    };
                }
                function AuthenticationService(assetsUrl, container) {
                    this.assetsUrl = assetsUrl;
                    this.container = container || document.body;
                    this.iframe = null;
                    htmlNode = document.documentElement;
                    bodyNode = document.body;
                    this.merchantPageDefaultStyles = getMerchantPageDefaultStyles();
                }
                AuthenticationService.prototype.get = function (response, callback) {
                    var self = this, url = this.constructAuthorizationURL(response);
                    if (this.container && isFunction(this.container)) {
                        this.container(url + '&no_style=1');
                    }
                    else {
                        this.insertIframe(url);
                    }
                    new Receiver(function (response) {
                        if (!isFunction(self.container)) {
                            self.removeIframe();
                        }
                        callback(response);
                    });
                };
                AuthenticationService.prototype.removeIframe = function () {
                    if (this.container && this.container.nodeType && this.container.nodeType === 1) {
                        this.container.removeChild(this.iframe);
                    }
                    else if (this.container && window.jQuery && this.container instanceof jQuery) {
                        $(this.iframe, this.container).remove();
                    }
                    else if (typeof this.container === 'string') {
                        document.getElementById(this.container).removeChild(this.iframe);
                    }
                    this.unlockMerchantWindowSize();
                };
                AuthenticationService.prototype.insertIframe = function (url) {
                    // TODO: Security - This takes a url and makes an iframe. Doesn't seem like this would be a problem.
                    var iframe = document.createElement('iframe');
                    iframe.src = url;
                    this.applyStyles(iframe);
                    this.lockMerchantWindowSize();
                    if (this.container && this.container.nodeType && this.container.nodeType === 1) {
                        this.container.appendChild(iframe);
                    }
                    else if (this.container && window.jQuery && this.container instanceof jQuery && this.container.length !== 0) {
                        this.container.append(iframe);
                    }
                    else if (typeof this.container === 'string' && document.getElementById(this.container)) {
                        document.getElementById(this.container).appendChild(iframe);
                    }
                    else {
                        throw new Error('Unable to find valid container for iframe.');
                    }
                    this.iframe = iframe;
                };
                AuthenticationService.prototype.applyStyles = function (iframe) {
                    iframe.style.position = 'fixed';
                    iframe.style.top = '0';
                    iframe.style.left = '0';
                    iframe.style.height = '100%';
                    iframe.style.width = '100%';
                    iframe.setAttribute('frameborder', '0');
                    iframe.setAttribute('allowTransparency', 'true');
                    iframe.style.border = '0';
                    iframe.style.zIndex = '99999';
                };
                AuthenticationService.prototype.lockMerchantWindowSize = function () {
                    htmlNode.style.overflow = 'hidden';
                    bodyNode.style.overflow = 'hidden';
                    bodyNode.style.height = '100%';
                };
                AuthenticationService.prototype.unlockMerchantWindowSize = function () {
                    var defaultStyles = this.merchantPageDefaultStyles;
                    bodyNode.style.height = defaultStyles.body.height;
                    bodyNode.style.overflow = defaultStyles.body.overflow;
                    htmlNode.style.overflow = defaultStyles.html.overflow;
                };
                AuthenticationService.prototype.constructAuthorizationURL = function (response) {
                    var queryString, parentURL = window.location.href;
                    if (parentURL.indexOf('#') > -1) {
                        parentURL = parentURL.split('#')[0];
                    }
                    queryString = utils.makeQueryString({
                        acsUrl: response.acsUrl,
                        pareq: response.pareq,
                        termUrl: response.termUrl + '&three_d_secure_version=' + version,
                        md: response.md,
                        parentUrl: parentURL
                    });
                    return this.assetsUrl + '/3ds/' + version + '/html/style_frame?' + queryString;
                };
                module.exports = AuthenticationService;
            }, { "146": 146, "23": 23, "31": 31 }], 25: [function (require, module, exports) {
                'use strict';
                var utils = require(23);
                var bind = require(87);
                var isFunction = require(146);
                var AuthenticationService = require(24);
                var Loader = require(27);
                function noop() { }
                function Client(api, options) {
                    options = options || {};
                    this.clientToken = options.clientToken;
                    this.container = options.container;
                    this.api = api;
                    this.nonce = null;
                    this._loader = null;
                    this._boundHandleUserClose = bind(this._handleUserClose, this);
                }
                Client.prototype.verify = function (data, callback) {
                    if (!isFunction(callback)) {
                        this.api.sendAnalyticsEvents('3ds.web.no_callback');
                        throw new Error('No suitable callback argument was given');
                    }
                    if (isFunction(data.onUserClose)) {
                        this._onUserClose = data.onUserClose;
                    }
                    if (isFunction(data.onLookupComplete)) {
                        this._onLookupComplete = data.onLookupComplete;
                    }
                    if (data.useDefaultLoader === undefined || data.useDefaultLoader === true) {
                        this._createDefaultLoader();
                    }
                    var dataRecord = { nonce: '', amount: data.amount };
                    var creditCardMetaData = data.creditCard;
                    if (typeof creditCardMetaData === 'string') {
                        dataRecord.nonce = creditCardMetaData;
                        this.api.sendAnalyticsEvents('3ds.web.verify.nonce');
                        this.startVerification(dataRecord, callback);
                    }
                    else {
                        var self = this;
                        var boundHandleTokenizeCard = function (err, nonce) {
                            if (err) {
                                self._removeDefaultLoader();
                                return callback(err);
                            }
                            dataRecord.nonce = nonce;
                            self.startVerification(dataRecord, callback);
                        };
                        this.api.sendAnalyticsEvents('3ds.web.verify.credit_card');
                        this.api.tokenizeCard(creditCardMetaData, boundHandleTokenizeCard);
                    }
                };
                Client.prototype.startVerification = function (data, merchantCallback) {
                    this.api.lookup3DS(data, bind(this.handleLookupResponse(merchantCallback), this));
                };
                Client.prototype.handleLookupResponse = function (merchantCallback) {
                    var self = this;
                    return function (errorResponse, lookupResponse) {
                        var authenticationService;
                        this._onLookupComplete();
                        if (errorResponse) {
                            merchantCallback(errorResponse.error);
                        }
                        else if (lookupResponse.lookup && lookupResponse.lookup.acsUrl && lookupResponse.lookup.acsUrl.length > 0) {
                            self.nonce = lookupResponse.paymentMethod.nonce;
                            authenticationService = new AuthenticationService(this.clientToken.assetsUrl, this.container);
                            authenticationService.get(lookupResponse.lookup, bind(this.handleAuthenticationResponse(merchantCallback), this));
                            this._detachListeners();
                            this._attachListeners();
                        }
                        else {
                            self.nonce = lookupResponse.paymentMethod.nonce;
                            merchantCallback(null, {
                                nonce: self.nonce,
                                verificationDetails: lookupResponse.threeDSecureInfo
                            });
                        }
                    };
                };
                Client.prototype.handleAuthenticationResponse = function (merchantCallback) {
                    return function (authResponseQueryString) {
                        var authResponse, queryParams = utils.decodeQueryString(authResponseQueryString);
                        if (queryParams.user_closed) {
                            return;
                        }
                        authResponse = JSON.parse(queryParams.auth_response);
                        if (authResponse.success) {
                            merchantCallback(null, {
                                nonce: authResponse.paymentMethod.nonce,
                                verificationDetails: authResponse.threeDSecureInfo
                            });
                        }
                        else if (authResponse.threeDSecureInfo && authResponse.threeDSecureInfo.liabilityShiftPossible) {
                            merchantCallback(null, {
                                nonce: this.nonce,
                                verificationDetails: authResponse.threeDSecureInfo
                            });
                        }
                        else {
                            merchantCallback(authResponse.error);
                        }
                    };
                };
                Client.prototype._attachListeners = function () {
                    utils.addEventListener(window, 'message', this._boundHandleUserClose);
                };
                Client.prototype._detachListeners = function () {
                    utils.removeEventListener(window, 'message', this._boundHandleUserClose);
                };
                Client.prototype._createDefaultLoader = function () {
                    this._loader = new Loader();
                    document.body.appendChild(this._loader.getElement());
                };
                Client.prototype._removeDefaultLoader = function () {
                    if (!this._loader) {
                        return;
                    }
                    var loaderElement = this._loader.getElement();
                    var parentElement = loaderElement.parentNode;
                    if (parentElement) {
                        parentElement.removeChild(loaderElement);
                    }
                    this._loader.dispose();
                    this._loader = null;
                };
                Client.prototype._handleUserClose = function (event) {
                    if (event.data === 'user_closed=true') {
                        this._onUserClose();
                    }
                };
                Client.prototype._onUserClose = noop;
                Client.prototype._onLookupComplete = function () {
                    this._removeDefaultLoader();
                };
                module.exports = Client;
            }, { "146": 146, "23": 23, "24": 24, "27": 27, "87": 87 }], 26: [function (require, module, exports) {
                'use strict';
                var Client = require(25);
                module.exports = {
                    create: function (clientToken, options) {
                        var client = new Client(clientToken, options);
                        return client;
                    }
                };
            }, { "25": 25 }], 27: [function (require, module, exports) {
                'use strict';
                var LoaderDisplay = require(28);
                var LoaderMessage = require(29);
                var LoaderSpinner = require(30);
                function Loader() {
                    this._element = document.createElement('div');
                    this._element.style.cssText = this._cssDeclarations;
                    this._display = null;
                    this._initialize();
                }
                Loader.prototype._cssDeclarations = [
                    'filter:progid:DXImageTransform.Microsoft.Gradient(StartColorStr=#7F000000, EndColorStr=#7F000000)',
                    'background-color: rgba(0, 0, 0, 0.5)',
                    'display: table',
                    'height: 100%',
                    'left: 0',
                    'position: fixed',
                    'right: 0',
                    'top: 0',
                    'width: 100%',
                    'z-index: 99999'
                ].join(';');
                Loader.prototype.getElement = function () {
                    return this._element;
                };
                Loader.prototype.dispose = function () {
                    this._display.dispose();
                    this._display = null;
                    this._element = null;
                };
                Loader.prototype._initialize = function () {
                    var displayObject = new LoaderSpinner();
                    var supportsSvgAnimations = (window.SVGElement && window.SVGAnimateElement &&
                        window.SVGAnimateTransformElement);
                    if (!(supportsSvgAnimations)) {
                        displayObject = new LoaderMessage('Loading...');
                    }
                    this._display = new LoaderDisplay(displayObject);
                    this.getElement().appendChild(this._display.getElement());
                };
                module.exports = Loader;
            }, { "28": 28, "29": 29, "30": 30 }], 28: [function (require, module, exports) {
                'use strict';
                function LoaderDisplay(displayObject) {
                    this._element = document.createElement('div');
                    this._element.style.cssText = this._cssDeclarations;
                    this._displayObject = displayObject;
                    this._initialize();
                }
                LoaderDisplay.prototype._cssDeclarations = [
                    'display: table-cell',
                    'vertical-align: middle'
                ].join(';');
                LoaderDisplay.prototype.getElement = function () {
                    return this._element;
                };
                LoaderDisplay.prototype.dispose = function () {
                    this._displayObject.dispose();
                    this._displayObject = null;
                    this._element = null;
                };
                LoaderDisplay.prototype._initialize = function () {
                    this.getElement().appendChild(this._displayObject.getElement());
                };
                module.exports = LoaderDisplay;
            }, {}], 29: [function (require, module, exports) {
                'use strict';
                function LoaderMessage(text) {
                    this._element = document.createElement('div');
                    this._element.style.cssText = this._cssDeclarations;
                    this._element.innerHTML = text;
                }
                LoaderMessage.prototype._cssDeclarations = [
                    'color: #fff',
                    'font-family: Helvetica, sans-serif',
                    'font-size: 12px',
                    'text-align: center'
                ].join(';');
                LoaderMessage.prototype.getElement = function () {
                    return this._element;
                };
                LoaderMessage.prototype.dispose = function () {
                    this._element = null;
                };
                module.exports = LoaderMessage;
            }, {}], 30: [function (require, module, exports) {
                'use strict';
                function LoaderSpinner() {
                    this._element = document.createElement('div');
                    this._element.style.cssText = this._cssDeclarations;
                    this._element.innerHTML = this._markup;
                }
                LoaderSpinner.prototype._cssDeclarations = [
                    'height: 36px',
                    'margin-left: auto',
                    'margin-right: auto',
                    'width: 36px'
                ].join(';');
                LoaderSpinner.prototype._markup = [
                    '<svg version="1.1" id="loader-1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"',
                    'width="100%" height="100%" viewBox="0 0 50 50" style="enable-background:new 0 0 50 50;" xml:space="preserve">',
                    '  <path fill="#FFF" d="M43.935,25.145c0-10.318-8.364-18.683-18.683-18.683c-10.318,0-18.683,8.365-18.683,18.683h4.068c0-8.071,6.543-14.615,14.615-14.615c8.072,0,14.615,6.543,14.615,14.615H43.935z">',
                    '    <animateTransform attributeType="xml"',
                    '    attributeName="transform"',
                    '    type="rotate"',
                    '    from="0 25 25"',
                    '    to="360 25 25"',
                    '    dur="780ms"',
                    '    repeatCount="indefinite"',
                    '    calcMode="spline"',
                    '    keySplines="0.44, 0.22, 0, 1"',
                    '    keyTimes="0;1"/>',
                    '  </path>',
                    '</svg>'
                ].join('');
                LoaderSpinner.prototype.getElement = function () {
                    return this._element;
                };
                LoaderSpinner.prototype.dispose = function () {
                    this._element = null;
                };
                module.exports = LoaderSpinner;
            }, {}], 31: [function (require, module, exports) {
                'use strict';
                var utils = require(23);
                function Receiver(callback) {
                    this.postMessageReceiver(callback);
                    this.hashChangeReceiver(callback);
                }
                Receiver.prototype.postMessageReceiver = function (callback) {
                    var self = this;
                    this.wrappedCallback = function (event) {
                        var data = event.data;
                        if (/^(auth_response=)/.test(data) || data === 'user_closed=true') {
                            callback(data);
                            self.stopListening();
                        }
                    };
                    utils.addEventListener(window, 'message', this.wrappedCallback);
                };
                Receiver.prototype.hashChangeReceiver = function (callback) {
                    var hash, originalHash = window.location.hash, self = this;
                    this.poll = setInterval(function () {
                        hash = window.location.hash;
                        if (hash.length > 0 && (hash !== originalHash)) {
                            self.stopListening();
                            hash = hash.substring(1, hash.length);
                            callback(hash);
                            if (originalHash.length > 0) {
                                window.location.hash = originalHash;
                            }
                            else {
                                window.location.hash = '';
                            }
                        }
                    }, 10);
                };
                Receiver.prototype.stopListening = function () {
                    clearTimeout(this.poll);
                    utils.removeEventListener(window, 'message', this.wrappedCallback);
                };
                module.exports = Receiver;
            }, { "23": 23 }], 32: [function (require, module, exports) {
                (function (global) {
                    'use strict';
                    var util = require(39);
                    var prepBody = require(38);
                    var parseBody = require(37);
                    var constants = require(34);
                    var isXHRAvailable = global.XMLHttpRequest && 'withCredentials' in new global.XMLHttpRequest();
                    function getRequestObject() {
                        return isXHRAvailable ? new XMLHttpRequest() : new XDomainRequest();
                    }
                    function get(url, attrs, deserializer, callback, timeout) {
                        var urlParams = util.createURLParams(url, attrs);
                        makeRequest('GET', urlParams, null, deserializer, callback, timeout);
                    }
                    function post(url, attrs, deserializer, callback, timeout) {
                        makeRequest('POST', url, attrs, deserializer, callback, timeout);
                    }
                    function makeRequest(method, url, body, deserializer, callback, timeout) {
                        var status, resBody;
                        var req = getRequestObject();
                        callback = callback || function () { };
                        if (isXHRAvailable) {
                            req.onreadystatechange = function () {
                                if (req.readyState !== 4) {
                                    return;
                                }
                                status = req.status;
                                resBody = parseBody(req.responseText);
                                if (status >= 400 || status === 0) {
                                    callback.call(null, resBody || { errors: constants.errors.UNKNOWN_ERROR }, null);
                                }
                                else if (status > 0) {
                                    callback.call(null, null, deserializer(resBody));
                                }
                            };
                        }
                        else {
                            req.onload = function () {
                                callback.call(null, null, deserializer(parseBody(req.responseText)));
                            };
                            req.onerror = function () {
                                callback.call(null, req.responseText, null);
                            };
                            // This must remain for IE9 to work
                            req.onprogress = function () { };
                            req.ontimeout = function () {
                                callback.call(null, { errors: constants.errors.UNKNOWN_ERROR }, null);
                            };
                        }
                        req.open(method, url, true);
                        req.timeout = timeout == null ? 60000 : timeout;
                        if (isXHRAvailable && method === 'POST') {
                            req.setRequestHeader('Content-Type', 'application/json');
                        }
                        setTimeout(function () {
                            req.send(prepBody(method, body));
                        }, 0);
                    }
                    module.exports = {
                        get: get,
                        post: post
                    };
                }).call(this, typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {});
            }, { "34": 34, "37": 37, "38": 38, "39": 39 }], 33: [function (require, module, exports) {
                'use strict';
                var JSONPDriver = require(35);
                var AJAXDriver = require(32);
                var util = require(39);
                function chooseRequestDriver(options) {
                    var ua = util.getUserAgent();
                    var isAJAXAvailable = !(util.isHTTP() && /(MSIE\s(8|9))|(Phantom)/.test(ua));
                    options = options || {};
                    if (options.enableCORS && isAJAXAvailable) {
                        return AJAXDriver;
                    }
                    else {
                        return JSONPDriver;
                    }
                }
                module.exports = chooseRequestDriver;
            }, { "32": 32, "35": 35, "39": 39 }], 34: [function (require, module, exports) {
                module.exports = {
                    "errors": {
                        "UNKNOWN_ERROR": "Unknown error",
                        "INVALID_TIMEOUT": "Timeout must be a number"
                    }
                };
            }, {}], 35: [function (require, module, exports) {
                'use strict';
                var JSONP = require(36);
                var constants = require(34);
                var timeoutWatchers = [];
                function deserialize(response, mapper) {
                    if (response.status >= 400) {
                        return [response, null];
                    }
                    else {
                        return [null, mapper(response)];
                    }
                }
                function noop() { }
                function requestWithTimeout(url, attrs, deserializer, method, callback, timeout) {
                    var uniqueName;
                    callback = callback || noop;
                    if (timeout == null) {
                        timeout = 60000;
                    }
                    uniqueName = method(url, attrs, function (err, data, name) {
                        if (timeoutWatchers[name]) {
                            clearTimeout(timeoutWatchers[name]);
                            if (err) {
                                callback.call(null, err);
                            }
                            else {
                                callback.apply(null, deserialize(data, function (d) { return deserializer(d); }));
                            }
                        }
                    });
                    if (typeof timeout === 'number') {
                        timeoutWatchers[uniqueName] = setTimeout(function () {
                            timeoutWatchers[uniqueName] = null;
                            callback.apply(null, [{ errors: constants.errors.UNKNOWN_ERROR }, null]);
                        }, timeout);
                    }
                    else {
                        callback.apply(null, [{ errors: constants.errors.INVALID_TIMEOUT }, null]);
                    }
                }
                function post(url, attrs, deserializer, callback, timeout) {
                    attrs._method = 'POST';
                    requestWithTimeout(url, attrs, deserializer, JSONP.get, callback, timeout);
                }
                function get(url, attrs, deserializer, callback, timeout) {
                    requestWithTimeout(url, attrs, deserializer, JSONP.get, callback, timeout);
                }
                module.exports = {
                    get: get,
                    post: post
                };
            }, { "34": 34, "36": 36 }], 36: [function (require, module, exports) {
                (function (global) {
                    'use strict';
                    var util = require(39);
                    /*
                    * Lightweight JSONP fetcher
                    * Copyright 2010-2012 Erik Karlsson. All rights reserved.
                    * BSD licensed
                    */
                    var head, window = global, config = {};
                    function load(url, pfnError) {
                        var script = document.createElement('script'), done = false;
                        script.src = url;
                        script.async = true;
                        var errorHandler = pfnError || config.error;
                        if (typeof errorHandler === 'function') {
                            script.onerror = function (ex) {
                                errorHandler({ url: url, event: ex });
                            };
                        }
                        script.onload = script.onreadystatechange = function () {
                            if (!done && (!this.readyState || this.readyState === "loaded" || this.readyState === "complete")) {
                                done = true;
                                script.onload = script.onreadystatechange = null;
                                if (script && script.parentNode) {
                                    script.parentNode.removeChild(script);
                                }
                            }
                        };
                        if (!head) {
                            head = document.getElementsByTagName('head')[0];
                        }
                        head.appendChild(script);
                    }
                    function jsonp(url, params, callback, callbackName) {
                        var urlParams, key, uniqueName;
                        callbackName = (callbackName || config['callbackName'] || 'callback');
                        uniqueName = callbackName + "_json" + util.generateUUID();
                        params[callbackName] = uniqueName;
                        urlParams = util.createURLParams(url, params);
                        window[uniqueName] = function (data) {
                            callback(null, data, uniqueName);
                            try {
                                delete window[uniqueName];
                            }
                            catch (e) { }
                            window[uniqueName] = null;
                        };
                        load(urlParams, function (err) {
                            callback(err, null, uniqueName);
                        });
                        return uniqueName;
                    }
                    function setDefaults(obj) {
                        config = obj;
                    }
                    module.exports = {
                        get: jsonp,
                        init: setDefaults
                    };
                }).call(this, typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {});
            }, { "39": 39 }], 37: [function (require, module, exports) {
                'use strict';
                module.exports = function (body) {
                    try {
                        body = JSON.parse(body);
                    }
                    catch (e) { }
                    return body;
                };
            }, {}], 38: [function (require, module, exports) {
                'use strict';
                module.exports = function (method, body) {
                    if (typeof method !== 'string') {
                        throw new Error('Method must be a string');
                    }
                    if (method.toLowerCase() !== 'get' && body != null) {
                        body = typeof body === 'string' ? body : JSON.stringify(body);
                    }
                    return body;
                };
            }, {}], 39: [function (require, module, exports) {
                (function (global) {
                    'use strict';
                    function notEmpty(obj) {
                        var key;
                        for (key in obj) {
                            if (obj.hasOwnProperty(key)) {
                                return true;
                            }
                        }
                        return false;
                    }
                    function isArray(value) {
                        return value && typeof value === 'object' && typeof value.length === 'number' &&
                            Object.prototype.toString.call(value) === '[object Array]' || false;
                    }
                    function stringify(params, namespace) {
                        var query = [], k, v, p;
                        for (p in params) {
                            if (!params.hasOwnProperty(p)) {
                                continue;
                            }
                            v = params[p];
                            if (namespace) {
                                if (isArray(params)) {
                                    k = namespace + '[]';
                                }
                                else {
                                    k = namespace + '[' + p + ']';
                                }
                            }
                            else {
                                k = p;
                            }
                            if (typeof v === 'object') {
                                query.push(stringify(v, k));
                            }
                            else {
                                query.push(encodeURIComponent(k) + '=' + encodeURIComponent(v));
                            }
                        }
                        return query.join('&');
                    }
                    function generateUUID() {
                        return 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx'.replace(/[xy]/g, function (xORy) {
                            var randomHex = Math.floor(Math.random() * 16);
                            var uuidHex = xORy === 'x' ? randomHex : randomHex & 0x3 | 0x8; // jshint ignore:line
                            return uuidHex.toString(16);
                        });
                    }
                    function createURLParams(url, params) {
                        url = url || '';
                        if (params != null && typeof params === 'object' && notEmpty(params)) {
                            url += url.indexOf('?') === -1 ? '?' : '';
                            url += url.indexOf('=') !== -1 ? '&' : '';
                            url += stringify(params);
                        }
                        return url;
                    }
                    function getUserAgent() {
                        return global.navigator.userAgent;
                    }
                    function isHTTP() {
                        return global.location.protocol === 'http:';
                    }
                    module.exports = {
                        isArray: isArray,
                        generateUUID: generateUUID,
                        stringify: stringify,
                        createURLParams: createURLParams,
                        getUserAgent: getUserAgent,
                        isHTTP: isHTTP
                    };
                }).call(this, typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {});
            }, {}], 40: [function (require, module, exports) {
                'use strict';
                var AJAXDriver = require(32);
                var JSONPDriver = require(35);
                var chooseDriver = require(33);
                var util = require(39);
                module.exports = {
                    AJAXDriver: AJAXDriver,
                    JSONPDriver: JSONPDriver,
                    chooseDriver: chooseDriver,
                    util: util
                };
            }, { "32": 32, "33": 33, "35": 35, "39": 39 }], 41: [function (require, module, exports) {
                arguments[4][15][0].apply(exports, arguments);
            }, { "15": 15 }], 42: [function (require, module, exports) {
                arguments[4][16][0].apply(exports, arguments);
            }, { "16": 16 }], 43: [function (require, module, exports) {
                arguments[4][17][0].apply(exports, arguments);
            }, { "17": 17 }], 44: [function (require, module, exports) {
                arguments[4][18][0].apply(exports, arguments);
            }, { "18": 18 }], 45: [function (require, module, exports) {
                arguments[4][19][0].apply(exports, arguments);
            }, { "19": 19 }], 46: [function (require, module, exports) {
                arguments[4][20][0].apply(exports, arguments);
            }, { "20": 20 }], 47: [function (require, module, exports) {
                arguments[4][21][0].apply(exports, arguments);
            }, { "21": 21, "41": 41 }], 48: [function (require, module, exports) {
                arguments[4][22][0].apply(exports, arguments);
            }, { "22": 22 }], 49: [function (require, module, exports) {
                arguments[4][23][0].apply(exports, arguments);
            }, { "23": 23, "41": 41, "42": 42, "43": 43, "44": 44, "45": 45, "46": 46, "47": 47, "48": 48 }], 50: [function (require, module, exports) {
                'use strict';
                var utils = require(64);
                function MessageBus(host, channel) {
                    this.host = host || window;
                    this.channel = channel || null;
                    this.handlers = [];
                    utils.addEventListener(this.host, 'message', utils.bind(this.receive, this));
                }
                MessageBus.prototype.receive = function (event) {
                    var i, message, parsed, type;
                    try {
                        parsed = JSON.parse(event.data);
                    }
                    catch (e) {
                        return;
                    }
                    type = parsed.type;
                    message = new MessageBus.Message(this, event.source, parsed.data);
                    for (i = 0; i < this.handlers.length; i++) {
                        if (this.handlers[i].type === type) {
                            this.handlers[i].handler(message);
                        }
                    }
                };
                MessageBus.prototype.send = function (source, type, data) {
                    try {
                        source.postMessage(JSON.stringify({
                            type: this._namespaceEvent(type),
                            data: data
                        }), '*');
                    }
                    catch (e) { }
                };
                MessageBus.prototype.register = function (type, handler) {
                    this.handlers.push({
                        type: this._namespaceEvent(type),
                        handler: handler
                    });
                };
                MessageBus.prototype.unregister = function (type, handler) {
                    for (var i = this.handlers.length - 1; i >= 0; i--) {
                        if (this.handlers[i].type === type && this.handlers[i].handler === handler) {
                            return this.handlers.splice(i, 1);
                        }
                    }
                };
                MessageBus.prototype._namespaceEvent = function (eventName) {
                    return this.channel ? ['braintree', this.channel, eventName].join(':') : eventName;
                };
                MessageBus.Message = function (bus, source, content) {
                    this.bus = bus;
                    this.source = source;
                    this.content = content;
                };
                MessageBus.Message.prototype.reply = function (type, data) {
                    this.bus.send(this.source, type, data);
                };
                module.exports = MessageBus;
            }, { "64": 64 }], 51: [function (require, module, exports) {
                'use strict';
                var utils = require(64);
                function PubsubClient(bus, target) {
                    this.bus = bus;
                    this.target = target;
                    this.handlers = [];
                    this.bus.register('publish', utils.bind(this._handleMessage, this));
                }
                PubsubClient.prototype._handleMessage = function (message) {
                    var i, content = message.content, handlers = this.handlers[content.channel];
                    if (typeof handlers !== 'undefined') {
                        for (i = 0; i < handlers.length; i++) {
                            handlers[i](content.data);
                        }
                    }
                };
                PubsubClient.prototype.publish = function (channel, data) {
                    this.bus.send(this.target, 'publish', { channel: channel, data: data });
                };
                PubsubClient.prototype.subscribe = function (channel, handler) {
                    this.handlers[channel] = this.handlers[channel] || [];
                    this.handlers[channel].push(handler);
                };
                PubsubClient.prototype.unsubscribe = function (channel, handler) {
                    var i, handlers = this.handlers[channel];
                    if (typeof handlers !== 'undefined') {
                        for (i = 0; i < handlers.length; i++) {
                            if (handlers[i] === handler) {
                                handlers.splice(i, 1);
                            }
                        }
                    }
                };
                module.exports = PubsubClient;
            }, { "64": 64 }], 52: [function (require, module, exports) {
                'use strict';
                function PubsubServer(bus) {
                    this.bus = bus;
                    this.frames = [];
                    this.handlers = [];
                }
                PubsubServer.prototype.subscribe = function (channel, handler) {
                    this.handlers[channel] = this.handlers[channel] || [];
                    this.handlers[channel].push(handler);
                };
                PubsubServer.prototype.registerFrame = function (frame) {
                    this.frames.push(frame);
                };
                PubsubServer.prototype.unregisterFrame = function (frame) {
                    for (var i = 0; i < this.frames.length; i++) {
                        if (this.frames[i] === frame) {
                            this.frames.splice(i, 1);
                        }
                    }
                };
                PubsubServer.prototype.publish = function (channel, data) {
                    var i, handlers = this.handlers[channel];
                    if (typeof handlers !== 'undefined') {
                        for (i = 0; i < handlers.length; i++) {
                            handlers[i](data);
                        }
                    }
                    for (i = 0; i < this.frames.length; i++) {
                        this.bus.send(this.frames[i], 'publish', {
                            channel: channel,
                            data: data
                        });
                    }
                };
                PubsubServer.prototype.unsubscribe = function (channel, handler) {
                    var i, handlers = this.handlers[channel];
                    if (typeof handlers !== 'undefined') {
                        for (i = 0; i < handlers.length; i++) {
                            if (handlers[i] === handler) {
                                handlers.splice(i, 1);
                            }
                        }
                    }
                };
                module.exports = PubsubServer;
            }, {}], 53: [function (require, module, exports) {
                'use strict';
                var utils = require(64);
                function RPCClient(bus, target) {
                    this.bus = bus;
                    this.target = target || window.parent;
                    this.counter = 0;
                    this.callbacks = {};
                    this.bus.register('rpc_response', utils.bind(this._handleResponse, this));
                }
                RPCClient.prototype._handleResponse = function (message) {
                    var content = message.content, thisCallback = this.callbacks[content.id];
                    if (typeof thisCallback === 'function') {
                        thisCallback.apply(null, content.response);
                        delete this.callbacks[content.id];
                    }
                };
                RPCClient.prototype.invoke = function (method, args, callback) {
                    var counter = this.counter++;
                    this.callbacks[counter] = callback;
                    this.bus.send(this.target, 'rpc_request', { id: counter, method: method, args: args });
                };
                module.exports = RPCClient;
            }, { "64": 64 }], 54: [function (require, module, exports) {
                'use strict';
                var utils = require(64);
                function RPCServer(bus) {
                    this.bus = bus;
                    this.methods = {};
                    this.bus.register('rpc_request', utils.bind(this._handleRequest, this));
                }
                RPCServer.prototype._handleRequest = function (message) {
                    var reply, content = message.content, args = content.args || [], thisMethod = this.methods[content.method];
                    if (typeof thisMethod === 'function') {
                        reply = function () {
                            message.reply('rpc_response', {
                                id: content.id,
                                response: Array.prototype.slice.call(arguments)
                            });
                        };
                        args.push(reply);
                        thisMethod.apply(null, args);
                    }
                };
                RPCServer.prototype.reset = function () {
                    this.methods = {};
                };
                RPCServer.prototype.define = function (method, handler) {
                    this.methods[method] = handler;
                };
                module.exports = RPCServer;
            }, { "64": 64 }], 55: [function (require, module, exports) {
                var MessageBus = require(50);
                var PubsubClient = require(51);
                var PubsubServer = require(52);
                var RPCClient = require(53);
                var RPCServer = require(54);
                module.exports = {
                    MessageBus: MessageBus,
                    PubsubClient: PubsubClient,
                    PubsubServer: PubsubServer,
                    RPCClient: RPCClient,
                    RPCServer: RPCServer
                };
            }, { "50": 50, "51": 51, "52": 52, "53": 53, "54": 54 }], 56: [function (require, module, exports) {
                arguments[4][15][0].apply(exports, arguments);
            }, { "15": 15 }], 57: [function (require, module, exports) {
                arguments[4][16][0].apply(exports, arguments);
            }, { "16": 16 }], 58: [function (require, module, exports) {
                arguments[4][17][0].apply(exports, arguments);
            }, { "17": 17 }], 59: [function (require, module, exports) {
                arguments[4][18][0].apply(exports, arguments);
            }, { "18": 18 }], 60: [function (require, module, exports) {
                arguments[4][19][0].apply(exports, arguments);
            }, { "19": 19 }], 61: [function (require, module, exports) {
                arguments[4][20][0].apply(exports, arguments);
            }, { "20": 20 }], 62: [function (require, module, exports) {
                arguments[4][21][0].apply(exports, arguments);
            }, { "21": 21, "56": 56 }], 63: [function (require, module, exports) {
                arguments[4][22][0].apply(exports, arguments);
            }, { "22": 22 }], 64: [function (require, module, exports) {
                arguments[4][23][0].apply(exports, arguments);
            }, { "23": 23, "56": 56, "57": 57, "58": 58, "59": 59, "60": 60, "61": 61, "62": 62, "63": 63 }], 65: [function (require, module, exports) {
                arguments[4][15][0].apply(exports, arguments);
            }, { "15": 15 }], 66: [function (require, module, exports) {
                arguments[4][16][0].apply(exports, arguments);
            }, { "16": 16 }], 67: [function (require, module, exports) {
                arguments[4][17][0].apply(exports, arguments);
            }, { "17": 17 }], 68: [function (require, module, exports) {
                arguments[4][18][0].apply(exports, arguments);
            }, { "18": 18 }], 69: [function (require, module, exports) {
                arguments[4][19][0].apply(exports, arguments);
            }, { "19": 19 }], 70: [function (require, module, exports) {
                arguments[4][20][0].apply(exports, arguments);
            }, { "20": 20 }], 71: [function (require, module, exports) {
                arguments[4][21][0].apply(exports, arguments);
            }, { "21": 21, "65": 65 }], 72: [function (require, module, exports) {
                arguments[4][22][0].apply(exports, arguments);
            }, { "22": 22 }], 73: [function (require, module, exports) {
                arguments[4][23][0].apply(exports, arguments);
            }, { "23": 23, "65": 65, "66": 66, "67": 67, "68": 68, "69": 69, "70": 70, "71": 71, "72": 72 }], 74: [function (require, module, exports) {
                'use strict';
                module.exports = ClassList;
                var indexOf = require(75), trim = require(76), arr = Array.prototype;
                /**
                 * ClassList(elem) is kind of like Element#classList.
                 *
                 * @param {Element} elem
                 * @return {ClassList}
                 */
                function ClassList(elem) {
                    if (!(this instanceof ClassList))
                        return new ClassList(elem);
                    var classes = trim(elem.className).split(/\s+/), i;
                    this._elem = elem;
                    this.length = 0;
                    for (i = 0; i < classes.length; i += 1) {
                        if (classes[i])
                            arr.push.call(this, classes[i]);
                    }
                }
                /**
                 * add(class1 [, class2 [, ...]]) adds the given class(es) to the
                 * element.
                 *
                 * @param {String} ...
                 * @return {Context}
                 */
                ClassList.prototype.add = function () {
                    var name, i;
                    for (i = 0; i < arguments.length; i += 1) {
                        name = '' + arguments[i];
                        if (indexOf(this, name) >= 0)
                            continue;
                        arr.push.call(this, name);
                    }
                    this._elem.className = this.toString();
                    return this;
                };
                /**
                 * remove(class1 [, class2 [, ...]]) removes the given class(es) from
                 * the element.
                 *
                 * @param {String} ...
                 * @return {Context}
                 */
                ClassList.prototype.remove = function () {
                    var index, name, i;
                    for (i = 0; i < arguments.length; i += 1) {
                        name = '' + arguments[i];
                        index = indexOf(this, name);
                        if (index < 0)
                            continue;
                        arr.splice.call(this, index, 1);
                    }
                    this._elem.className = this.toString();
                    return this;
                };
                /**
                 * contains(name) determines if the element has a given class.
                 *
                 * @param {String} name
                 * @return {Boolean}
                 */
                ClassList.prototype.contains = function (name) {
                    name += '';
                    return indexOf(this, name) >= 0;
                };
                /**
                 * toggle(name [, force]) toggles a class. If force is a boolean,
                 * this method is basically just an alias for add/remove.
                 *
                 * @param {String} name
                 * @param {Boolean} force
                 * @return {Context}
                 */
                ClassList.prototype.toggle = function (name, force) {
                    name += '';
                    if (force === true)
                        return this.add(name);
                    if (force === false)
                        return this.remove(name);
                    return this[this.contains(name) ? 'remove' : 'add'](name);
                };
                /**
                 * toString() returns the className of the element.
                 *
                 * @return {String}
                 */
                ClassList.prototype.toString = function () {
                    return arr.join.call(this, ' ');
                };
            }, { "75": 75, "76": 76 }], 75: [function (require, module, exports) {
                module.exports = function (arr, obj) {
                    if (arr.indexOf)
                        return arr.indexOf(obj);
                    for (var i = 0; i < arr.length; ++i) {
                        if (arr[i] === obj)
                            return i;
                    }
                    return -1;
                };
            }, {}], 76: [function (require, module, exports) {
                exports = module.exports = trim;
                function trim(str) {
                    return str.replace(/^\s*|\s*$/g, '');
                }
                exports.left = function (str) {
                    return str.replace(/^\s*/, '');
                };
                exports.right = function (str) {
                    return str.replace(/\s*$/, '');
                };
            }, {}], 77: [function (require, module, exports) {
                'use strict';
                var batchExecuteFunctions = require(78);
                // Reach into lib for isFunction. This lib requires a DOM and cannot be
                // tested otherwise
                var fnUtil = require(79);
                function Destructor() {
                    this._teardownRegistry = [];
                }
                Destructor.prototype.registerFunctionForTeardown = function (fn) {
                    if (fnUtil.isFunction(fn)) {
                        this._teardownRegistry.push(fn);
                    }
                };
                Destructor.prototype.teardown = function (callback) {
                    batchExecuteFunctions(this._teardownRegistry, fnUtil.bind(function (err) {
                        this._teardownRegistry = [];
                        if (fnUtil.isFunction(callback)) {
                            callback(err);
                        }
                    }, this));
                };
                module.exports = Destructor;
            }, { "78": 78, "79": 79 }], 78: [function (require, module, exports) {
                'use strict';
                function call(fn, callback) {
                    var isSync = fn.length === 0;
                    var wrappedCallback;
                    if (isSync) {
                        fn();
                        callback(null);
                    }
                    else {
                        wrappedCallback = once(callback);
                        fn(wrappedCallback);
                    }
                }
                function once(fn) {
                    var called = false;
                    return function () {
                        if (!called) {
                            called = true;
                            fn.apply(this, arguments);
                        }
                    };
                }
                module.exports = function (functions, callback) {
                    var length = functions.length;
                    var remaining = length;
                    if (length === 0) {
                        callback(null);
                        return;
                    }
                    for (var i = 0; i < length; i++) {
                        call(functions[i], function (err) {
                            if (err) {
                                callback(err);
                                return;
                            }
                            remaining -= 1;
                            if (remaining === 0) {
                                callback(null);
                            }
                        });
                    }
                };
            }, {}], 79: [function (require, module, exports) {
                arguments[4][19][0].apply(exports, arguments);
            }, { "19": 19 }], 80: [function (require, module, exports) {
                (function (global) {
                    'use strict';
                    function FormNapper(form) {
                        if (typeof form === 'string' || form instanceof String) {
                            form = document.getElementById(form);
                        }
                        if (form instanceof HTMLFormElement) {
                            this.htmlForm = form;
                        }
                        else {
                            throw new TypeError('FormNapper requires an HTMLFormElement element or the id string of one.');
                        }
                    }
                    FormNapper.prototype.hijack = function (onsubmit) {
                        if (this.submitHandler) {
                            return;
                        }
                        this.submitHandler = function (event) {
                            if (event.preventDefault) {
                                event.preventDefault();
                            }
                            else {
                                event.returnValue = false;
                            }
                            onsubmit(event);
                        };
                        if (global.addEventListener != null) {
                            this.htmlForm.addEventListener('submit', this.submitHandler, false);
                        }
                        else if (global.attachEvent != null) {
                            this.htmlForm.attachEvent('onsubmit', this.submitHandler);
                        }
                        else {
                            this.htmlForm.onsubmit = this.submitHandler;
                        }
                    };
                    FormNapper.prototype.inject = function (name, value) {
                        var input = this.htmlForm.querySelector('input[name="' + name + '"]');
                        if (input == null) {
                            input = document.createElement('input');
                            input.type = 'hidden';
                            input.name = name;
                            this.htmlForm.appendChild(input);
                        }
                        input.value = value;
                        return input;
                    };
                    FormNapper.prototype.submit = function () {
                        HTMLFormElement.prototype.submit.call(this.htmlForm);
                    };
                    FormNapper.prototype.detach = function () {
                        if (!this.submitHandler) {
                            return;
                        }
                        if (global.removeEventListener != null) {
                            this.htmlForm.removeEventListener('submit', this.submitHandler, false);
                        }
                        else if (global.detachEvent != null) {
                            this.htmlForm.detachEvent('onsubmit', this.submitHandler);
                        }
                        else {
                            this.htmlForm.onsubmit = null;
                        }
                        delete this.submitHandler;
                    };
                    module.exports = FormNapper;
                }).call(this, typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {});
            }, {}], 81: [function (require, module, exports) {
                'use strict';
                (function (root, factory) {
                    if (typeof exports === 'object' && typeof module !== 'undefined') {
                        module.exports = factory();
                    }
                    else if (typeof define === 'function' && define.amd) {
                        define([], factory);
                    }
                    else {
                        root.framebus = factory();
                    }
                })(this, function () {
                    var win, framebus;
                    var popups = [];
                    var subscribers = {};
                    var prefix = '/*framebus*/';
                    function include(popup) {
                        if (popup == null) {
                            return false;
                        }
                        if (popup.Window == null) {
                            return false;
                        }
                        if (popup.constructor !== popup.Window) {
                            return false;
                        }
                        popups.push(popup);
                        return true;
                    }
                    function target(origin) {
                        var key;
                        var targetedFramebus = {};
                        for (key in framebus) {
                            if (!framebus.hasOwnProperty(key)) {
                                continue;
                            }
                            targetedFramebus[key] = framebus[key];
                        }
                        targetedFramebus._origin = origin || '*';
                        return targetedFramebus;
                    }
                    function publish(event) {
                        var payload, args;
                        var origin = _getOrigin(this); // eslint-disable-line no-invalid-this
                        if (_isntString(event)) {
                            return false;
                        }
                        if (_isntString(origin)) {
                            return false;
                        }
                        args = Array.prototype.slice.call(arguments, 1);
                        payload = _packagePayload(event, args, origin);
                        if (payload === false) {
                            return false;
                        }
                        _broadcast(win.top, payload, origin);
                        return true;
                    }
                    function subscribe(event, fn) {
                        var origin = _getOrigin(this); // eslint-disable-line no-invalid-this
                        if (_subscriptionArgsInvalid(event, fn, origin)) {
                            return false;
                        }
                        subscribers[origin] = subscribers[origin] || {};
                        subscribers[origin][event] = subscribers[origin][event] || [];
                        subscribers[origin][event].push(fn);
                        return true;
                    }
                    function unsubscribe(event, fn) {
                        var i, subscriberList;
                        var origin = _getOrigin(this); // eslint-disable-line no-invalid-this
                        if (_subscriptionArgsInvalid(event, fn, origin)) {
                            return false;
                        }
                        subscriberList = subscribers[origin] && subscribers[origin][event];
                        if (!subscriberList) {
                            return false;
                        }
                        for (i = 0; i < subscriberList.length; i++) {
                            if (subscriberList[i] === fn) {
                                subscriberList.splice(i, 1);
                                return true;
                            }
                        }
                        return false;
                    }
                    function _getOrigin(scope) {
                        return scope && scope._origin || '*';
                    }
                    function _isntString(string) {
                        return typeof string !== 'string';
                    }
                    function _packagePayload(event, args, origin) {
                        var packaged = false;
                        var payload = {
                            event: event,
                            origin: origin
                        };
                        var reply = args[args.length - 1];
                        if (typeof reply === 'function') {
                            payload.reply = _subscribeReplier(reply, origin);
                            args = args.slice(0, -1);
                        }
                        payload.args = args;
                        try {
                            packaged = prefix + JSON.stringify(payload);
                        }
                        catch (e) {
                            throw new Error('Could not stringify event: ' + e.message);
                        }
                        return packaged;
                    }
                    function _unpackPayload(e) {
                        var payload, replyOrigin, replySource, replyEvent;
                        if (e.data.slice(0, prefix.length) !== prefix) {
                            return false;
                        }
                        try {
                            payload = JSON.parse(e.data.slice(prefix.length));
                        }
                        catch (err) {
                            return false;
                        }
                        if (payload.reply != null) {
                            replyOrigin = e.origin;
                            replySource = e.source;
                            replyEvent = payload.reply;
                            payload.reply = function reply(data) {
                                var replyPayload = _packagePayload(replyEvent, [data], replyOrigin);
                                if (replyPayload === false) {
                                    return false;
                                }
                                replySource.postMessage(replyPayload, replyOrigin);
                            };
                            payload.args.push(payload.reply);
                        }
                        return payload;
                    }
                    function _attach(w) {
                        if (win) {
                            return;
                        }
                        win = w || window;
                        if (win.addEventListener) {
                            win.addEventListener('message', _onmessage, false);
                        }
                        else if (win.attachEvent) {
                            win.attachEvent('onmessage', _onmessage);
                        }
                        else if (win.onmessage === null) {
                            win.onmessage = _onmessage;
                        }
                        else {
                            win = null;
                        }
                    }
                    function _uuid() {
                        return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
                            var r = Math.random() * 16 | 0;
                            var v = c === 'x' ? r : r & 0x3 | 0x8;
                            return v.toString(16);
                        });
                    }
                    function _onmessage(e) {
                        var payload;
                        if (_isntString(e.data)) {
                            return;
                        }
                        payload = _unpackPayload(e);
                        if (!payload) {
                            return;
                        }
                        _dispatch('*', payload.event, payload.args, e);
                        _dispatch(e.origin, payload.event, payload.args, e);
                        _broadcastPopups(e.data, payload.origin, e.source);
                    }
                    function _dispatch(origin, event, args, e) {
                        var i;
                        if (!subscribers[origin]) {
                            return;
                        }
                        if (!subscribers[origin][event]) {
                            return;
                        }
                        for (i = 0; i < subscribers[origin][event].length; i++) {
                            subscribers[origin][event][i].apply(e, args);
                        }
                    }
                    function _hasOpener(frame) {
                        if (frame.top !== frame) {
                            return false;
                        }
                        if (frame.opener == null) {
                            return false;
                        }
                        if (frame.opener === frame) {
                            return false;
                        }
                        if (frame.opener.closed === true) {
                            return false;
                        }
                        return true;
                    }
                    function _broadcast(frame, payload, origin) {
                        var i;
                        try {
                            frame.postMessage(payload, origin);
                            if (_hasOpener(frame)) {
                                _broadcast(frame.opener.top, payload, origin);
                            }
                            for (i = 0; i < frame.frames.length; i++) {
                                _broadcast(frame.frames[i], payload, origin);
                            }
                        }
                        catch (_) { }
                    }
                    function _broadcastPopups(payload, origin, source) {
                        var i, popup;
                        for (i = popups.length - 1; i >= 0; i--) {
                            popup = popups[i];
                            if (popup.closed === true) {
                                popups = popups.slice(i, 1);
                            }
                            else if (source !== popup) {
                                _broadcast(popup.top, payload, origin);
                            }
                        }
                    }
                    function _subscribeReplier(fn, origin) {
                        var uuid = _uuid();
                        function replier(d, o) {
                            fn(d, o);
                            framebus.target(origin).unsubscribe(uuid, replier);
                        }
                        framebus.target(origin).subscribe(uuid, replier);
                        return uuid;
                    }
                    function _subscriptionArgsInvalid(event, fn, origin) {
                        if (_isntString(event)) {
                            return true;
                        }
                        if (typeof fn !== 'function') {
                            return true;
                        }
                        if (_isntString(origin)) {
                            return true;
                        }
                        return false;
                    }
                    _attach();
                    framebus = {
                        target: target,
                        include: include,
                        publish: publish,
                        pub: publish,
                        trigger: publish,
                        emit: publish,
                        subscribe: subscribe,
                        sub: subscribe,
                        on: subscribe,
                        unsubscribe: unsubscribe,
                        unsub: unsubscribe,
                        off: unsubscribe
                    };
                    return framebus;
                });
            }, {}], 82: [function (require, module, exports) {
                'use strict';
                var assign = require(150);
                var isString = require(149);
                var setAttributes = require(84);
                var defaultAttributes = require(83);
                module.exports = function createFrame(options) {
                    var iframe = document.createElement('iframe');
                    var config = assign({}, defaultAttributes, options);
                    if (config.style && !isString(config.style)) {
                        assign(iframe.style, config.style);
                        delete config.style;
                    }
                    setAttributes(iframe, config);
                    if (!iframe.getAttribute('id')) {
                        iframe.id = iframe.name;
                    }
                    return iframe;
                };
            }, { "149": 149, "150": 150, "83": 83, "84": 84 }], 83: [function (require, module, exports) {
                module.exports = {
                    "src": "about:blank",
                    "frameBorder": 0,
                    "allowtransparency": true,
                    "scrolling": "no"
                };
            }, {}], 84: [function (require, module, exports) {
                module.exports = function setAttributes(element, attributes) {
                    var value;
                    for (var key in attributes) {
                        if (attributes.hasOwnProperty(key)) {
                            value = attributes[key];
                            if (value == null) {
                                element.removeAttribute(key);
                            }
                            else {
                                element.setAttribute(key, value);
                            }
                        }
                    }
                };
            }, {}], 85: [function (require, module, exports) {
                var LazyWrapper = require(92), LodashWrapper = require(93), baseLodash = require(107), isArray = require(145), isObjectLike = require(133), wrapperClone = require(142);
                /** Used for native method references. */
                var objectProto = Object.prototype;
                /** Used to check objects for own properties. */
                var hasOwnProperty = objectProto.hasOwnProperty;
                /**
                 * Creates a `lodash` object which wraps `value` to enable implicit chaining.
                 * Methods that operate on and return arrays, collections, and functions can
                 * be chained together. Methods that retrieve a single value or may return a
                 * primitive value will automatically end the chain returning the unwrapped
                 * value. Explicit chaining may be enabled using `_.chain`. The execution of
                 * chained methods is lazy, that is, execution is deferred until `_#value`
                 * is implicitly or explicitly called.
                 *
                 * Lazy evaluation allows several methods to support shortcut fusion. Shortcut
                 * fusion is an optimization strategy which merge iteratee calls; this can help
                 * to avoid the creation of intermediate data structures and greatly reduce the
                 * number of iteratee executions.
                 *
                 * Chaining is supported in custom builds as long as the `_#value` method is
                 * directly or indirectly included in the build.
                 *
                 * In addition to lodash methods, wrappers have `Array` and `String` methods.
                 *
                 * The wrapper `Array` methods are:
                 * `concat`, `join`, `pop`, `push`, `reverse`, `shift`, `slice`, `sort`,
                 * `splice`, and `unshift`
                 *
                 * The wrapper `String` methods are:
                 * `replace` and `split`
                 *
                 * The wrapper methods that support shortcut fusion are:
                 * `compact`, `drop`, `dropRight`, `dropRightWhile`, `dropWhile`, `filter`,
                 * `first`, `initial`, `last`, `map`, `pluck`, `reject`, `rest`, `reverse`,
                 * `slice`, `take`, `takeRight`, `takeRightWhile`, `takeWhile`, `toArray`,
                 * and `where`
                 *
                 * The chainable wrapper methods are:
                 * `after`, `ary`, `assign`, `at`, `before`, `bind`, `bindAll`, `bindKey`,
                 * `callback`, `chain`, `chunk`, `commit`, `compact`, `concat`, `constant`,
                 * `countBy`, `create`, `curry`, `debounce`, `defaults`, `defaultsDeep`,
                 * `defer`, `delay`, `difference`, `drop`, `dropRight`, `dropRightWhile`,
                 * `dropWhile`, `fill`, `filter`, `flatten`, `flattenDeep`, `flow`, `flowRight`,
                 * `forEach`, `forEachRight`, `forIn`, `forInRight`, `forOwn`, `forOwnRight`,
                 * `functions`, `groupBy`, `indexBy`, `initial`, `intersection`, `invert`,
                 * `invoke`, `keys`, `keysIn`, `map`, `mapKeys`, `mapValues`, `matches`,
                 * `matchesProperty`, `memoize`, `merge`, `method`, `methodOf`, `mixin`,
                 * `modArgs`, `negate`, `omit`, `once`, `pairs`, `partial`, `partialRight`,
                 * `partition`, `pick`, `plant`, `pluck`, `property`, `propertyOf`, `pull`,
                 * `pullAt`, `push`, `range`, `rearg`, `reject`, `remove`, `rest`, `restParam`,
                 * `reverse`, `set`, `shuffle`, `slice`, `sort`, `sortBy`, `sortByAll`,
                 * `sortByOrder`, `splice`, `spread`, `take`, `takeRight`, `takeRightWhile`,
                 * `takeWhile`, `tap`, `throttle`, `thru`, `times`, `toArray`, `toPlainObject`,
                 * `transform`, `union`, `uniq`, `unshift`, `unzip`, `unzipWith`, `values`,
                 * `valuesIn`, `where`, `without`, `wrap`, `xor`, `zip`, `zipObject`, `zipWith`
                 *
                 * The wrapper methods that are **not** chainable by default are:
                 * `add`, `attempt`, `camelCase`, `capitalize`, `ceil`, `clone`, `cloneDeep`,
                 * `deburr`, `endsWith`, `escape`, `escapeRegExp`, `every`, `find`, `findIndex`,
                 * `findKey`, `findLast`, `findLastIndex`, `findLastKey`, `findWhere`, `first`,
                 * `floor`, `get`, `gt`, `gte`, `has`, `identity`, `includes`, `indexOf`,
                 * `inRange`, `isArguments`, `isArray`, `isBoolean`, `isDate`, `isElement`,
                 * `isEmpty`, `isEqual`, `isError`, `isFinite` `isFunction`, `isMatch`,
                 * `isNative`, `isNaN`, `isNull`, `isNumber`, `isObject`, `isPlainObject`,
                 * `isRegExp`, `isString`, `isUndefined`, `isTypedArray`, `join`, `kebabCase`,
                 * `last`, `lastIndexOf`, `lt`, `lte`, `max`, `min`, `noConflict`, `noop`,
                 * `now`, `pad`, `padLeft`, `padRight`, `parseInt`, `pop`, `random`, `reduce`,
                 * `reduceRight`, `repeat`, `result`, `round`, `runInContext`, `shift`, `size`,
                 * `snakeCase`, `some`, `sortedIndex`, `sortedLastIndex`, `startCase`,
                 * `startsWith`, `sum`, `template`, `trim`, `trimLeft`, `trimRight`, `trunc`,
                 * `unescape`, `uniqueId`, `value`, and `words`
                 *
                 * The wrapper method `sample` will return a wrapped value when `n` is provided,
                 * otherwise an unwrapped value is returned.
                 *
                 * @name _
                 * @constructor
                 * @category Chain
                 * @param {*} value The value to wrap in a `lodash` instance.
                 * @returns {Object} Returns the new `lodash` wrapper instance.
                 * @example
                 *
                 * var wrapped = _([1, 2, 3]);
                 *
                 * // returns an unwrapped value
                 * wrapped.reduce(function(total, n) {
                 *   return total + n;
                 * });
                 * // => 6
                 *
                 * // returns a wrapped value
                 * var squares = wrapped.map(function(n) {
                 *   return n * n;
                 * });
                 *
                 * _.isArray(squares);
                 * // => false
                 *
                 * _.isArray(squares.value());
                 * // => true
                 */
                function lodash(value) {
                    if (isObjectLike(value) && !isArray(value) && !(value instanceof LazyWrapper)) {
                        if (value instanceof LodashWrapper) {
                            return value;
                        }
                        if (hasOwnProperty.call(value, '__chain__') && hasOwnProperty.call(value, '__wrapped__')) {
                            return wrapperClone(value);
                        }
                    }
                    return new LodashWrapper(value);
                }
                // Ensure wrappers are instances of `baseLodash`.
                lodash.prototype = baseLodash.prototype;
                module.exports = lodash;
            }, { "107": 107, "133": 133, "142": 142, "145": 145, "92": 92, "93": 93 }], 86: [function (require, module, exports) {
                var getNative = require(124);
                /* Native method references for those with the same name as other `lodash` methods. */
                var nativeNow = getNative(Date, 'now');
                /**
                 * Gets the number of milliseconds that have elapsed since the Unix epoch
                 * (1 January 1970 00:00:00 UTC).
                 *
                 * @static
                 * @memberOf _
                 * @category Date
                 * @example
                 *
                 * _.defer(function(stamp) {
                 *   console.log(_.now() - stamp);
                 * }, _.now());
                 * // => logs the number of milliseconds it took for the deferred function to be invoked
                 */
                var now = nativeNow || function () {
                    return new Date().getTime();
                };
                module.exports = now;
            }, { "124": 124 }], 87: [function (require, module, exports) {
                var createWrapper = require(120), replaceHolders = require(138), restParam = require(91);
                /** Used to compose bitmasks for wrapper metadata. */
                var BIND_FLAG = 1, PARTIAL_FLAG = 32;
                /**
                 * Creates a function that invokes `func` with the `this` binding of `thisArg`
                 * and prepends any additional `_.bind` arguments to those provided to the
                 * bound function.
                 *
                 * The `_.bind.placeholder` value, which defaults to `_` in monolithic builds,
                 * may be used as a placeholder for partially applied arguments.
                 *
                 * **Note:** Unlike native `Function#bind` this method does not set the "length"
                 * property of bound functions.
                 *
                 * @static
                 * @memberOf _
                 * @category Function
                 * @param {Function} func The function to bind.
                 * @param {*} thisArg The `this` binding of `func`.
                 * @param {...*} [partials] The arguments to be partially applied.
                 * @returns {Function} Returns the new bound function.
                 * @example
                 *
                 * var greet = function(greeting, punctuation) {
                 *   return greeting + ' ' + this.user + punctuation;
                 * };
                 *
                 * var object = { 'user': 'fred' };
                 *
                 * var bound = _.bind(greet, object, 'hi');
                 * bound('!');
                 * // => 'hi fred!'
                 *
                 * // using placeholders
                 * var bound = _.bind(greet, object, _, '!');
                 * bound('hi');
                 * // => 'hi fred!'
                 */
                var bind = restParam(function (func, thisArg, partials) {
                    var bitmask = BIND_FLAG;
                    if (partials.length) {
                        var holders = replaceHolders(partials, bind.placeholder);
                        bitmask |= PARTIAL_FLAG;
                    }
                    return createWrapper(func, bitmask, thisArg, partials, holders);
                });
                // Assign default placeholders.
                bind.placeholder = {};
                module.exports = bind;
            }, { "120": 120, "138": 138, "91": 91 }], 88: [function (require, module, exports) {
                var baseFlatten = require(103), createWrapper = require(120), functions = require(152), restParam = require(91);
                /** Used to compose bitmasks for wrapper metadata. */
                var BIND_FLAG = 1;
                /**
                 * Binds methods of an object to the object itself, overwriting the existing
                 * method. Method names may be specified as individual arguments or as arrays
                 * of method names. If no method names are provided all enumerable function
                 * properties, own and inherited, of `object` are bound.
                 *
                 * **Note:** This method does not set the "length" property of bound functions.
                 *
                 * @static
                 * @memberOf _
                 * @category Function
                 * @param {Object} object The object to bind and assign the bound methods to.
                 * @param {...(string|string[])} [methodNames] The object method names to bind,
                 *  specified as individual method names or arrays of method names.
                 * @returns {Object} Returns `object`.
                 * @example
                 *
                 * var view = {
                 *   'label': 'docs',
                 *   'onClick': function() {
                 *     console.log('clicked ' + this.label);
                 *   }
                 * };
                 *
                 * _.bindAll(view);
                 * jQuery('#docs').on('click', view.onClick);
                 * // => logs 'clicked docs' when the element is clicked
                 */
                var bindAll = restParam(function (object, methodNames) {
                    methodNames = methodNames.length ? baseFlatten(methodNames) : functions(object);
                    var index = -1, length = methodNames.length;
                    while (++index < length) {
                        var key = methodNames[index];
                        object[key] = createWrapper(object[key], BIND_FLAG, object);
                    }
                    return object;
                });
                module.exports = bindAll;
            }, { "103": 103, "120": 120, "152": 152, "91": 91 }], 89: [function (require, module, exports) {
                var isObject = require(148), now = require(86);
                /** Used as the `TypeError` message for "Functions" methods. */
                var FUNC_ERROR_TEXT = 'Expected a function';
                /* Native method references for those with the same name as other `lodash` methods. */
                var nativeMax = Math.max;
                /**
                 * Creates a debounced function that delays invoking `func` until after `wait`
                 * milliseconds have elapsed since the last time the debounced function was
                 * invoked. The debounced function comes with a `cancel` method to cancel
                 * delayed invocations. Provide an options object to indicate that `func`
                 * should be invoked on the leading and/or trailing edge of the `wait` timeout.
                 * Subsequent calls to the debounced function return the result of the last
                 * `func` invocation.
                 *
                 * **Note:** If `leading` and `trailing` options are `true`, `func` is invoked
                 * on the trailing edge of the timeout only if the the debounced function is
                 * invoked more than once during the `wait` timeout.
                 *
                 * See [David Corbacho's article](http://drupalmotion.com/article/debounce-and-throttle-visual-explanation)
                 * for details over the differences between `_.debounce` and `_.throttle`.
                 *
                 * @static
                 * @memberOf _
                 * @category Function
                 * @param {Function} func The function to debounce.
                 * @param {number} [wait=0] The number of milliseconds to delay.
                 * @param {Object} [options] The options object.
                 * @param {boolean} [options.leading=false] Specify invoking on the leading
                 *  edge of the timeout.
                 * @param {number} [options.maxWait] The maximum time `func` is allowed to be
                 *  delayed before it's invoked.
                 * @param {boolean} [options.trailing=true] Specify invoking on the trailing
                 *  edge of the timeout.
                 * @returns {Function} Returns the new debounced function.
                 * @example
                 *
                 * // avoid costly calculations while the window size is in flux
                 * jQuery(window).on('resize', _.debounce(calculateLayout, 150));
                 *
                 * // invoke `sendMail` when the click event is fired, debouncing subsequent calls
                 * jQuery('#postbox').on('click', _.debounce(sendMail, 300, {
                 *   'leading': true,
                 *   'trailing': false
                 * }));
                 *
                 * // ensure `batchLog` is invoked once after 1 second of debounced calls
                 * var source = new EventSource('/stream');
                 * jQuery(source).on('message', _.debounce(batchLog, 250, {
                 *   'maxWait': 1000
                 * }));
                 *
                 * // cancel a debounced call
                 * var todoChanges = _.debounce(batchLog, 1000);
                 * Object.observe(models.todo, todoChanges);
                 *
                 * Object.observe(models, function(changes) {
                 *   if (_.find(changes, { 'user': 'todo', 'type': 'delete'})) {
                 *     todoChanges.cancel();
                 *   }
                 * }, ['delete']);
                 *
                 * // ...at some point `models.todo` is changed
                 * models.todo.completed = true;
                 *
                 * // ...before 1 second has passed `models.todo` is deleted
                 * // which cancels the debounced `todoChanges` call
                 * delete models.todo;
                 */
                function debounce(func, wait, options) {
                    var args, maxTimeoutId, result, stamp, thisArg, timeoutId, trailingCall, lastCalled = 0, maxWait = false, trailing = true;
                    if (typeof func != 'function') {
                        throw new TypeError(FUNC_ERROR_TEXT);
                    }
                    wait = wait < 0 ? 0 : (+wait || 0);
                    if (options === true) {
                        var leading = true;
                        trailing = false;
                    }
                    else if (isObject(options)) {
                        leading = !!options.leading;
                        maxWait = 'maxWait' in options && nativeMax(+options.maxWait || 0, wait);
                        trailing = 'trailing' in options ? !!options.trailing : trailing;
                    }
                    function cancel() {
                        if (timeoutId) {
                            clearTimeout(timeoutId);
                        }
                        if (maxTimeoutId) {
                            clearTimeout(maxTimeoutId);
                        }
                        lastCalled = 0;
                        maxTimeoutId = timeoutId = trailingCall = undefined;
                    }
                    function complete(isCalled, id) {
                        if (id) {
                            clearTimeout(id);
                        }
                        maxTimeoutId = timeoutId = trailingCall = undefined;
                        if (isCalled) {
                            lastCalled = now();
                            result = func.apply(thisArg, args);
                            if (!timeoutId && !maxTimeoutId) {
                                args = thisArg = undefined;
                            }
                        }
                    }
                    function delayed() {
                        var remaining = wait - (now() - stamp);
                        if (remaining <= 0 || remaining > wait) {
                            complete(trailingCall, maxTimeoutId);
                        }
                        else {
                            timeoutId = setTimeout(delayed, remaining);
                        }
                    }
                    function maxDelayed() {
                        complete(trailing, timeoutId);
                    }
                    function debounced() {
                        args = arguments;
                        stamp = now();
                        thisArg = this;
                        trailingCall = trailing && (timeoutId || !leading);
                        if (maxWait === false) {
                            var leadingCall = leading && !timeoutId;
                        }
                        else {
                            if (!maxTimeoutId && !leading) {
                                lastCalled = stamp;
                            }
                            var remaining = maxWait - (stamp - lastCalled), isCalled = remaining <= 0 || remaining > maxWait;
                            if (isCalled) {
                                if (maxTimeoutId) {
                                    maxTimeoutId = clearTimeout(maxTimeoutId);
                                }
                                lastCalled = stamp;
                                result = func.apply(thisArg, args);
                            }
                            else if (!maxTimeoutId) {
                                maxTimeoutId = setTimeout(maxDelayed, remaining);
                            }
                        }
                        if (isCalled && timeoutId) {
                            timeoutId = clearTimeout(timeoutId);
                        }
                        else if (!timeoutId && wait !== maxWait) {
                            timeoutId = setTimeout(delayed, wait);
                        }
                        if (leadingCall) {
                            isCalled = true;
                            result = func.apply(thisArg, args);
                        }
                        if (isCalled && !timeoutId && !maxTimeoutId) {
                            args = thisArg = undefined;
                        }
                        return result;
                    }
                    debounced.cancel = cancel;
                    return debounced;
                }
                module.exports = debounce;
            }, { "148": 148, "86": 86 }], 90: [function (require, module, exports) {
                var baseDelay = require(102), restParam = require(91);
                /**
                 * Defers invoking the `func` until the current call stack has cleared. Any
                 * additional arguments are provided to `func` when it's invoked.
                 *
                 * @static
                 * @memberOf _
                 * @category Function
                 * @param {Function} func The function to defer.
                 * @param {...*} [args] The arguments to invoke the function with.
                 * @returns {number} Returns the timer id.
                 * @example
                 *
                 * _.defer(function(text) {
                 *   console.log(text);
                 * }, 'deferred');
                 * // logs 'deferred' after one or more milliseconds
                 */
                var defer = restParam(function (func, args) {
                    return baseDelay(func, 1, args);
                });
                module.exports = defer;
            }, { "102": 102, "91": 91 }], 91: [function (require, module, exports) {
                /** Used as the `TypeError` message for "Functions" methods. */
                var FUNC_ERROR_TEXT = 'Expected a function';
                /* Native method references for those with the same name as other `lodash` methods. */
                var nativeMax = Math.max;
                /**
                 * Creates a function that invokes `func` with the `this` binding of the
                 * created function and arguments from `start` and beyond provided as an array.
                 *
                 * **Note:** This method is based on the [rest parameter](https://developer.mozilla.org/Web/JavaScript/Reference/Functions/rest_parameters).
                 *
                 * @static
                 * @memberOf _
                 * @category Function
                 * @param {Function} func The function to apply a rest parameter to.
                 * @param {number} [start=func.length-1] The start position of the rest parameter.
                 * @returns {Function} Returns the new function.
                 * @example
                 *
                 * var say = _.restParam(function(what, names) {
                 *   return what + ' ' + _.initial(names).join(', ') +
                 *     (_.size(names) > 1 ? ', & ' : '') + _.last(names);
                 * });
                 *
                 * say('hello', 'fred', 'barney', 'pebbles');
                 * // => 'hello fred, barney, & pebbles'
                 */
                function restParam(func, start) {
                    if (typeof func != 'function') {
                        throw new TypeError(FUNC_ERROR_TEXT);
                    }
                    start = nativeMax(start === undefined ? (func.length - 1) : (+start || 0), 0);
                    return function () {
                        var args = arguments, index = -1, length = nativeMax(args.length - start, 0), rest = Array(length);
                        while (++index < length) {
                            rest[index] = args[start + index];
                        }
                        switch (start) {
                            case 0: return func.call(this, rest);
                            case 1: return func.call(this, args[0], rest);
                            case 2: return func.call(this, args[0], args[1], rest);
                        }
                        var otherArgs = Array(start + 1);
                        index = -1;
                        while (++index < start) {
                            otherArgs[index] = args[index];
                        }
                        otherArgs[start] = rest;
                        return func.apply(this, otherArgs);
                    };
                }
                module.exports = restParam;
            }, {}], 92: [function (require, module, exports) {
                var baseCreate = require(101), baseLodash = require(107);
                /** Used as references for `-Infinity` and `Infinity`. */
                var POSITIVE_INFINITY = Number.POSITIVE_INFINITY;
                /**
                 * Creates a lazy wrapper object which wraps `value` to enable lazy evaluation.
                 *
                 * @private
                 * @param {*} value The value to wrap.
                 */
                function LazyWrapper(value) {
                    this.__wrapped__ = value;
                    this.__actions__ = [];
                    this.__dir__ = 1;
                    this.__filtered__ = false;
                    this.__iteratees__ = [];
                    this.__takeCount__ = POSITIVE_INFINITY;
                    this.__views__ = [];
                }
                LazyWrapper.prototype = baseCreate(baseLodash.prototype);
                LazyWrapper.prototype.constructor = LazyWrapper;
                module.exports = LazyWrapper;
            }, { "101": 101, "107": 107 }], 93: [function (require, module, exports) {
                var baseCreate = require(101), baseLodash = require(107);
                /**
                 * The base constructor for creating `lodash` wrapper objects.
                 *
                 * @private
                 * @param {*} value The value to wrap.
                 * @param {boolean} [chainAll] Enable chaining for all wrapper methods.
                 * @param {Array} [actions=[]] Actions to peform to resolve the unwrapped value.
                 */
                function LodashWrapper(value, chainAll, actions) {
                    this.__wrapped__ = value;
                    this.__actions__ = actions || [];
                    this.__chain__ = !!chainAll;
                }
                LodashWrapper.prototype = baseCreate(baseLodash.prototype);
                LodashWrapper.prototype.constructor = LodashWrapper;
                module.exports = LodashWrapper;
            }, { "101": 101, "107": 107 }], 94: [function (require, module, exports) {
                /**
                 * Copies the values of `source` to `array`.
                 *
                 * @private
                 * @param {Array} source The array to copy values from.
                 * @param {Array} [array=[]] The array to copy values to.
                 * @returns {Array} Returns `array`.
                 */
                function arrayCopy(source, array) {
                    var index = -1, length = source.length;
                    array || (array = Array(length));
                    while (++index < length) {
                        array[index] = source[index];
                    }
                    return array;
                }
                module.exports = arrayCopy;
            }, {}], 95: [function (require, module, exports) {
                /**
                 * A specialized version of `_.forEach` for arrays without support for callback
                 * shorthands and `this` binding.
                 *
                 * @private
                 * @param {Array} array The array to iterate over.
                 * @param {Function} iteratee The function invoked per iteration.
                 * @returns {Array} Returns `array`.
                 */
                function arrayEach(array, iteratee) {
                    var index = -1, length = array.length;
                    while (++index < length) {
                        if (iteratee(array[index], index, array) === false) {
                            break;
                        }
                    }
                    return array;
                }
                module.exports = arrayEach;
            }, {}], 96: [function (require, module, exports) {
                /**
                 * Appends the elements of `values` to `array`.
                 *
                 * @private
                 * @param {Array} array The array to modify.
                 * @param {Array} values The values to append.
                 * @returns {Array} Returns `array`.
                 */
                function arrayPush(array, values) {
                    var index = -1, length = values.length, offset = array.length;
                    while (++index < length) {
                        array[offset + index] = values[index];
                    }
                    return array;
                }
                module.exports = arrayPush;
            }, {}], 97: [function (require, module, exports) {
                var keys = require(153);
                /**
                 * A specialized version of `_.assign` for customizing assigned values without
                 * support for argument juggling, multiple sources, and `this` binding `customizer`
                 * functions.
                 *
                 * @private
                 * @param {Object} object The destination object.
                 * @param {Object} source The source object.
                 * @param {Function} customizer The function to customize assigned values.
                 * @returns {Object} Returns `object`.
                 */
                function assignWith(object, source, customizer) {
                    var index = -1, props = keys(source), length = props.length;
                    while (++index < length) {
                        var key = props[index], value = object[key], result = customizer(value, source[key], key, object, source);
                        if ((result === result ? (result !== value) : (value === value)) ||
                            (value === undefined && !(key in object))) {
                            object[key] = result;
                        }
                    }
                    return object;
                }
                module.exports = assignWith;
            }, { "153": 153 }], 98: [function (require, module, exports) {
                var baseCopy = require(100), keys = require(153);
                /**
                 * The base implementation of `_.assign` without support for argument juggling,
                 * multiple sources, and `customizer` functions.
                 *
                 * @private
                 * @param {Object} object The destination object.
                 * @param {Object} source The source object.
                 * @returns {Object} Returns `object`.
                 */
                function baseAssign(object, source) {
                    return source == null
                        ? object
                        : baseCopy(source, keys(source), object);
                }
                module.exports = baseAssign;
            }, { "100": 100, "153": 153 }], 99: [function (require, module, exports) {
                var arrayCopy = require(94), arrayEach = require(95), baseAssign = require(98), baseForOwn = require(105), initCloneArray = require(125), initCloneByTag = require(126), initCloneObject = require(127), isArray = require(145), isObject = require(148);
                /** `Object#toString` result references. */
                var argsTag = '[object Arguments]', arrayTag = '[object Array]', boolTag = '[object Boolean]', dateTag = '[object Date]', errorTag = '[object Error]', funcTag = '[object Function]', mapTag = '[object Map]', numberTag = '[object Number]', objectTag = '[object Object]', regexpTag = '[object RegExp]', setTag = '[object Set]', stringTag = '[object String]', weakMapTag = '[object WeakMap]';
                var arrayBufferTag = '[object ArrayBuffer]', float32Tag = '[object Float32Array]', float64Tag = '[object Float64Array]', int8Tag = '[object Int8Array]', int16Tag = '[object Int16Array]', int32Tag = '[object Int32Array]', uint8Tag = '[object Uint8Array]', uint8ClampedTag = '[object Uint8ClampedArray]', uint16Tag = '[object Uint16Array]', uint32Tag = '[object Uint32Array]';
                /** Used to identify `toStringTag` values supported by `_.clone`. */
                var cloneableTags = {};
                cloneableTags[argsTag] = cloneableTags[arrayTag] =
                    cloneableTags[arrayBufferTag] = cloneableTags[boolTag] =
                        cloneableTags[dateTag] = cloneableTags[float32Tag] =
                            cloneableTags[float64Tag] = cloneableTags[int8Tag] =
                                cloneableTags[int16Tag] = cloneableTags[int32Tag] =
                                    cloneableTags[numberTag] = cloneableTags[objectTag] =
                                        cloneableTags[regexpTag] = cloneableTags[stringTag] =
                                            cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] =
                                                cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true;
                cloneableTags[errorTag] = cloneableTags[funcTag] =
                    cloneableTags[mapTag] = cloneableTags[setTag] =
                        cloneableTags[weakMapTag] = false;
                /** Used for native method references. */
                var objectProto = Object.prototype;
                /**
                 * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring)
                 * of values.
                 */
                var objToString = objectProto.toString;
                /**
                 * The base implementation of `_.clone` without support for argument juggling
                 * and `this` binding `customizer` functions.
                 *
                 * @private
                 * @param {*} value The value to clone.
                 * @param {boolean} [isDeep] Specify a deep clone.
                 * @param {Function} [customizer] The function to customize cloning values.
                 * @param {string} [key] The key of `value`.
                 * @param {Object} [object] The object `value` belongs to.
                 * @param {Array} [stackA=[]] Tracks traversed source objects.
                 * @param {Array} [stackB=[]] Associates clones with source counterparts.
                 * @returns {*} Returns the cloned value.
                 */
                function baseClone(value, isDeep, customizer, key, object, stackA, stackB) {
                    var result;
                    if (customizer) {
                        result = object ? customizer(value, key, object) : customizer(value);
                    }
                    if (result !== undefined) {
                        return result;
                    }
                    if (!isObject(value)) {
                        return value;
                    }
                    var isArr = isArray(value);
                    if (isArr) {
                        result = initCloneArray(value);
                        if (!isDeep) {
                            return arrayCopy(value, result);
                        }
                    }
                    else {
                        var tag = objToString.call(value), isFunc = tag == funcTag;
                        if (tag == objectTag || tag == argsTag || (isFunc && !object)) {
                            result = initCloneObject(isFunc ? {} : value);
                            if (!isDeep) {
                                return baseAssign(result, value);
                            }
                        }
                        else {
                            return cloneableTags[tag]
                                ? initCloneByTag(value, tag, isDeep)
                                : (object ? value : {});
                        }
                    }
                    // Check for circular references and return its corresponding clone.
                    stackA || (stackA = []);
                    stackB || (stackB = []);
                    var length = stackA.length;
                    while (length--) {
                        if (stackA[length] == value) {
                            return stackB[length];
                        }
                    }
                    // Add the source value to the stack of traversed objects and associate it with its clone.
                    stackA.push(value);
                    stackB.push(result);
                    // Recursively populate clone (susceptible to call stack limits).
                    (isArr ? arrayEach : baseForOwn)(value, function (subValue, key) {
                        result[key] = baseClone(subValue, isDeep, customizer, key, value, stackA, stackB);
                    });
                    return result;
                }
                module.exports = baseClone;
            }, { "105": 105, "125": 125, "126": 126, "127": 127, "145": 145, "148": 148, "94": 94, "95": 95, "98": 98 }], 100: [function (require, module, exports) {
                /**
                 * Copies properties of `source` to `object`.
                 *
                 * @private
                 * @param {Object} source The object to copy properties from.
                 * @param {Array} props The property names to copy.
                 * @param {Object} [object={}] The object to copy properties to.
                 * @returns {Object} Returns `object`.
                 */
                function baseCopy(source, props, object) {
                    object || (object = {});
                    var index = -1, length = props.length;
                    while (++index < length) {
                        var key = props[index];
                        object[key] = source[key];
                    }
                    return object;
                }
                module.exports = baseCopy;
            }, {}], 101: [function (require, module, exports) {
                var isObject = require(148);
                /**
                 * The base implementation of `_.create` without support for assigning
                 * properties to the created object.
                 *
                 * @private
                 * @param {Object} prototype The object to inherit from.
                 * @returns {Object} Returns the new object.
                 */
                var baseCreate = (function () {
                    function object() { }
                    return function (prototype) {
                        if (isObject(prototype)) {
                            object.prototype = prototype;
                            var result = new object;
                            object.prototype = undefined;
                        }
                        return result || {};
                    };
                }());
                module.exports = baseCreate;
            }, { "148": 148 }], 102: [function (require, module, exports) {
                /** Used as the `TypeError` message for "Functions" methods. */
                var FUNC_ERROR_TEXT = 'Expected a function';
                /**
                 * The base implementation of `_.delay` and `_.defer` which accepts an index
                 * of where to slice the arguments to provide to `func`.
                 *
                 * @private
                 * @param {Function} func The function to delay.
                 * @param {number} wait The number of milliseconds to delay invocation.
                 * @param {Object} args The arguments provide to `func`.
                 * @returns {number} Returns the timer id.
                 */
                function baseDelay(func, wait, args) {
                    if (typeof func != 'function') {
                        throw new TypeError(FUNC_ERROR_TEXT);
                    }
                    return setTimeout(function () { func.apply(undefined, args); }, wait);
                }
                module.exports = baseDelay;
            }, {}], 103: [function (require, module, exports) {
                var arrayPush = require(96), isArguments = require(144), isArray = require(145), isArrayLike = require(128), isObjectLike = require(133);
                /**
                 * The base implementation of `_.flatten` with added support for restricting
                 * flattening and specifying the start index.
                 *
                 * @private
                 * @param {Array} array The array to flatten.
                 * @param {boolean} [isDeep] Specify a deep flatten.
                 * @param {boolean} [isStrict] Restrict flattening to arrays-like objects.
                 * @param {Array} [result=[]] The initial result value.
                 * @returns {Array} Returns the new flattened array.
                 */
                function baseFlatten(array, isDeep, isStrict, result) {
                    result || (result = []);
                    var index = -1, length = array.length;
                    while (++index < length) {
                        var value = array[index];
                        if (isObjectLike(value) && isArrayLike(value) &&
                            (isStrict || isArray(value) || isArguments(value))) {
                            if (isDeep) {
                                // Recursively flatten arrays (susceptible to call stack limits).
                                baseFlatten(value, isDeep, isStrict, result);
                            }
                            else {
                                arrayPush(result, value);
                            }
                        }
                        else if (!isStrict) {
                            result[result.length] = value;
                        }
                    }
                    return result;
                }
                module.exports = baseFlatten;
            }, { "128": 128, "133": 133, "144": 144, "145": 145, "96": 96 }], 104: [function (require, module, exports) {
                var createBaseFor = require(115);
                /**
                 * The base implementation of `baseForIn` and `baseForOwn` which iterates
                 * over `object` properties returned by `keysFunc` invoking `iteratee` for
                 * each property. Iteratee functions may exit iteration early by explicitly
                 * returning `false`.
                 *
                 * @private
                 * @param {Object} object The object to iterate over.
                 * @param {Function} iteratee The function invoked per iteration.
                 * @param {Function} keysFunc The function to get the keys of `object`.
                 * @returns {Object} Returns `object`.
                 */
                var baseFor = createBaseFor();
                module.exports = baseFor;
            }, { "115": 115 }], 105: [function (require, module, exports) {
                var baseFor = require(104), keys = require(153);
                /**
                 * The base implementation of `_.forOwn` without support for callback
                 * shorthands and `this` binding.
                 *
                 * @private
                 * @param {Object} object The object to iterate over.
                 * @param {Function} iteratee The function invoked per iteration.
                 * @returns {Object} Returns `object`.
                 */
                function baseForOwn(object, iteratee) {
                    return baseFor(object, iteratee, keys);
                }
                module.exports = baseForOwn;
            }, { "104": 104, "153": 153 }], 106: [function (require, module, exports) {
                var isFunction = require(146);
                /**
                 * The base implementation of `_.functions` which creates an array of
                 * `object` function property names filtered from those provided.
                 *
                 * @private
                 * @param {Object} object The object to inspect.
                 * @param {Array} props The property names to filter.
                 * @returns {Array} Returns the new array of filtered property names.
                 */
                function baseFunctions(object, props) {
                    var index = -1, length = props.length, resIndex = -1, result = [];
                    while (++index < length) {
                        var key = props[index];
                        if (isFunction(object[key])) {
                            result[++resIndex] = key;
                        }
                    }
                    return result;
                }
                module.exports = baseFunctions;
            }, { "146": 146 }], 107: [function (require, module, exports) {
                /**
                 * The function whose prototype all chaining wrappers inherit from.
                 *
                 * @private
                 */
                function baseLodash() {
                    // No operation performed.
                }
                module.exports = baseLodash;
            }, {}], 108: [function (require, module, exports) {
                /**
                 * The base implementation of `_.property` without support for deep paths.
                 *
                 * @private
                 * @param {string} key The key of the property to get.
                 * @returns {Function} Returns the new function.
                 */
                function baseProperty(key) {
                    return function (object) {
                        return object == null ? undefined : object[key];
                    };
                }
                module.exports = baseProperty;
            }, {}], 109: [function (require, module, exports) {
                var identity = require(155), metaMap = require(135);
                /**
                 * The base implementation of `setData` without support for hot loop detection.
                 *
                 * @private
                 * @param {Function} func The function to associate metadata with.
                 * @param {*} data The metadata.
                 * @returns {Function} Returns `func`.
                 */
                var baseSetData = !metaMap ? identity : function (func, data) {
                    metaMap.set(func, data);
                    return func;
                };
                module.exports = baseSetData;
            }, { "135": 135, "155": 155 }], 110: [function (require, module, exports) {
                var identity = require(155);
                /**
                 * A specialized version of `baseCallback` which only supports `this` binding
                 * and specifying the number of arguments to provide to `func`.
                 *
                 * @private
                 * @param {Function} func The function to bind.
                 * @param {*} thisArg The `this` binding of `func`.
                 * @param {number} [argCount] The number of arguments to provide to `func`.
                 * @returns {Function} Returns the callback.
                 */
                function bindCallback(func, thisArg, argCount) {
                    if (typeof func != 'function') {
                        return identity;
                    }
                    if (thisArg === undefined) {
                        return func;
                    }
                    switch (argCount) {
                        case 1: return function (value) {
                            return func.call(thisArg, value);
                        };
                        case 3: return function (value, index, collection) {
                            return func.call(thisArg, value, index, collection);
                        };
                        case 4: return function (accumulator, value, index, collection) {
                            return func.call(thisArg, accumulator, value, index, collection);
                        };
                        case 5: return function (value, other, key, object, source) {
                            return func.call(thisArg, value, other, key, object, source);
                        };
                    }
                    return function () {
                        return func.apply(thisArg, arguments);
                    };
                }
                module.exports = bindCallback;
            }, { "155": 155 }], 111: [function (require, module, exports) {
                (function (global) {
                    /** Native method references. */
                    var ArrayBuffer = global.ArrayBuffer, Uint8Array = global.Uint8Array;
                    /**
                     * Creates a clone of the given array buffer.
                     *
                     * @private
                     * @param {ArrayBuffer} buffer The array buffer to clone.
                     * @returns {ArrayBuffer} Returns the cloned array buffer.
                     */
                    function bufferClone(buffer) {
                        var result = new ArrayBuffer(buffer.byteLength), view = new Uint8Array(result);
                        view.set(new Uint8Array(buffer));
                        return result;
                    }
                    module.exports = bufferClone;
                }).call(this, typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {});
            }, {}], 112: [function (require, module, exports) {
                /* Native method references for those with the same name as other `lodash` methods. */
                var nativeMax = Math.max;
                /**
                 * Creates an array that is the composition of partially applied arguments,
                 * placeholders, and provided arguments into a single array of arguments.
                 *
                 * @private
                 * @param {Array|Object} args The provided arguments.
                 * @param {Array} partials The arguments to prepend to those provided.
                 * @param {Array} holders The `partials` placeholder indexes.
                 * @returns {Array} Returns the new array of composed arguments.
                 */
                function composeArgs(args, partials, holders) {
                    var holdersLength = holders.length, argsIndex = -1, argsLength = nativeMax(args.length - holdersLength, 0), leftIndex = -1, leftLength = partials.length, result = Array(leftLength + argsLength);
                    while (++leftIndex < leftLength) {
                        result[leftIndex] = partials[leftIndex];
                    }
                    while (++argsIndex < holdersLength) {
                        result[holders[argsIndex]] = args[argsIndex];
                    }
                    while (argsLength--) {
                        result[leftIndex++] = args[argsIndex++];
                    }
                    return result;
                }
                module.exports = composeArgs;
            }, {}], 113: [function (require, module, exports) {
                /* Native method references for those with the same name as other `lodash` methods. */
                var nativeMax = Math.max;
                /**
                 * This function is like `composeArgs` except that the arguments composition
                 * is tailored for `_.partialRight`.
                 *
                 * @private
                 * @param {Array|Object} args The provided arguments.
                 * @param {Array} partials The arguments to append to those provided.
                 * @param {Array} holders The `partials` placeholder indexes.
                 * @returns {Array} Returns the new array of composed arguments.
                 */
                function composeArgsRight(args, partials, holders) {
                    var holdersIndex = -1, holdersLength = holders.length, argsIndex = -1, argsLength = nativeMax(args.length - holdersLength, 0), rightIndex = -1, rightLength = partials.length, result = Array(argsLength + rightLength);
                    while (++argsIndex < argsLength) {
                        result[argsIndex] = args[argsIndex];
                    }
                    var offset = argsIndex;
                    while (++rightIndex < rightLength) {
                        result[offset + rightIndex] = partials[rightIndex];
                    }
                    while (++holdersIndex < holdersLength) {
                        result[offset + holders[holdersIndex]] = args[argsIndex++];
                    }
                    return result;
                }
                module.exports = composeArgsRight;
            }, {}], 114: [function (require, module, exports) {
                var bindCallback = require(110), isIterateeCall = require(130), restParam = require(91);
                /**
                 * Creates a `_.assign`, `_.defaults`, or `_.merge` function.
                 *
                 * @private
                 * @param {Function} assigner The function to assign values.
                 * @returns {Function} Returns the new assigner function.
                 */
                function createAssigner(assigner) {
                    return restParam(function (object, sources) {
                        var index = -1, length = object == null ? 0 : sources.length, customizer = length > 2 ? sources[length - 2] : undefined, guard = length > 2 ? sources[2] : undefined, thisArg = length > 1 ? sources[length - 1] : undefined;
                        if (typeof customizer == 'function') {
                            customizer = bindCallback(customizer, thisArg, 5);
                            length -= 2;
                        }
                        else {
                            customizer = typeof thisArg == 'function' ? thisArg : undefined;
                            length -= (customizer ? 1 : 0);
                        }
                        if (guard && isIterateeCall(sources[0], sources[1], guard)) {
                            customizer = length < 3 ? undefined : customizer;
                            length = 1;
                        }
                        while (++index < length) {
                            var source = sources[index];
                            if (source) {
                                assigner(object, source, customizer);
                            }
                        }
                        return object;
                    });
                }
                module.exports = createAssigner;
            }, { "110": 110, "130": 130, "91": 91 }], 115: [function (require, module, exports) {
                var toObject = require(141);
                /**
                 * Creates a base function for `_.forIn` or `_.forInRight`.
                 *
                 * @private
                 * @param {boolean} [fromRight] Specify iterating from right to left.
                 * @returns {Function} Returns the new base function.
                 */
                function createBaseFor(fromRight) {
                    return function (object, iteratee, keysFunc) {
                        var iterable = toObject(object), props = keysFunc(object), length = props.length, index = fromRight ? length : -1;
                        while ((fromRight ? index-- : ++index < length)) {
                            var key = props[index];
                            if (iteratee(iterable[key], key, iterable) === false) {
                                break;
                            }
                        }
                        return object;
                    };
                }
                module.exports = createBaseFor;
            }, { "141": 141 }], 116: [function (require, module, exports) {
                (function (global) {
                    var createCtorWrapper = require(117);
                    /**
                     * Creates a function that wraps `func` and invokes it with the `this`
                     * binding of `thisArg`.
                     *
                     * @private
                     * @param {Function} func The function to bind.
                     * @param {*} [thisArg] The `this` binding of `func`.
                     * @returns {Function} Returns the new bound function.
                     */
                    function createBindWrapper(func, thisArg) {
                        var Ctor = createCtorWrapper(func);
                        function wrapper() {
                            var fn = (this && this !== global && this instanceof wrapper) ? Ctor : func;
                            return fn.apply(thisArg, arguments);
                        }
                        return wrapper;
                    }
                    module.exports = createBindWrapper;
                }).call(this, typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {});
            }, { "117": 117 }], 117: [function (require, module, exports) {
                var baseCreate = require(101), isObject = require(148);
                /**
                 * Creates a function that produces an instance of `Ctor` regardless of
                 * whether it was invoked as part of a `new` expression or by `call` or `apply`.
                 *
                 * @private
                 * @param {Function} Ctor The constructor to wrap.
                 * @returns {Function} Returns the new wrapped function.
                 */
                function createCtorWrapper(Ctor) {
                    return function () {
                        // Use a `switch` statement to work with class constructors.
                        // See http://ecma-international.org/ecma-262/6.0/#sec-ecmascript-function-objects-call-thisargument-argumentslist
                        // for more details.
                        var args = arguments;
                        switch (args.length) {
                            case 0: return new Ctor;
                            case 1: return new Ctor(args[0]);
                            case 2: return new Ctor(args[0], args[1]);
                            case 3: return new Ctor(args[0], args[1], args[2]);
                            case 4: return new Ctor(args[0], args[1], args[2], args[3]);
                            case 5: return new Ctor(args[0], args[1], args[2], args[3], args[4]);
                            case 6: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5]);
                            case 7: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
                        }
                        var thisBinding = baseCreate(Ctor.prototype), result = Ctor.apply(thisBinding, args);
                        // Mimic the constructor's `return` behavior.
                        // See https://es5.github.io/#x13.2.2 for more details.
                        return isObject(result) ? result : thisBinding;
                    };
                }
                module.exports = createCtorWrapper;
            }, { "101": 101, "148": 148 }], 118: [function (require, module, exports) {
                (function (global) {
                    var arrayCopy = require(94), composeArgs = require(112), composeArgsRight = require(113), createCtorWrapper = require(117), isLaziable = require(131), reorder = require(137), replaceHolders = require(138), setData = require(139);
                    /** Used to compose bitmasks for wrapper metadata. */
                    var BIND_FLAG = 1, BIND_KEY_FLAG = 2, CURRY_BOUND_FLAG = 4, CURRY_FLAG = 8, CURRY_RIGHT_FLAG = 16, PARTIAL_FLAG = 32, PARTIAL_RIGHT_FLAG = 64, ARY_FLAG = 128;
                    /* Native method references for those with the same name as other `lodash` methods. */
                    var nativeMax = Math.max;
                    /**
                     * Creates a function that wraps `func` and invokes it with optional `this`
                     * binding of, partial application, and currying.
                     *
                     * @private
                     * @param {Function|string} func The function or method name to reference.
                     * @param {number} bitmask The bitmask of flags. See `createWrapper` for more details.
                     * @param {*} [thisArg] The `this` binding of `func`.
                     * @param {Array} [partials] The arguments to prepend to those provided to the new function.
                     * @param {Array} [holders] The `partials` placeholder indexes.
                     * @param {Array} [partialsRight] The arguments to append to those provided to the new function.
                     * @param {Array} [holdersRight] The `partialsRight` placeholder indexes.
                     * @param {Array} [argPos] The argument positions of the new function.
                     * @param {number} [ary] The arity cap of `func`.
                     * @param {number} [arity] The arity of `func`.
                     * @returns {Function} Returns the new wrapped function.
                     */
                    function createHybridWrapper(func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity) {
                        var isAry = bitmask & ARY_FLAG, isBind = bitmask & BIND_FLAG, isBindKey = bitmask & BIND_KEY_FLAG, isCurry = bitmask & CURRY_FLAG, isCurryBound = bitmask & CURRY_BOUND_FLAG, isCurryRight = bitmask & CURRY_RIGHT_FLAG, Ctor = isBindKey ? undefined : createCtorWrapper(func);
                        function wrapper() {
                            // Avoid `arguments` object use disqualifying optimizations by
                            // converting it to an array before providing it to other functions.
                            var length = arguments.length, index = length, args = Array(length);
                            while (index--) {
                                args[index] = arguments[index];
                            }
                            if (partials) {
                                args = composeArgs(args, partials, holders);
                            }
                            if (partialsRight) {
                                args = composeArgsRight(args, partialsRight, holdersRight);
                            }
                            if (isCurry || isCurryRight) {
                                var placeholder = wrapper.placeholder, argsHolders = replaceHolders(args, placeholder);
                                length -= argsHolders.length;
                                if (length < arity) {
                                    var newArgPos = argPos ? arrayCopy(argPos) : undefined, newArity = nativeMax(arity - length, 0), newsHolders = isCurry ? argsHolders : undefined, newHoldersRight = isCurry ? undefined : argsHolders, newPartials = isCurry ? args : undefined, newPartialsRight = isCurry ? undefined : args;
                                    bitmask |= (isCurry ? PARTIAL_FLAG : PARTIAL_RIGHT_FLAG);
                                    bitmask &= ~(isCurry ? PARTIAL_RIGHT_FLAG : PARTIAL_FLAG);
                                    if (!isCurryBound) {
                                        bitmask &= ~(BIND_FLAG | BIND_KEY_FLAG);
                                    }
                                    var newData = [func, bitmask, thisArg, newPartials, newsHolders, newPartialsRight, newHoldersRight, newArgPos, ary, newArity], result = createHybridWrapper.apply(undefined, newData);
                                    if (isLaziable(func)) {
                                        setData(result, newData);
                                    }
                                    result.placeholder = placeholder;
                                    return result;
                                }
                            }
                            var thisBinding = isBind ? thisArg : this, fn = isBindKey ? thisBinding[func] : func;
                            if (argPos) {
                                args = reorder(args, argPos);
                            }
                            if (isAry && ary < args.length) {
                                args.length = ary;
                            }
                            if (this && this !== global && this instanceof wrapper) {
                                fn = Ctor || createCtorWrapper(func);
                            }
                            return fn.apply(thisBinding, args);
                        }
                        return wrapper;
                    }
                    module.exports = createHybridWrapper;
                }).call(this, typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {});
            }, { "112": 112, "113": 113, "117": 117, "131": 131, "137": 137, "138": 138, "139": 139, "94": 94 }], 119: [function (require, module, exports) {
                (function (global) {
                    var createCtorWrapper = require(117);
                    /** Used to compose bitmasks for wrapper metadata. */
                    var BIND_FLAG = 1;
                    /**
                     * Creates a function that wraps `func` and invokes it with the optional `this`
                     * binding of `thisArg` and the `partials` prepended to those provided to
                     * the wrapper.
                     *
                     * @private
                     * @param {Function} func The function to partially apply arguments to.
                     * @param {number} bitmask The bitmask of flags. See `createWrapper` for more details.
                     * @param {*} thisArg The `this` binding of `func`.
                     * @param {Array} partials The arguments to prepend to those provided to the new function.
                     * @returns {Function} Returns the new bound function.
                     */
                    function createPartialWrapper(func, bitmask, thisArg, partials) {
                        var isBind = bitmask & BIND_FLAG, Ctor = createCtorWrapper(func);
                        function wrapper() {
                            // Avoid `arguments` object use disqualifying optimizations by
                            // converting it to an array before providing it `func`.
                            var argsIndex = -1, argsLength = arguments.length, leftIndex = -1, leftLength = partials.length, args = Array(leftLength + argsLength);
                            while (++leftIndex < leftLength) {
                                args[leftIndex] = partials[leftIndex];
                            }
                            while (argsLength--) {
                                args[leftIndex++] = arguments[++argsIndex];
                            }
                            var fn = (this && this !== global && this instanceof wrapper) ? Ctor : func;
                            return fn.apply(isBind ? thisArg : this, args);
                        }
                        return wrapper;
                    }
                    module.exports = createPartialWrapper;
                }).call(this, typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {});
            }, { "117": 117 }], 120: [function (require, module, exports) {
                var baseSetData = require(109), createBindWrapper = require(116), createHybridWrapper = require(118), createPartialWrapper = require(119), getData = require(121), mergeData = require(134), setData = require(139);
                /** Used to compose bitmasks for wrapper metadata. */
                var BIND_FLAG = 1, BIND_KEY_FLAG = 2, PARTIAL_FLAG = 32, PARTIAL_RIGHT_FLAG = 64;
                /** Used as the `TypeError` message for "Functions" methods. */
                var FUNC_ERROR_TEXT = 'Expected a function';
                /* Native method references for those with the same name as other `lodash` methods. */
                var nativeMax = Math.max;
                /**
                 * Creates a function that either curries or invokes `func` with optional
                 * `this` binding and partially applied arguments.
                 *
                 * @private
                 * @param {Function|string} func The function or method name to reference.
                 * @param {number} bitmask The bitmask of flags.
                 *  The bitmask may be composed of the following flags:
                 *     1 - `_.bind`
                 *     2 - `_.bindKey`
                 *     4 - `_.curry` or `_.curryRight` of a bound function
                 *     8 - `_.curry`
                 *    16 - `_.curryRight`
                 *    32 - `_.partial`
                 *    64 - `_.partialRight`
                 *   128 - `_.rearg`
                 *   256 - `_.ary`
                 * @param {*} [thisArg] The `this` binding of `func`.
                 * @param {Array} [partials] The arguments to be partially applied.
                 * @param {Array} [holders] The `partials` placeholder indexes.
                 * @param {Array} [argPos] The argument positions of the new function.
                 * @param {number} [ary] The arity cap of `func`.
                 * @param {number} [arity] The arity of `func`.
                 * @returns {Function} Returns the new wrapped function.
                 */
                function createWrapper(func, bitmask, thisArg, partials, holders, argPos, ary, arity) {
                    var isBindKey = bitmask & BIND_KEY_FLAG;
                    if (!isBindKey && typeof func != 'function') {
                        throw new TypeError(FUNC_ERROR_TEXT);
                    }
                    var length = partials ? partials.length : 0;
                    if (!length) {
                        bitmask &= ~(PARTIAL_FLAG | PARTIAL_RIGHT_FLAG);
                        partials = holders = undefined;
                    }
                    length -= (holders ? holders.length : 0);
                    if (bitmask & PARTIAL_RIGHT_FLAG) {
                        var partialsRight = partials, holdersRight = holders;
                        partials = holders = undefined;
                    }
                    var data = isBindKey ? undefined : getData(func), newData = [func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity];
                    if (data) {
                        mergeData(newData, data);
                        bitmask = newData[1];
                        arity = newData[9];
                    }
                    newData[9] = arity == null
                        ? (isBindKey ? 0 : func.length)
                        : (nativeMax(arity - length, 0) || 0);
                    if (bitmask == BIND_FLAG) {
                        var result = createBindWrapper(newData[0], newData[2]);
                    }
                    else if ((bitmask == PARTIAL_FLAG || bitmask == (BIND_FLAG | PARTIAL_FLAG)) && !newData[4].length) {
                        result = createPartialWrapper.apply(undefined, newData);
                    }
                    else {
                        result = createHybridWrapper.apply(undefined, newData);
                    }
                    var setter = data ? baseSetData : setData;
                    return setter(result, newData);
                }
                module.exports = createWrapper;
            }, { "109": 109, "116": 116, "118": 118, "119": 119, "121": 121, "134": 134, "139": 139 }], 121: [function (require, module, exports) {
                var metaMap = require(135), noop = require(156);
                /**
                 * Gets metadata for `func`.
                 *
                 * @private
                 * @param {Function} func The function to query.
                 * @returns {*} Returns the metadata for `func`.
                 */
                var getData = !metaMap ? noop : function (func) {
                    return metaMap.get(func);
                };
                module.exports = getData;
            }, { "135": 135, "156": 156 }], 122: [function (require, module, exports) {
                var realNames = require(136);
                /**
                 * Gets the name of `func`.
                 *
                 * @private
                 * @param {Function} func The function to query.
                 * @returns {string} Returns the function name.
                 */
                function getFuncName(func) {
                    var result = (func.name + ''), array = realNames[result], length = array ? array.length : 0;
                    while (length--) {
                        var data = array[length], otherFunc = data.func;
                        if (otherFunc == null || otherFunc == func) {
                            return data.name;
                        }
                    }
                    return result;
                }
                module.exports = getFuncName;
            }, { "136": 136 }], 123: [function (require, module, exports) {
                var baseProperty = require(108);
                /**
                 * Gets the "length" property value of `object`.
                 *
                 * **Note:** This function is used to avoid a [JIT bug](https://bugs.webkit.org/show_bug.cgi?id=142792)
                 * that affects Safari on at least iOS 8.1-8.3 ARM64.
                 *
                 * @private
                 * @param {Object} object The object to query.
                 * @returns {*} Returns the "length" value.
                 */
                var getLength = baseProperty('length');
                module.exports = getLength;
            }, { "108": 108 }], 124: [function (require, module, exports) {
                var isNative = require(147);
                /**
                 * Gets the native function at `key` of `object`.
                 *
                 * @private
                 * @param {Object} object The object to query.
                 * @param {string} key The key of the method to get.
                 * @returns {*} Returns the function if it's native, else `undefined`.
                 */
                function getNative(object, key) {
                    var value = object == null ? undefined : object[key];
                    return isNative(value) ? value : undefined;
                }
                module.exports = getNative;
            }, { "147": 147 }], 125: [function (require, module, exports) {
                /** Used for native method references. */
                var objectProto = Object.prototype;
                /** Used to check objects for own properties. */
                var hasOwnProperty = objectProto.hasOwnProperty;
                /**
                 * Initializes an array clone.
                 *
                 * @private
                 * @param {Array} array The array to clone.
                 * @returns {Array} Returns the initialized clone.
                 */
                function initCloneArray(array) {
                    var length = array.length, result = new array.constructor(length);
                    // Add array properties assigned by `RegExp#exec`.
                    if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) {
                        result.index = array.index;
                        result.input = array.input;
                    }
                    return result;
                }
                module.exports = initCloneArray;
            }, {}], 126: [function (require, module, exports) {
                var bufferClone = require(111);
                /** `Object#toString` result references. */
                var boolTag = '[object Boolean]', dateTag = '[object Date]', numberTag = '[object Number]', regexpTag = '[object RegExp]', stringTag = '[object String]';
                var arrayBufferTag = '[object ArrayBuffer]', float32Tag = '[object Float32Array]', float64Tag = '[object Float64Array]', int8Tag = '[object Int8Array]', int16Tag = '[object Int16Array]', int32Tag = '[object Int32Array]', uint8Tag = '[object Uint8Array]', uint8ClampedTag = '[object Uint8ClampedArray]', uint16Tag = '[object Uint16Array]', uint32Tag = '[object Uint32Array]';
                /** Used to match `RegExp` flags from their coerced string values. */
                var reFlags = /\w*$/;
                /**
                 * Initializes an object clone based on its `toStringTag`.
                 *
                 * **Note:** This function only supports cloning values with tags of
                 * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`.
                 *
                 * @private
                 * @param {Object} object The object to clone.
                 * @param {string} tag The `toStringTag` of the object to clone.
                 * @param {boolean} [isDeep] Specify a deep clone.
                 * @returns {Object} Returns the initialized clone.
                 */
                function initCloneByTag(object, tag, isDeep) {
                    var Ctor = object.constructor;
                    switch (tag) {
                        case arrayBufferTag:
                            return bufferClone(object);
                        case boolTag:
                        case dateTag:
                            return new Ctor(+object);
                        case float32Tag:
                        case float64Tag:
                        case int8Tag:
                        case int16Tag:
                        case int32Tag:
                        case uint8Tag:
                        case uint8ClampedTag:
                        case uint16Tag:
                        case uint32Tag:
                            var buffer = object.buffer;
                            return new Ctor(isDeep ? bufferClone(buffer) : buffer, object.byteOffset, object.length);
                        case numberTag:
                        case stringTag:
                            return new Ctor(object);
                        case regexpTag:
                            var result = new Ctor(object.source, reFlags.exec(object));
                            result.lastIndex = object.lastIndex;
                    }
                    return result;
                }
                module.exports = initCloneByTag;
            }, { "111": 111 }], 127: [function (require, module, exports) {
                /**
                 * Initializes an object clone.
                 *
                 * @private
                 * @param {Object} object The object to clone.
                 * @returns {Object} Returns the initialized clone.
                 */
                function initCloneObject(object) {
                    var Ctor = object.constructor;
                    if (!(typeof Ctor == 'function' && Ctor instanceof Ctor)) {
                        Ctor = Object;
                    }
                    return new Ctor;
                }
                module.exports = initCloneObject;
            }, {}], 128: [function (require, module, exports) {
                var getLength = require(123), isLength = require(132);
                /**
                 * Checks if `value` is array-like.
                 *
                 * @private
                 * @param {*} value The value to check.
                 * @returns {boolean} Returns `true` if `value` is array-like, else `false`.
                 */
                function isArrayLike(value) {
                    return value != null && isLength(getLength(value));
                }
                module.exports = isArrayLike;
            }, { "123": 123, "132": 132 }], 129: [function (require, module, exports) {
                /** Used to detect unsigned integer values. */
                var reIsUint = /^\d+$/;
                /**
                 * Used as the [maximum length](http://ecma-international.org/ecma-262/6.0/#sec-number.max_safe_integer)
                 * of an array-like value.
                 */
                var MAX_SAFE_INTEGER = 9007199254740991;
                /**
                 * Checks if `value` is a valid array-like index.
                 *
                 * @private
                 * @param {*} value The value to check.
                 * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.
                 * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.
                 */
                function isIndex(value, length) {
                    value = (typeof value == 'number' || reIsUint.test(value)) ? +value : -1;
                    length = length == null ? MAX_SAFE_INTEGER : length;
                    return value > -1 && value % 1 == 0 && value < length;
                }
                module.exports = isIndex;
            }, {}], 130: [function (require, module, exports) {
                var isArrayLike = require(128), isIndex = require(129), isObject = require(148);
                /**
                 * Checks if the provided arguments are from an iteratee call.
                 *
                 * @private
                 * @param {*} value The potential iteratee value argument.
                 * @param {*} index The potential iteratee index or key argument.
                 * @param {*} object The potential iteratee object argument.
                 * @returns {boolean} Returns `true` if the arguments are from an iteratee call, else `false`.
                 */
                function isIterateeCall(value, index, object) {
                    if (!isObject(object)) {
                        return false;
                    }
                    var type = typeof index;
                    if (type == 'number'
                        ? (isArrayLike(object) && isIndex(index, object.length))
                        : (type == 'string' && index in object)) {
                        var other = object[index];
                        return value === value ? (value === other) : (other !== other);
                    }
                    return false;
                }
                module.exports = isIterateeCall;
            }, { "128": 128, "129": 129, "148": 148 }], 131: [function (require, module, exports) {
                var LazyWrapper = require(92), getData = require(121), getFuncName = require(122), lodash = require(85);
                /**
                 * Checks if `func` has a lazy counterpart.
                 *
                 * @private
                 * @param {Function} func The function to check.
                 * @returns {boolean} Returns `true` if `func` has a lazy counterpart, else `false`.
                 */
                function isLaziable(func) {
                    var funcName = getFuncName(func), other = lodash[funcName];
                    if (typeof other != 'function' || !(funcName in LazyWrapper.prototype)) {
                        return false;
                    }
                    if (func === other) {
                        return true;
                    }
                    var data = getData(other);
                    return !!data && func === data[0];
                }
                module.exports = isLaziable;
            }, { "121": 121, "122": 122, "85": 85, "92": 92 }], 132: [function (require, module, exports) {
                /**
                 * Used as the [maximum length](http://ecma-international.org/ecma-262/6.0/#sec-number.max_safe_integer)
                 * of an array-like value.
                 */
                var MAX_SAFE_INTEGER = 9007199254740991;
                /**
                 * Checks if `value` is a valid array-like length.
                 *
                 * **Note:** This function is based on [`ToLength`](http://ecma-international.org/ecma-262/6.0/#sec-tolength).
                 *
                 * @private
                 * @param {*} value The value to check.
                 * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.
                 */
                function isLength(value) {
                    return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
                }
                module.exports = isLength;
            }, {}], 133: [function (require, module, exports) {
                /**
                 * Checks if `value` is object-like.
                 *
                 * @private
                 * @param {*} value The value to check.
                 * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
                 */
                function isObjectLike(value) {
                    return !!value && typeof value == 'object';
                }
                module.exports = isObjectLike;
            }, {}], 134: [function (require, module, exports) {
                var arrayCopy = require(94), composeArgs = require(112), composeArgsRight = require(113), replaceHolders = require(138);
                /** Used to compose bitmasks for wrapper metadata. */
                var BIND_FLAG = 1, CURRY_BOUND_FLAG = 4, CURRY_FLAG = 8, ARY_FLAG = 128, REARG_FLAG = 256;
                /** Used as the internal argument placeholder. */
                var PLACEHOLDER = '__lodash_placeholder__';
                /* Native method references for those with the same name as other `lodash` methods. */
                var nativeMin = Math.min;
                /**
                 * Merges the function metadata of `source` into `data`.
                 *
                 * Merging metadata reduces the number of wrappers required to invoke a function.
                 * This is possible because methods like `_.bind`, `_.curry`, and `_.partial`
                 * may be applied regardless of execution order. Methods like `_.ary` and `_.rearg`
                 * augment function arguments, making the order in which they are executed important,
                 * preventing the merging of metadata. However, we make an exception for a safe
                 * common case where curried functions have `_.ary` and or `_.rearg` applied.
                 *
                 * @private
                 * @param {Array} data The destination metadata.
                 * @param {Array} source The source metadata.
                 * @returns {Array} Returns `data`.
                 */
                function mergeData(data, source) {
                    var bitmask = data[1], srcBitmask = source[1], newBitmask = bitmask | srcBitmask, isCommon = newBitmask < ARY_FLAG;
                    var isCombo = (srcBitmask == ARY_FLAG && bitmask == CURRY_FLAG) ||
                        (srcBitmask == ARY_FLAG && bitmask == REARG_FLAG && data[7].length <= source[8]) ||
                        (srcBitmask == (ARY_FLAG | REARG_FLAG) && bitmask == CURRY_FLAG);
                    // Exit early if metadata can't be merged.
                    if (!(isCommon || isCombo)) {
                        return data;
                    }
                    // Use source `thisArg` if available.
                    if (srcBitmask & BIND_FLAG) {
                        data[2] = source[2];
                        // Set when currying a bound function.
                        newBitmask |= (bitmask & BIND_FLAG) ? 0 : CURRY_BOUND_FLAG;
                    }
                    // Compose partial arguments.
                    var value = source[3];
                    if (value) {
                        var partials = data[3];
                        data[3] = partials ? composeArgs(partials, value, source[4]) : arrayCopy(value);
                        data[4] = partials ? replaceHolders(data[3], PLACEHOLDER) : arrayCopy(source[4]);
                    }
                    // Compose partial right arguments.
                    value = source[5];
                    if (value) {
                        partials = data[5];
                        data[5] = partials ? composeArgsRight(partials, value, source[6]) : arrayCopy(value);
                        data[6] = partials ? replaceHolders(data[5], PLACEHOLDER) : arrayCopy(source[6]);
                    }
                    // Use source `argPos` if available.
                    value = source[7];
                    if (value) {
                        data[7] = arrayCopy(value);
                    }
                    // Use source `ary` if it's smaller.
                    if (srcBitmask & ARY_FLAG) {
                        data[8] = data[8] == null ? source[8] : nativeMin(data[8], source[8]);
                    }
                    // Use source `arity` if one is not provided.
                    if (data[9] == null) {
                        data[9] = source[9];
                    }
                    // Use source `func` and merge bitmasks.
                    data[0] = source[0];
                    data[1] = newBitmask;
                    return data;
                }
                module.exports = mergeData;
            }, { "112": 112, "113": 113, "138": 138, "94": 94 }], 135: [function (require, module, exports) {
                (function (global) {
                    var getNative = require(124);
                    /** Native method references. */
                    var WeakMap = getNative(global, 'WeakMap');
                    /** Used to store function metadata. */
                    var metaMap = WeakMap && new WeakMap;
                    module.exports = metaMap;
                }).call(this, typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {});
            }, { "124": 124 }], 136: [function (require, module, exports) {
                /** Used to lookup unminified function names. */
                var realNames = {};
                module.exports = realNames;
            }, {}], 137: [function (require, module, exports) {
                var arrayCopy = require(94), isIndex = require(129);
                /* Native method references for those with the same name as other `lodash` methods. */
                var nativeMin = Math.min;
                /**
                 * Reorder `array` according to the specified indexes where the element at
                 * the first index is assigned as the first element, the element at
                 * the second index is assigned as the second element, and so on.
                 *
                 * @private
                 * @param {Array} array The array to reorder.
                 * @param {Array} indexes The arranged array indexes.
                 * @returns {Array} Returns `array`.
                 */
                function reorder(array, indexes) {
                    var arrLength = array.length, length = nativeMin(indexes.length, arrLength), oldArray = arrayCopy(array);
                    while (length--) {
                        var index = indexes[length];
                        array[length] = isIndex(index, arrLength) ? oldArray[index] : undefined;
                    }
                    return array;
                }
                module.exports = reorder;
            }, { "129": 129, "94": 94 }], 138: [function (require, module, exports) {
                /** Used as the internal argument placeholder. */
                var PLACEHOLDER = '__lodash_placeholder__';
                /**
                 * Replaces all `placeholder` elements in `array` with an internal placeholder
                 * and returns an array of their indexes.
                 *
                 * @private
                 * @param {Array} array The array to modify.
                 * @param {*} placeholder The placeholder to replace.
                 * @returns {Array} Returns the new array of placeholder indexes.
                 */
                function replaceHolders(array, placeholder) {
                    var index = -1, length = array.length, resIndex = -1, result = [];
                    while (++index < length) {
                        if (array[index] === placeholder) {
                            array[index] = PLACEHOLDER;
                            result[++resIndex] = index;
                        }
                    }
                    return result;
                }
                module.exports = replaceHolders;
            }, {}], 139: [function (require, module, exports) {
                var baseSetData = require(109), now = require(86);
                /** Used to detect when a function becomes hot. */
                var HOT_COUNT = 150, HOT_SPAN = 16;
                /**
                 * Sets metadata for `func`.
                 *
                 * **Note:** If this function becomes hot, i.e. is invoked a lot in a short
                 * period of time, it will trip its breaker and transition to an identity function
                 * to avoid garbage collection pauses in V8. See [V8 issue 2070](https://code.google.com/p/v8/issues/detail?id=2070)
                 * for more details.
                 *
                 * @private
                 * @param {Function} func The function to associate metadata with.
                 * @param {*} data The metadata.
                 * @returns {Function} Returns `func`.
                 */
                var setData = (function () {
                    var count = 0, lastCalled = 0;
                    return function (key, value) {
                        var stamp = now(), remaining = HOT_SPAN - (stamp - lastCalled);
                        lastCalled = stamp;
                        if (remaining > 0) {
                            if (++count >= HOT_COUNT) {
                                return key;
                            }
                        }
                        else {
                            count = 0;
                        }
                        return baseSetData(key, value);
                    };
                }());
                module.exports = setData;
            }, { "109": 109, "86": 86 }], 140: [function (require, module, exports) {
                var isArguments = require(144), isArray = require(145), isIndex = require(129), isLength = require(132), keysIn = require(154);
                /** Used for native method references. */
                var objectProto = Object.prototype;
                /** Used to check objects for own properties. */
                var hasOwnProperty = objectProto.hasOwnProperty;
                /**
                 * A fallback implementation of `Object.keys` which creates an array of the
                 * own enumerable property names of `object`.
                 *
                 * @private
                 * @param {Object} object The object to query.
                 * @returns {Array} Returns the array of property names.
                 */
                function shimKeys(object) {
                    var props = keysIn(object), propsLength = props.length, length = propsLength && object.length;
                    var allowIndexes = !!length && isLength(length) &&
                        (isArray(object) || isArguments(object));
                    var index = -1, result = [];
                    while (++index < propsLength) {
                        var key = props[index];
                        if ((allowIndexes && isIndex(key, length)) || hasOwnProperty.call(object, key)) {
                            result.push(key);
                        }
                    }
                    return result;
                }
                module.exports = shimKeys;
            }, { "129": 129, "132": 132, "144": 144, "145": 145, "154": 154 }], 141: [function (require, module, exports) {
                var isObject = require(148);
                /**
                 * Converts `value` to an object if it's not one.
                 *
                 * @private
                 * @param {*} value The value to process.
                 * @returns {Object} Returns the object.
                 */
                function toObject(value) {
                    return isObject(value) ? value : Object(value);
                }
                module.exports = toObject;
            }, { "148": 148 }], 142: [function (require, module, exports) {
                var LazyWrapper = require(92), LodashWrapper = require(93), arrayCopy = require(94);
                /**
                 * Creates a clone of `wrapper`.
                 *
                 * @private
                 * @param {Object} wrapper The wrapper to clone.
                 * @returns {Object} Returns the cloned wrapper.
                 */
                function wrapperClone(wrapper) {
                    return wrapper instanceof LazyWrapper
                        ? wrapper.clone()
                        : new LodashWrapper(wrapper.__wrapped__, wrapper.__chain__, arrayCopy(wrapper.__actions__));
                }
                module.exports = wrapperClone;
            }, { "92": 92, "93": 93, "94": 94 }], 143: [function (require, module, exports) {
                var baseClone = require(99), bindCallback = require(110);
                /**
                 * Creates a deep clone of `value`. If `customizer` is provided it's invoked
                 * to produce the cloned values. If `customizer` returns `undefined` cloning
                 * is handled by the method instead. The `customizer` is bound to `thisArg`
                 * and invoked with up to three argument; (value [, index|key, object]).
                 *
                 * **Note:** This method is loosely based on the
                 * [structured clone algorithm](http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm).
                 * The enumerable properties of `arguments` objects and objects created by
                 * constructors other than `Object` are cloned to plain `Object` objects. An
                 * empty object is returned for uncloneable values such as functions, DOM nodes,
                 * Maps, Sets, and WeakMaps.
                 *
                 * @static
                 * @memberOf _
                 * @category Lang
                 * @param {*} value The value to deep clone.
                 * @param {Function} [customizer] The function to customize cloning values.
                 * @param {*} [thisArg] The `this` binding of `customizer`.
                 * @returns {*} Returns the deep cloned value.
                 * @example
                 *
                 * var users = [
                 *   { 'user': 'barney' },
                 *   { 'user': 'fred' }
                 * ];
                 *
                 * var deep = _.cloneDeep(users);
                 * deep[0] === users[0];
                 * // => false
                 *
                 * // using a customizer callback
                 * var el = _.cloneDeep(document.body, function(value) {
                 *   if (_.isElement(value)) {
                 *     return value.cloneNode(true);
                 *   }
                 * });
                 *
                 * el === document.body
                 * // => false
                 * el.nodeName
                 * // => BODY
                 * el.childNodes.length;
                 * // => 20
                 */
                function cloneDeep(value, customizer, thisArg) {
                    return typeof customizer == 'function'
                        ? baseClone(value, true, bindCallback(customizer, thisArg, 3))
                        : baseClone(value, true);
                }
                module.exports = cloneDeep;
            }, { "110": 110, "99": 99 }], 144: [function (require, module, exports) {
                var isArrayLike = require(128), isObjectLike = require(133);
                /** Used for native method references. */
                var objectProto = Object.prototype;
                /** Used to check objects for own properties. */
                var hasOwnProperty = objectProto.hasOwnProperty;
                /** Native method references. */
                var propertyIsEnumerable = objectProto.propertyIsEnumerable;
                /**
                 * Checks if `value` is classified as an `arguments` object.
                 *
                 * @static
                 * @memberOf _
                 * @category Lang
                 * @param {*} value The value to check.
                 * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
                 * @example
                 *
                 * _.isArguments(function() { return arguments; }());
                 * // => true
                 *
                 * _.isArguments([1, 2, 3]);
                 * // => false
                 */
                function isArguments(value) {
                    return isObjectLike(value) && isArrayLike(value) &&
                        hasOwnProperty.call(value, 'callee') && !propertyIsEnumerable.call(value, 'callee');
                }
                module.exports = isArguments;
            }, { "128": 128, "133": 133 }], 145: [function (require, module, exports) {
                var getNative = require(124), isLength = require(132), isObjectLike = require(133);
                /** `Object#toString` result references. */
                var arrayTag = '[object Array]';
                /** Used for native method references. */
                var objectProto = Object.prototype;
                /**
                 * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring)
                 * of values.
                 */
                var objToString = objectProto.toString;
                /* Native method references for those with the same name as other `lodash` methods. */
                var nativeIsArray = getNative(Array, 'isArray');
                /**
                 * Checks if `value` is classified as an `Array` object.
                 *
                 * @static
                 * @memberOf _
                 * @category Lang
                 * @param {*} value The value to check.
                 * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
                 * @example
                 *
                 * _.isArray([1, 2, 3]);
                 * // => true
                 *
                 * _.isArray(function() { return arguments; }());
                 * // => false
                 */
                var isArray = nativeIsArray || function (value) {
                    return isObjectLike(value) && isLength(value.length) && objToString.call(value) == arrayTag;
                };
                module.exports = isArray;
            }, { "124": 124, "132": 132, "133": 133 }], 146: [function (require, module, exports) {
                var isObject = require(148);
                /** `Object#toString` result references. */
                var funcTag = '[object Function]';
                /** Used for native method references. */
                var objectProto = Object.prototype;
                /**
                 * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring)
                 * of values.
                 */
                var objToString = objectProto.toString;
                /**
                 * Checks if `value` is classified as a `Function` object.
                 *
                 * @static
                 * @memberOf _
                 * @category Lang
                 * @param {*} value The value to check.
                 * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
                 * @example
                 *
                 * _.isFunction(_);
                 * // => true
                 *
                 * _.isFunction(/abc/);
                 * // => false
                 */
                function isFunction(value) {
                    // The use of `Object#toString` avoids issues with the `typeof` operator
                    // in older versions of Chrome and Safari which return 'function' for regexes
                    // and Safari 8 which returns 'object' for typed array constructors.
                    return isObject(value) && objToString.call(value) == funcTag;
                }
                module.exports = isFunction;
            }, { "148": 148 }], 147: [function (require, module, exports) {
                var isFunction = require(146), isObjectLike = require(133);
                /** Used to detect host constructors (Safari > 5). */
                var reIsHostCtor = /^\[object .+?Constructor\]$/;
                /** Used for native method references. */
                var objectProto = Object.prototype;
                /** Used to resolve the decompiled source of functions. */
                var fnToString = Function.prototype.toString;
                /** Used to check objects for own properties. */
                var hasOwnProperty = objectProto.hasOwnProperty;
                /** Used to detect if a method is native. */
                var reIsNative = RegExp('^' +
                    fnToString.call(hasOwnProperty).replace(/[\\^$.*+?()[\]{}|]/g, '\\$&')
                        .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$');
                /**
                 * Checks if `value` is a native function.
                 *
                 * @static
                 * @memberOf _
                 * @category Lang
                 * @param {*} value The value to check.
                 * @returns {boolean} Returns `true` if `value` is a native function, else `false`.
                 * @example
                 *
                 * _.isNative(Array.prototype.push);
                 * // => true
                 *
                 * _.isNative(_);
                 * // => false
                 */
                function isNative(value) {
                    if (value == null) {
                        return false;
                    }
                    if (isFunction(value)) {
                        return reIsNative.test(fnToString.call(value));
                    }
                    return isObjectLike(value) && reIsHostCtor.test(value);
                }
                module.exports = isNative;
            }, { "133": 133, "146": 146 }], 148: [function (require, module, exports) {
                /**
                 * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`.
                 * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
                 *
                 * @static
                 * @memberOf _
                 * @category Lang
                 * @param {*} value The value to check.
                 * @returns {boolean} Returns `true` if `value` is an object, else `false`.
                 * @example
                 *
                 * _.isObject({});
                 * // => true
                 *
                 * _.isObject([1, 2, 3]);
                 * // => true
                 *
                 * _.isObject(1);
                 * // => false
                 */
                function isObject(value) {
                    // Avoid a V8 JIT bug in Chrome 19-20.
                    // See https://code.google.com/p/v8/issues/detail?id=2291 for more details.
                    var type = typeof value;
                    return !!value && (type == 'object' || type == 'function');
                }
                module.exports = isObject;
            }, {}], 149: [function (require, module, exports) {
                var isObjectLike = require(133);
                /** `Object#toString` result references. */
                var stringTag = '[object String]';
                /** Used for native method references. */
                var objectProto = Object.prototype;
                /**
                 * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring)
                 * of values.
                 */
                var objToString = objectProto.toString;
                /**
                 * Checks if `value` is classified as a `String` primitive or object.
                 *
                 * @static
                 * @memberOf _
                 * @category Lang
                 * @param {*} value The value to check.
                 * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
                 * @example
                 *
                 * _.isString('abc');
                 * // => true
                 *
                 * _.isString(1);
                 * // => false
                 */
                function isString(value) {
                    return typeof value == 'string' || (isObjectLike(value) && objToString.call(value) == stringTag);
                }
                module.exports = isString;
            }, { "133": 133 }], 150: [function (require, module, exports) {
                var assignWith = require(97), baseAssign = require(98), createAssigner = require(114);
                /**
                 * Assigns own enumerable properties of source object(s) to the destination
                 * object. Subsequent sources overwrite property assignments of previous sources.
                 * If `customizer` is provided it's invoked to produce the assigned values.
                 * The `customizer` is bound to `thisArg` and invoked with five arguments:
                 * (objectValue, sourceValue, key, object, source).
                 *
                 * **Note:** This method mutates `object` and is based on
                 * [`Object.assign`](http://ecma-international.org/ecma-262/6.0/#sec-object.assign).
                 *
                 * @static
                 * @memberOf _
                 * @alias extend
                 * @category Object
                 * @param {Object} object The destination object.
                 * @param {...Object} [sources] The source objects.
                 * @param {Function} [customizer] The function to customize assigned values.
                 * @param {*} [thisArg] The `this` binding of `customizer`.
                 * @returns {Object} Returns `object`.
                 * @example
                 *
                 * _.assign({ 'user': 'barney' }, { 'age': 40 }, { 'user': 'fred' });
                 * // => { 'user': 'fred', 'age': 40 }
                 *
                 * // using a customizer callback
                 * var defaults = _.partialRight(_.assign, function(value, other) {
                 *   return _.isUndefined(value) ? other : value;
                 * });
                 *
                 * defaults({ 'user': 'barney' }, { 'age': 36 }, { 'user': 'fred' });
                 * // => { 'user': 'barney', 'age': 36 }
                 */
                var assign = createAssigner(function (object, source, customizer) {
                    return customizer
                        ? assignWith(object, source, customizer)
                        : baseAssign(object, source);
                });
                module.exports = assign;
            }, { "114": 114, "97": 97, "98": 98 }], 151: [function (require, module, exports) {
                var baseAssign = require(98), baseCreate = require(101), isIterateeCall = require(130);
                /**
                 * Creates an object that inherits from the given `prototype` object. If a
                 * `properties` object is provided its own enumerable properties are assigned
                 * to the created object.
                 *
                 * @static
                 * @memberOf _
                 * @category Object
                 * @param {Object} prototype The object to inherit from.
                 * @param {Object} [properties] The properties to assign to the object.
                 * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
                 * @returns {Object} Returns the new object.
                 * @example
                 *
                 * function Shape() {
                 *   this.x = 0;
                 *   this.y = 0;
                 * }
                 *
                 * function Circle() {
                 *   Shape.call(this);
                 * }
                 *
                 * Circle.prototype = _.create(Shape.prototype, {
                 *   'constructor': Circle
                 * });
                 *
                 * var circle = new Circle;
                 * circle instanceof Circle;
                 * // => true
                 *
                 * circle instanceof Shape;
                 * // => true
                 */
                function create(prototype, properties, guard) {
                    var result = baseCreate(prototype);
                    if (guard && isIterateeCall(prototype, properties, guard)) {
                        properties = undefined;
                    }
                    return properties ? baseAssign(result, properties) : result;
                }
                module.exports = create;
            }, { "101": 101, "130": 130, "98": 98 }], 152: [function (require, module, exports) {
                var baseFunctions = require(106), keysIn = require(154);
                /**
                 * Creates an array of function property names from all enumerable properties,
                 * own and inherited, of `object`.
                 *
                 * @static
                 * @memberOf _
                 * @alias methods
                 * @category Object
                 * @param {Object} object The object to inspect.
                 * @returns {Array} Returns the new array of property names.
                 * @example
                 *
                 * _.functions(_);
                 * // => ['after', 'ary', 'assign', ...]
                 */
                function functions(object) {
                    return baseFunctions(object, keysIn(object));
                }
                module.exports = functions;
            }, { "106": 106, "154": 154 }], 153: [function (require, module, exports) {
                var getNative = require(124), isArrayLike = require(128), isObject = require(148), shimKeys = require(140);
                /* Native method references for those with the same name as other `lodash` methods. */
                var nativeKeys = getNative(Object, 'keys');
                /**
                 * Creates an array of the own enumerable property names of `object`.
                 *
                 * **Note:** Non-object values are coerced to objects. See the
                 * [ES spec](http://ecma-international.org/ecma-262/6.0/#sec-object.keys)
                 * for more details.
                 *
                 * @static
                 * @memberOf _
                 * @category Object
                 * @param {Object} object The object to query.
                 * @returns {Array} Returns the array of property names.
                 * @example
                 *
                 * function Foo() {
                 *   this.a = 1;
                 *   this.b = 2;
                 * }
                 *
                 * Foo.prototype.c = 3;
                 *
                 * _.keys(new Foo);
                 * // => ['a', 'b'] (iteration order is not guaranteed)
                 *
                 * _.keys('hi');
                 * // => ['0', '1']
                 */
                var keys = !nativeKeys ? shimKeys : function (object) {
                    var Ctor = object == null ? undefined : object.constructor;
                    if ((typeof Ctor == 'function' && Ctor.prototype === object) ||
                        (typeof object != 'function' && isArrayLike(object))) {
                        return shimKeys(object);
                    }
                    return isObject(object) ? nativeKeys(object) : [];
                };
                module.exports = keys;
            }, { "124": 124, "128": 128, "140": 140, "148": 148 }], 154: [function (require, module, exports) {
                var isArguments = require(144), isArray = require(145), isIndex = require(129), isLength = require(132), isObject = require(148);
                /** Used for native method references. */
                var objectProto = Object.prototype;
                /** Used to check objects for own properties. */
                var hasOwnProperty = objectProto.hasOwnProperty;
                /**
                 * Creates an array of the own and inherited enumerable property names of `object`.
                 *
                 * **Note:** Non-object values are coerced to objects.
                 *
                 * @static
                 * @memberOf _
                 * @category Object
                 * @param {Object} object The object to query.
                 * @returns {Array} Returns the array of property names.
                 * @example
                 *
                 * function Foo() {
                 *   this.a = 1;
                 *   this.b = 2;
                 * }
                 *
                 * Foo.prototype.c = 3;
                 *
                 * _.keysIn(new Foo);
                 * // => ['a', 'b', 'c'] (iteration order is not guaranteed)
                 */
                function keysIn(object) {
                    if (object == null) {
                        return [];
                    }
                    if (!isObject(object)) {
                        object = Object(object);
                    }
                    var length = object.length;
                    length = (length && isLength(length) &&
                        (isArray(object) || isArguments(object)) && length) || 0;
                    var Ctor = object.constructor, index = -1, isProto = typeof Ctor == 'function' && Ctor.prototype === object, result = Array(length), skipIndexes = length > 0;
                    while (++index < length) {
                        result[index] = (index + '');
                    }
                    for (var key in object) {
                        if (!(skipIndexes && isIndex(key, length)) &&
                            !(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) {
                            result.push(key);
                        }
                    }
                    return result;
                }
                module.exports = keysIn;
            }, { "129": 129, "132": 132, "144": 144, "145": 145, "148": 148 }], 155: [function (require, module, exports) {
                /**
                 * This method returns the first argument provided to it.
                 *
                 * @static
                 * @memberOf _
                 * @category Utility
                 * @param {*} value Any value.
                 * @returns {*} Returns `value`.
                 * @example
                 *
                 * var object = { 'user': 'fred' };
                 *
                 * _.identity(object) === object;
                 * // => true
                 */
                function identity(value) {
                    return value;
                }
                module.exports = identity;
            }, {}], 156: [function (require, module, exports) {
                /**
                 * A no-operation function that returns `undefined` regardless of the
                 * arguments it receives.
                 *
                 * @static
                 * @memberOf _
                 * @category Utility
                 * @example
                 *
                 * var object = { 'user': 'fred' };
                 *
                 * _.noop(object) === undefined;
                 * // => true
                 */
                function noop() {
                    // No operation performed.
                }
                module.exports = noop;
            }, {}], 157: [function (require, module, exports) {
                function nodeListToArray(nodeList) {
                    try {
                        return Array.prototype.slice.call(nodeList);
                    }
                    catch (err) {
                        var result = [];
                        for (var i = 0; i < nodeList.length; i++) {
                            result.push(nodeList[i]);
                        }
                        return result;
                    }
                }
                if (typeof module !== 'undefined') {
                    module.exports = nodeListToArray;
                }
            }, {}], 158: [function (require, module, exports) {
                'use strict';
                var bus = require(81);
                var events = require(160);
                var checkOrigin = require(159).checkOrigin;
                function BraintreeBus(options) {
                    options = options || {};
                    this.channel = options.channel;
                    if (!this.channel) {
                        throw new Error('Channel ID must be specified');
                    }
                    this.merchantUrl = options.merchantUrl;
                    this._isDestroyed = false;
                    this._isVerbose = false;
                    this._listeners = [];
                    this._log('new bus on channel ' + this.channel, [location.href]);
                }
                BraintreeBus.prototype.on = function (eventName, originalHandler) {
                    var namespacedEvent, args;
                    var handler = originalHandler;
                    var self = this;
                    if (this._isDestroyed) {
                        return;
                    }
                    if (this.merchantUrl) {
                        handler = function () {
                            /* eslint-disable no-invalid-this */
                            if (checkOrigin(this.origin, self.merchantUrl)) {
                                originalHandler.apply(this, arguments);
                            }
                            /* eslint-enable no-invalid-this */
                        };
                    }
                    namespacedEvent = this._namespaceEvent(eventName);
                    args = Array.prototype.slice.call(arguments);
                    args[0] = namespacedEvent;
                    args[1] = handler;
                    this._log('on', args);
                    bus.on.apply(bus, args);
                    this._listeners.push({
                        eventName: eventName,
                        handler: handler,
                        originalHandler: originalHandler
                    });
                };
                BraintreeBus.prototype.emit = function (eventName) {
                    var args;
                    if (this._isDestroyed) {
                        return;
                    }
                    args = Array.prototype.slice.call(arguments);
                    args[0] = this._namespaceEvent(eventName);
                    this._log('emit', args);
                    bus.emit.apply(bus, args);
                };
                BraintreeBus.prototype._offDirect = function (eventName) {
                    var args = Array.prototype.slice.call(arguments);
                    if (this._isDestroyed) {
                        return;
                    }
                    args[0] = this._namespaceEvent(eventName);
                    this._log('off', args);
                    bus.off.apply(bus, args);
                };
                BraintreeBus.prototype.off = function (eventName, originalHandler) {
                    var i, listener;
                    var handler = originalHandler;
                    if (this._isDestroyed) {
                        return;
                    }
                    if (this.merchantUrl) {
                        for (i = 0; i < this._listeners.length; i++) {
                            listener = this._listeners[i];
                            if (listener.originalHandler === originalHandler) {
                                handler = listener.handler;
                            }
                        }
                    }
                    this._offDirect(eventName, handler);
                };
                BraintreeBus.prototype._namespaceEvent = function (eventName) {
                    return ['braintree', this.channel, eventName].join(':');
                };
                BraintreeBus.prototype.teardown = function () {
                    var listener, i;
                    for (i = 0; i < this._listeners.length; i++) {
                        listener = this._listeners[i];
                        this._offDirect(listener.eventName, listener.handler);
                    }
                    this._listeners.length = 0;
                    this._isDestroyed = true;
                };
                BraintreeBus.prototype._log = function (functionName, args) {
                    if (this._isVerbose) {
                        console.log(functionName, args); // eslint-disable-line no-console
                    }
                };
                BraintreeBus.events = events;
                module.exports = BraintreeBus;
            }, { "159": 159, "160": 160, "81": 81 }], 159: [function (require, module, exports) {
                'use strict';
                var BT_ORIGIN_REGEX = /^https:\/\/([a-zA-Z0-9-]+\.)*(braintreepayments|braintreegateway|paypal)\.com(:\d{1,5})?$/;
                function checkOrigin(postMessageOrigin, merchantUrl) {
                    var merchantOrigin, merchantHost;
                    var a = document.createElement('a');
                    a.href = merchantUrl;
                    if (a.protocol === 'https:') {
                        merchantHost = a.host.replace(/:443$/, '');
                    }
                    else if (a.protocol === 'http:') {
                        merchantHost = a.host.replace(/:80$/, '');
                    }
                    else {
                        merchantHost = a.host;
                    }
                    merchantOrigin = a.protocol + '//' + merchantHost;
                    return merchantOrigin === postMessageOrigin || BT_ORIGIN_REGEX.test(postMessageOrigin);
                }
                module.exports = {
                    checkOrigin: checkOrigin
                };
            }, {}], 160: [function (require, module, exports) {
                'use strict';
                var i, evnt;
                var eventList = [
                    'PAYMENT_METHOD_REQUEST',
                    'PAYMENT_METHOD_RECEIVED',
                    'PAYMENT_METHOD_GENERATED',
                    'PAYMENT_METHOD_NOT_GENERATED',
                    'PAYMENT_METHOD_CANCELLED',
                    'PAYMENT_METHOD_ERROR',
                    'CONFIGURATION_REQUEST',
                    'ROOT_METADATA_REQUEST',
                    'ERROR',
                    'WARNING',
                    'UI_POPUP_DID_OPEN',
                    'UI_POPUP_DID_CLOSE',
                    'UI_POPUP_FORCE_CLOSE',
                    'UI_MODAL_DID_OPEN',
                    'UI_MODAL_DID_CLOSE',
                    'ASYNC_DEPENDENCY_INITIALIZING',
                    'ASYNC_DEPENDENCY_READY',
                    'USER_FORM_SUBMIT_REQUEST',
                    'SEND_ANALYTICS_EVENTS'
                ];
                var eventEnum = {};
                for (i = 0; i < eventList.length; i++) {
                    evnt = eventList[i];
                    eventEnum[evnt] = evnt;
                }
                module.exports = eventEnum;
            }, {}], 161: [function (require, module, exports) {
                'use strict';
                /* eslint-disable consistent-return */
                function convertToLegacyShippingAddress(address) {
                    var prop;
                    var legacyShippingAddress = {};
                    if (!address) {
                        return;
                    }
                    for (prop in address) {
                        if (address.hasOwnProperty(prop)) {
                            legacyShippingAddress[toSnakeCase(prop)] = address[prop];
                        }
                    }
                    return legacyShippingAddress;
                }
                function toSnakeCase(string) {
                    return string.replace(/([A-Z])/g, function ($1) {
                        return '_' + $1.toLowerCase();
                    });
                }
                module.exports = { convertToLegacyShippingAddress: convertToLegacyShippingAddress };
            }, {}], 162: [function (require, module, exports) {
                'use strict';
                module.exports = {
                    ROOT_SUCCESS_CALLBACK: 'onPaymentMethodReceived',
                    ROOT_ERROR_CALLBACK: 'onError',
                    ROOT_READY_CALLBACK: 'onReady',
                    TEARDOWN_STATE: {
                        IN_PROGRESS: 'inProgress',
                        COMPLETE: 'complete'
                    }
                };
            }, {}], 163: [function (require, module, exports) {
                (function (global) {
                    'use strict';
                    var cloneAndStripDOM = require(169).cloneAndStripDOM;
                    var api = require(14);
                    var Bus = require(158);
                    var Destructor = require(77);
                    var bind = require(87);
                    var constants = require(162);
                    var sanitizePayload = require(174);
                    var lookupCallbackFor = require(172);
                    var fallbackErrorHandler = require(170);
                    var dataCollector = require(188);
                    function noop() { }
                    function _ensureDropinPayPalConfig(merchantConfiguration) {
                        merchantConfiguration.paypal = merchantConfiguration.paypal || {};
                    }
                    function _handleDependencyInitializing() {
                        this._dependenciesRemaining++;
                    }
                    function _handleDependencyReady() {
                        this._dependenciesRemaining--;
                        if (this._dependenciesRemaining === 0) {
                            delete this._dependenciesRemaining;
                            this.bus.off(Bus.events.ASYNC_DEPENDENCY_INITIALIZING, this._handleDependencyInitializing);
                            this.bus.off(Bus.events.ASYNC_DEPENDENCY_READY, this._handleDependencyReady);
                            this._onIntegrationReady();
                        }
                    }
                    function BaseIntegration(configuration) {
                        this.configuration = configuration;
                        this.isReady = false;
                        this.destructor = new Destructor();
                        this.bus = new Bus({
                            channel: this.configuration.channel,
                            merchantUrl: global.location.href
                        });
                        this.apiClient = new api.Client(this.configuration);
                        this._configureCallbacks();
                        this._configureAnalytics();
                        this._attachEvents();
                        this._emitInitializing();
                    }
                    BaseIntegration.prototype._emitInitializing = function () {
                        this.bus.emit(Bus.events.ASYNC_DEPENDENCY_INITIALIZING);
                    };
                    BaseIntegration.prototype._configureCallbacks = function () {
                        var getCallback = lookupCallbackFor(this.configuration.merchantConfiguration);
                        function successHandler(fn) {
                            return function (payload) {
                                fn(sanitizePayload(payload));
                            };
                        }
                        this.onSuccess = successHandler(getCallback(constants.ROOT_SUCCESS_CALLBACK));
                        this.onError = getCallback(constants.ROOT_ERROR_CALLBACK, fallbackErrorHandler);
                        this.onReady = getCallback(constants.ROOT_READY_CALLBACK);
                    };
                    BaseIntegration.prototype._configureAnalytics = function () {
                        var prefix = 'web.' + this.configuration.integrationType + '.';
                        var apiClient = this.apiClient;
                        this.bus.on(Bus.events.SEND_ANALYTICS_EVENTS, function (events, callback) {
                            var i;
                            if (!(events instanceof Array)) {
                                events = [events];
                            }
                            for (i = 0; i < events.length; i++) {
                                events[i] = prefix + events[i];
                            }
                            apiClient.sendAnalyticsEvents(events, callback);
                        });
                    };
                    BaseIntegration.prototype._attachEvents = function () {
                        var replyConfiguration = cloneAndStripDOM(this.configuration);
                        if (replyConfiguration.integrationType === 'dropin') {
                            _ensureDropinPayPalConfig(replyConfiguration.merchantConfiguration);
                        }
                        this.bus.on(Bus.events.ERROR, this.onError);
                        this.bus.on(Bus.events.PAYMENT_METHOD_RECEIVED, this.onSuccess);
                        this.bus.on(Bus.events.WARNING, function (warning) {
                            try {
                                console.warn(warning);
                            }
                            catch (e) { } // eslint-disable-line no-console
                        });
                        this.bus.on(Bus.events.CONFIGURATION_REQUEST, function (reply) {
                            reply(replyConfiguration);
                        });
                        this._dependenciesRemaining = 0;
                        this._handleDependencyInitializing = bind(_handleDependencyInitializing, this);
                        this._handleDependencyReady = bind(_handleDependencyReady, this);
                        this.bus.on(Bus.events.ASYNC_DEPENDENCY_INITIALIZING, this._handleDependencyInitializing);
                        this.bus.on(Bus.events.ASYNC_DEPENDENCY_READY, this._handleDependencyReady);
                    };
                    BaseIntegration.prototype._addDeviceData = function (instance) {
                        var dataCollectorInstance;
                        var merchantConfiguration = this.configuration.merchantConfiguration;
                        var gatewayConfiguration = this.configuration.gatewayConfiguration;
                        var dataCollectorOptions = {};
                        if (merchantConfiguration.dataCollector == null) {
                            return;
                        }
                        if (gatewayConfiguration.kount && merchantConfiguration.dataCollector.kount) {
                            dataCollectorOptions.kount = {
                                merchantId: merchantConfiguration.dataCollector.kount.merchantId || gatewayConfiguration.kount.kountMerchantId,
                                environment: merchantConfiguration.dataCollector.kount.environment || gatewayConfiguration.environment
                            };
                        }
                        dataCollectorOptions.paypal = merchantConfiguration.dataCollector.paypal === true;
                        if (!dataCollectorOptions.kount && !dataCollectorOptions.paypal) {
                            return;
                        }
                        try {
                            dataCollectorInstance = dataCollector.setup(dataCollectorOptions);
                        }
                        catch (e) {
                            this.bus.emit(Bus.events.ERROR, {
                                type: 'CONFIGURATION',
                                message: e.message
                            });
                        }
                        if (dataCollectorInstance == null) {
                            return;
                        }
                        this.destructor.registerFunctionForTeardown(function () {
                            dataCollectorInstance.teardown();
                        });
                        instance.deviceData = dataCollectorInstance.deviceData;
                    };
                    BaseIntegration.prototype.teardown = function (merchantCallback) {
                        if (this.teardownState === constants.TEARDOWN_STATE.IN_PROGRESS) {
                            throw new Error('Cannot call teardown while in progress');
                        }
                        if (this.teardownState === constants.TEARDOWN_STATE.COMPLETE) {
                            throw new Error('Cannot teardown integration more than once');
                        }
                        this.teardownMerchantCallback = merchantCallback || noop;
                        this.teardownState = constants.TEARDOWN_STATE.IN_PROGRESS;
                        this.destructor.teardown(bind(this._handleTeardown, this));
                    };
                    BaseIntegration.prototype._handleTeardown = function () {
                        this.bus.teardown();
                        this.teardownState = constants.TEARDOWN_STATE.COMPLETE;
                        this.teardownMerchantCallback();
                    };
                    BaseIntegration.prototype._wrapWithTeardownReply = function (funcName, func) {
                        var self = this;
                        return function () {
                            if (self.teardownState === constants.TEARDOWN_STATE.IN_PROGRESS) {
                                throw new Error('Cannot call ' + funcName + ' while teardown is in progress');
                            }
                            if (self.teardownState === constants.TEARDOWN_STATE.COMPLETE) {
                                throw new Error('Cannot call ' + funcName + ' after teardown has completed');
                            }
                            func();
                        };
                    };
                    BaseIntegration.prototype._onIntegrationReady = function (instance) {
                        this.returnedInstance = instance || {};
                        this.returnedInstance.teardown = bind(this.teardown, this);
                        this._addDeviceData(this.returnedInstance);
                        this.isReady = true;
                        this.onReady(this.returnedInstance);
                    };
                    module.exports = BaseIntegration;
                }).call(this, typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {});
            }, { "14": 14, "158": 158, "162": 162, "169": 169, "170": 170, "172": 172, "174": 174, "188": 188, "77": 77, "87": 87 }], 164: [function (require, module, exports) {
                'use strict';
                var cloneAndPreserveDOM = require(169).cloneAndPreserveDOM;
                var create = require(151);
                var bind = require(87);
                var coinbase = require(176);
                var Bus = require(158);
                var BaseIntegration = require(163);
                function CoinbaseIntegration() {
                    var coinbaseIntegration, configuration;
                    BaseIntegration.apply(this, arguments);
                    configuration = cloneAndPreserveDOM(this.configuration);
                    configuration.apiClient = this.apiClient;
                    this._attachBusEvents();
                    coinbaseIntegration = coinbase.create(configuration);
                    if (coinbaseIntegration != null) {
                        this.destructor.registerFunctionForTeardown(function (done) {
                            coinbaseIntegration.teardown(done);
                        });
                    }
                    this.bus.emit(Bus.events.ASYNC_DEPENDENCY_READY);
                }
                CoinbaseIntegration.prototype = create(BaseIntegration.prototype, {
                    constructor: CoinbaseIntegration
                });
                CoinbaseIntegration.prototype._attachBusEvents = function () {
                    this.bus.on(Bus.events.PAYMENT_METHOD_GENERATED, bind(this._onPaymentMethodGenerated, this));
                };
                CoinbaseIntegration.prototype._onPaymentMethodGenerated = function (payload) {
                    this.bus.emit(Bus.events.PAYMENT_METHOD_RECEIVED, payload);
                };
                module.exports = CoinbaseIntegration;
            }, { "151": 151, "158": 158, "163": 163, "169": 169, "176": 176, "87": 87 }], 165: [function (require, module, exports) {
                'use strict';
                var cloneAndPreserveDOM = require(169).cloneAndPreserveDOM;
                var create = require(151);
                var debounce = require(89);
                var defer = require(90);
                var form = require(197);
                var paypal = require(209);
                var coinbase = require(176);
                var bind = require(87);
                var isFunction = require(146);
                var hostedFields = require(203);
                var FormNapper = require(80);
                var constants = require(162);
                var Bus = require(158);
                var convertToLegacyShippingAddress = require(161).convertToLegacyShippingAddress;
                var BaseIntegration = require(163);
                var NonceManager = require(171);
                function CustomIntegration() {
                    BaseIntegration.apply(this, arguments);
                    if (this.configuration.merchantConfiguration.hostedFields != null) {
                        this._setupHostedFields();
                    }
                    else {
                        this._setupForm();
                    }
                    this._setupPayPal();
                    this._setupCoinbase();
                    this.bus.emit(Bus.events.ASYNC_DEPENDENCY_READY);
                }
                CustomIntegration.prototype = create(BaseIntegration.prototype, {
                    constructor: CustomIntegration
                });
                CustomIntegration.prototype._setupHostedFields = function () {
                    var submitRequestHandler;
                    var merchantConfiguration = this.configuration.merchantConfiguration;
                    var rootSuccessCallback = merchantConfiguration[constants.ROOT_SUCCESS_CALLBACK];
                    var formNapper = new FormNapper(merchantConfiguration.id);
                    var hostedFieldsIntegration = hostedFields.create(this.configuration);
                    var nonceManager = new NonceManager({
                        formNapper: formNapper,
                        rootCallback: rootSuccessCallback,
                        channel: this.configuration.channel
                    });
                    if (formNapper.htmlForm == null) {
                        this.bus.emit(Bus.events.ERROR, {
                            type: 'CONFIGURATION',
                            message: 'options.id does not reference a valid DOM element'
                        });
                        return;
                    }
                    submitRequestHandler = bind(nonceManager.handleSubmitRequest, nonceManager);
                    formNapper.hijack(submitRequestHandler);
                    this.bus.on(Bus.events.USER_FORM_SUBMIT_REQUEST, submitRequestHandler);
                    this.destructor.registerFunctionForTeardown(bind(function (done) {
                        nonceManager.teardown();
                        formNapper.detach();
                        hostedFieldsIntegration.teardown(done);
                    }, this));
                };
                CustomIntegration.prototype._setupForm = function () {
                    var merchantConfiguration = this.configuration.merchantConfiguration;
                    var formShouldAutoSubmit, successCallback, formIntegration;
                    if (merchantConfiguration.id) {
                        formIntegration = form.setup(this.apiClient, this.configuration);
                        formShouldAutoSubmit = !isFunction(merchantConfiguration[constants.ROOT_SUCCESS_CALLBACK]);
                        if (!formShouldAutoSubmit) {
                            successCallback = this.onSuccess;
                            formIntegration.onNonceReceived = bind(function (err, payload) {
                                if (err) {
                                    this.bus.emit(Bus.events.ERROR, err); // eslint-disable-line no-invalid-this
                                }
                                else {
                                    successCallback(payload);
                                }
                            }, this);
                        }
                        this.destructor.registerFunctionForTeardown(function () {
                            formIntegration.teardown();
                        });
                    }
                    else {
                        this.bus.on(Bus.events.PAYMENT_METHOD_GENERATED, bind(function (payload) {
                            this.bus.emit(Bus.events.PAYMENT_METHOD_RECEIVED, payload); // eslint-disable-line no-invalid-this
                        }, this));
                    }
                };
                CustomIntegration.prototype._setupPayPal = function () {
                    var configuration, paypalCallbackLookup, legacyPaypalSuccessCallback, legacyPaypalCancelledCallback, dummyInput, paypalConfiguration, merchantConfiguration, authorizationDismissedHandler, nonce;
                    if (!this.configuration.merchantConfiguration.paypal) {
                        return;
                    }
                    configuration = cloneAndPreserveDOM(this.configuration);
                    merchantConfiguration = configuration.merchantConfiguration;
                    paypalConfiguration = merchantConfiguration.paypal;
                    paypalCallbackLookup = getIntegrationCallbackLookup(merchantConfiguration, 'paypal');
                    legacyPaypalSuccessCallback = paypalCallbackLookup('onSuccess');
                    legacyPaypalCancelledCallback = paypalCallbackLookup('onCancelled');
                    if (!paypalConfiguration.paymentMethodNonceInputField) {
                        dummyInput = document.createElement('input');
                        dummyInput.id = 'braintree-custom-integration-dummy-input';
                        paypalConfiguration.paymentMethodNonceInputField = dummyInput;
                    }
                    paypalConfiguration.onSuccess = function (payload) {
                        nonce = payload.nonce;
                        legacyPaypalSuccessCallback(payload.nonce, payload.details.email, convertToLegacyShippingAddress(payload.details.shippingAddress));
                    };
                    if (isFunction(paypalConfiguration.onAuthorizationDismissed)) {
                        authorizationDismissedHandler = debounce(function (event) {
                            defer(function () {
                                if (event && event.source === 'PayPal' && !nonce) {
                                    paypalConfiguration.onAuthorizationDismissed();
                                }
                            });
                        }, 200, { leading: true });
                        this.bus.on(Bus.events.UI_POPUP_DID_CLOSE, authorizationDismissedHandler);
                        this.bus.on(Bus.events.UI_MODAL_DID_CLOSE, authorizationDismissedHandler);
                    }
                    paypalConfiguration.onCancelled = function () {
                        nonce = null;
                        legacyPaypalCancelledCallback();
                    };
                    if (merchantConfiguration.enableCORS) {
                        paypalConfiguration.enableCORS = true;
                    }
                    this.paypalIntegration = paypal.create(configuration);
                    if (this.paypalIntegration != null) {
                        this.destructor.registerFunctionForTeardown(bind(function () {
                            this.paypalIntegration.teardown(); // eslint-disable-line no-invalid-this
                        }, this));
                    }
                };
                CustomIntegration.prototype._setupCoinbase = function () {
                    var coinbaseConfiguration, coinbaseIntegration;
                    if (!this.configuration.merchantConfiguration.coinbase) {
                        return;
                    }
                    if (navigator.userAgent.match(/MSIE 8\.0/)) {
                        return;
                    }
                    coinbaseConfiguration = cloneAndPreserveDOM(this.configuration);
                    coinbaseConfiguration.apiClient = this.apiClient;
                    coinbaseIntegration = coinbase.create(coinbaseConfiguration);
                    if (coinbaseIntegration != null) {
                        this.destructor.registerFunctionForTeardown(function (done) {
                            coinbaseIntegration.teardown(done);
                        });
                    }
                };
                CustomIntegration.prototype._onIntegrationReady = function () {
                    var self = this;
                    var returnedInstance = {};
                    if (this.paypalIntegration) {
                        returnedInstance.paypal = {
                            initAuthFlow: this._wrapWithTeardownReply('initAuthFlow', function () {
                                self.bus.emit(Bus.events.SEND_ANALYTICS_EVENTS, 'paypal.auth.init');
                                self.paypalIntegration.initAuthFlow();
                            }),
                            closeAuthFlow: this._wrapWithTeardownReply('closeAuthFlow', function () {
                                self.bus.emit(Bus.events.SEND_ANALYTICS_EVENTS, 'paypal.auth.close');
                                self.paypalIntegration.closeAuthFlow();
                            })
                        };
                    }
                    BaseIntegration.prototype._onIntegrationReady.call(this, returnedInstance);
                };
                function getIntegrationCallbackLookup(options, integration) {
                    return function (funcName) {
                        if (integration in options && isFunction(options[integration][funcName])) {
                            return options[integration][funcName];
                        }
                        return function noop() { };
                    };
                }
                module.exports = CustomIntegration;
            }, { "146": 146, "151": 151, "158": 158, "161": 161, "162": 162, "163": 163, "169": 169, "171": 171, "176": 176, "197": 197, "203": 203, "209": 209, "80": 80, "87": 87, "89": 89, "90": 90 }], 166: [function (require, module, exports) {
                'use strict';
                var cloneAndPreserveDOM = require(169).cloneAndPreserveDOM;
                var create = require(151);
                var dropin = require(195);
                var bind = require(87);
                var isFunction = require(146);
                var Bus = require(158);
                var constants = require(162);
                var sanitizePayload = require(174);
                var BaseIntegration = require(163);
                function _getLegacyCallback(options) {
                    if (isFunction(options.paymentMethodNonceReceived)) {
                        return options.paymentMethodNonceReceived;
                    }
                    return null;
                }
                function _hasRootCallback(options) {
                    return isFunction(options[constants.ROOT_SUCCESS_CALLBACK]);
                }
                function DropinIntegration() {
                    var merchantConfiguration, legacyCallback, hasRootCallback, dropinIntegration, configuration;
                    BaseIntegration.apply(this, arguments);
                    configuration = cloneAndPreserveDOM(this.configuration);
                    merchantConfiguration = configuration.merchantConfiguration;
                    legacyCallback = _getLegacyCallback(merchantConfiguration);
                    hasRootCallback = _hasRootCallback(merchantConfiguration);
                    if (legacyCallback || hasRootCallback) {
                        merchantConfiguration.paymentMethodNonceReceived = bind(function (payload) {
                            if (legacyCallback) {
                                legacyCallback(payload.originalEvent, payload.nonce);
                            }
                            this.bus.emit(Bus.events.PAYMENT_METHOD_RECEIVED, sanitizePayload(payload)); // eslint-disable-line no-invalid-this
                        }, this);
                    }
                    dropinIntegration = dropin.create(configuration);
                    this.destructor.registerFunctionForTeardown(function (done) {
                        dropinIntegration.teardown(done);
                    });
                    this.bus.emit(Bus.events.ASYNC_DEPENDENCY_READY);
                }
                DropinIntegration.prototype = create(BaseIntegration.prototype, {
                    constructor: DropinIntegration
                });
                module.exports = DropinIntegration;
            }, { "146": 146, "151": 151, "158": 158, "162": 162, "163": 163, "169": 169, "174": 174, "195": 195, "87": 87 }], 167: [function (require, module, exports) {
                'use strict';
                module.exports = {
                    custom: require(165),
                    dropin: require(166),
                    paypal: require(168),
                    coinbase: require(164)
                };
            }, { "164": 164, "165": 165, "166": 166, "168": 168 }], 168: [function (require, module, exports) {
                'use strict';
                var cloneAndPreserveDOM = require(169).cloneAndPreserveDOM;
                var create = require(151);
                var debounce = require(89);
                var defer = require(90);
                var paypal = require(209);
                var bind = require(87);
                var isFunction = require(146);
                var constants = require(162);
                var Bus = require(158);
                var convertToLegacyShippingAddress = require(161).convertToLegacyShippingAddress;
                var BaseIntegration = require(163);
                function _getLegacyCallback(options) {
                    if ('onSuccess' in options && isFunction(options.onSuccess)) {
                        return options.onSuccess;
                    }
                    else if ('paypal' in options && isFunction(options.paypal.onSuccess)) {
                        return options.paypal.onSuccess;
                    }
                    return null;
                }
                function _hasRootCallback(options) {
                    return isFunction(options[constants.ROOT_SUCCESS_CALLBACK]);
                }
                function PayPalIntegration(configuration) {
                    var merchantConfiguration, legacyCallback, hasRootCallback, key, onCancelled, authorizationDismissedHandler, nonce;
                    configuration = cloneAndPreserveDOM(configuration);
                    configuration.merchantConfiguration.paypal = configuration.merchantConfiguration.paypal || {};
                    for (key in configuration.merchantConfiguration) {
                        if (configuration.merchantConfiguration.hasOwnProperty(key) && key !== 'paypal') {
                            configuration.merchantConfiguration.paypal[key] = configuration.merchantConfiguration[key];
                        }
                    }
                    BaseIntegration.call(this, configuration);
                    merchantConfiguration = this.configuration.merchantConfiguration;
                    legacyCallback = _getLegacyCallback(merchantConfiguration);
                    hasRootCallback = _hasRootCallback(merchantConfiguration);
                    onCancelled = isFunction(merchantConfiguration.paypal.onCancelled) ? merchantConfiguration.paypal.onCancelled : function () { };
                    if (legacyCallback || hasRootCallback) {
                        merchantConfiguration.paypal.onSuccess = bind(function (payload) {
                            nonce = payload.nonce;
                            if (legacyCallback) {
                                legacyCallback(payload.nonce, payload.details.email, convertToLegacyShippingAddress(payload.details.shippingAddress));
                            }
                            this.bus.emit(Bus.events.PAYMENT_METHOD_RECEIVED, payload); // eslint-disable-line no-invalid-this
                        }, this);
                    }
                    if (isFunction(merchantConfiguration.paypal.onAuthorizationDismissed)) {
                        authorizationDismissedHandler = debounce(function (event) {
                            defer(function () {
                                if (event && event.source === 'PayPal' && !nonce) {
                                    merchantConfiguration.paypal.onAuthorizationDismissed();
                                }
                            });
                        }, 200, { leading: true });
                        this.bus.on(Bus.events.UI_POPUP_DID_CLOSE, authorizationDismissedHandler);
                        this.bus.on(Bus.events.UI_MODAL_DID_CLOSE, authorizationDismissedHandler);
                    }
                    merchantConfiguration.paypal.onCancelled = function () {
                        nonce = null;
                        if (onCancelled) {
                            onCancelled();
                        }
                    };
                    this.paypalIntegration = paypal.create(this.configuration);
                    this.destructor.registerFunctionForTeardown(bind(function () {
                        this.paypalIntegration.teardown(); // eslint-disable-line no-invalid-this
                    }, this));
                    this.bus.emit(Bus.events.ASYNC_DEPENDENCY_READY);
                }
                PayPalIntegration.prototype = create(BaseIntegration.prototype, {
                    constructor: PayPalIntegration
                });
                PayPalIntegration.prototype._onIntegrationReady = function () {
                    var self = this;
                    var returnedInstance = {};
                    if (this.paypalIntegration) {
                        returnedInstance.paypal = {
                            initAuthFlow: this._wrapWithTeardownReply('initAuthFlow', function () {
                                self.bus.emit(Bus.events.SEND_ANALYTICS_EVENTS, 'paypal.auth.init');
                                self.paypalIntegration.initAuthFlow();
                            }),
                            closeAuthFlow: this._wrapWithTeardownReply('closeAuthFlow', function () {
                                self.bus.emit(Bus.events.SEND_ANALYTICS_EVENTS, 'paypal.auth.close');
                                self.paypalIntegration.closeAuthFlow();
                            })
                        };
                    }
                    BaseIntegration.prototype._onIntegrationReady.call(this, returnedInstance);
                };
                module.exports = PayPalIntegration;
            }, { "146": 146, "151": 151, "158": 158, "161": 161, "162": 162, "163": 163, "169": 169, "209": 209, "87": 87, "89": 89, "90": 90 }], 169: [function (require, module, exports) {
                'use strict';
                var cloneDeep = require(143);
                var nodeType = require(173);
                var isJQueryElement = nodeType.isJQueryElement;
                var isHTMLElement = nodeType.isHTMLElement;
                function cloneAndPreserveDOM(obj) {
                    return cloneDeep(obj, function (value) {
                        if (isJQueryElement(value)) {
                            return value.get(0);
                        }
                        else if (isHTMLElement(value)) {
                            return value;
                        }
                    });
                }
                function cloneAndStripDOM(obj) {
                    return cloneDeep(obj, function (value) {
                        if (isJQueryElement(value) || isHTMLElement(value)) {
                            return {};
                        }
                    });
                }
                module.exports = {
                    cloneAndPreserveDOM: cloneAndPreserveDOM,
                    cloneAndStripDOM: cloneAndStripDOM
                };
            }, { "143": 143, "173": 173 }], 170: [function (require, module, exports) {
                'use strict';
                module.exports = function fallbackError(error) {
                    if (error.type === 'CONFIGURATION' || error.type === 'IMMEDIATE') {
                        throw new Error(error.message);
                    }
                    else {
                        try {
                            if (navigator.userAgent.indexOf('MSIE') === -1) {
                                console.error(error); // eslint-disable-line no-console
                            }
                            else {
                                console.error(JSON.stringify(error, null, 2)); // eslint-disable-line no-console
                            }
                        }
                        catch (e) { }
                    }
                };
            }, {}], 171: [function (require, module, exports) {
                'use strict';
                var Bus = require(158);
                var hostedFields = require(203);
                var ANALYTICS_STRING = 'web.custom.hosted-fields.via.';
                var INPUT_NAME = 'payment_method_nonce';
                function NonceManager(configuration) {
                    this.paymentMethod = null;
                    this.nonceInputElement = null;
                    this.bus = new Bus({ channel: configuration.channel });
                    this.formNapper = configuration.formNapper;
                    this.rootCallback = configuration.rootCallback;
                    this._attachEvents();
                }
                NonceManager.prototype._shouldStrictlyValidate = function (payload) {
                    if (payload != null) {
                        return false;
                    }
                    return this.paymentMethod == null || this.paymentMethod.type === 'CreditCard';
                };
                NonceManager.prototype._clearNonce = function () {
                    if (this.paymentMethod && this.paymentMethod.nonce) {
                        this.paymentMethod = null;
                        this.nonceInputElement = this.formNapper.inject(INPUT_NAME, '');
                    }
                };
                NonceManager.prototype._attachEvents = function () {
                    var self = this;
                    this.bus.on(Bus.events.PAYMENT_METHOD_CANCELLED, function () {
                        self._clearNonce();
                    });
                    this.bus.on(Bus.events.PAYMENT_METHOD_GENERATED, function (payload) {
                        self.paymentMethod = payload;
                        self.nonceInputElement = self.formNapper.inject(INPUT_NAME, self.paymentMethod.nonce);
                    });
                };
                NonceManager.prototype.handleSubmitRequest = function () {
                    var self = this;
                    this.bus.emit(hostedFields.events.TOKENIZATION_REQUEST, function (args) {
                        var err = args[0];
                        var payload = args[1];
                        if (err) {
                            self.bus.emit(Bus.events.ERROR, err);
                            return;
                        }
                        self.paymentMethod = payload || self.paymentMethod;
                        if (self._shouldStrictlyValidate(payload)) {
                            self.bus.emit(hostedFields.events.VALIDATE_STRICT);
                            self.bus.emit(Bus.events.ERROR, {
                                type: 'VALIDATION',
                                message: 'User did not enter a payment method'
                            });
                            return;
                        }
                        if (self.rootCallback) {
                            self.bus.emit(Bus.events.SEND_ANALYTICS_EVENTS, ANALYTICS_STRING + 'callback.success', function () {
                                self.rootCallback(self.paymentMethod);
                            });
                        }
                        else {
                            self.bus.emit(Bus.events.SEND_ANALYTICS_EVENTS, ANALYTICS_STRING + 'formsubmit.success', function () {
                                self.nonceInputElement = self.formNapper.inject(INPUT_NAME, self.paymentMethod.nonce);
                                self.formNapper.submit();
                            });
                        }
                    });
                };
                NonceManager.prototype.teardown = function () {
                    this._clearNonce();
                };
                module.exports = NonceManager;
            }, { "158": 158, "203": 203 }], 172: [function (require, module, exports) {
                'use strict';
                var isFunction = require(146);
                function noop() { }
                module.exports = function lookupCallbackFor(model) {
                    return function (callbackName, fallbackCallback) {
                        if (isFunction(model[callbackName])) {
                            return model[callbackName];
                        }
                        else if (isFunction(fallbackCallback)) {
                            return fallbackCallback;
                        }
                        return noop;
                    };
                };
            }, { "146": 146 }], 173: [function (require, module, exports) {
                'use strict';
                function isJQueryElement(element) {
                    return Boolean(element) && typeof element === 'object' && 'jquery' in element;
                }
                function isHTMLElement(element) {
                    return Boolean(element) && element.nodeType === 1;
                }
                module.exports = {
                    isJQueryElement: isJQueryElement,
                    isHTMLElement: isHTMLElement
                };
            }, {}], 174: [function (require, module, exports) {
                'use strict';
                module.exports = function sanitizePayload(payload) {
                    return {
                        nonce: payload.nonce,
                        details: payload.details,
                        type: payload.type
                    };
                };
            }, {}], 175: [function (require, module, exports) {
                (function (global) {
                    'use strict';
                    var VERSION = "2.26.0";
                    var api = require(14);
                    var paypal = require(209);
                    var dropin = require(195);
                    var integrations = require(167);
                    var constants = require(162);
                    var fallbackErrorHandler = require(170);
                    var lookupCallbackFor = require(172);
                    var utils = require(73);
                    var dataCollector = require(188);
                    function setup(authorization, integrationType, merchantConfiguration) {
                        var channel;
                        if (!integrations.hasOwnProperty(integrationType)) {
                            throw new Error(integrationType + ' is an unsupported integration');
                        }
                        merchantConfiguration = merchantConfiguration || {};
                        channel = utils.uuid();
                        api._getConfiguration({
                            enableCORS: merchantConfiguration.enableCORS || false,
                            authorization: authorization,
                            sessionId: channel
                        }, function (err, gatewayConfiguration) {
                            var errorFallback;
                            if (err) {
                                errorFallback = lookupCallbackFor(merchantConfiguration)(constants.ROOT_ERROR_CALLBACK, fallbackErrorHandler);
                                errorFallback({ message: err.errors });
                                return;
                            }
                            new integrations[integrationType]({
                                channel: channel,
                                authorization: authorization,
                                gatewayConfiguration: gatewayConfiguration,
                                integrationType: integrationType,
                                merchantConfiguration: merchantConfiguration,
                                analyticsConfiguration: {
                                    sdkVersion: 'braintree/web/' + VERSION,
                                    merchantAppId: global.location.host
                                },
                                isMerchantPageHttps: utils.isBrowserHttps()
                            });
                        });
                    }
                    module.exports = {
                        api: api,
                        data: dataCollector,
                        cse: global.Braintree,
                        paypal: paypal,
                        dropin: dropin,
                        hostedFields: { VERSION: require(203).VERSION },
                        setup: setup,
                        VERSION: VERSION
                    };
                }).call(this, typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {});
            }, { "14": 14, "162": 162, "167": 167, "170": 170, "172": 172, "188": 188, "195": 195, "203": 203, "209": 209, "73": 73 }], 176: [function (require, module, exports) {
                'use strict';
                var Coinbase = require(179);
                function create(options) {
                    var result = new Coinbase(options);
                    return result.canCreateIntegration ? result : null;
                }
                module.exports = { create: create };
            }, { "179": 179 }], 177: [function (require, module, exports) {
                (function (global) {
                    'use strict';
                    function iOSSafariVersion(userAgent) {
                        userAgent = userAgent || global.navigator.userAgent;
                        if (!/AppleWebKit\//.test(userAgent)) {
                            return null;
                        }
                        if (!/Mobile\//.test(userAgent)) {
                            return null;
                        }
                        return userAgent.replace(/.* OS ([0-9_]+) like Mac OS X.*/, '$1').replace(/_/g, '.');
                    }
                    function ieVersion(UA) {
                        var userAgent = UA || global.navigator.userAgent;
                        var result = null;
                        var match = /MSIE.(\d+)/.exec(userAgent);
                        if (/Trident/.test(userAgent)) {
                            result = 11;
                        }
                        if (match) {
                            result = parseInt(match[1], 10);
                        }
                        return result;
                    }
                    function androidVersion(UA) {
                        UA = UA || global.navigator.userAgent;
                        if (!/Android/.test(UA)) {
                            return null;
                        }
                        return UA.replace(/^.* Android ([0-9\.]+).*$/, '$1');
                    }
                    module.exports = {
                        ieVersion: ieVersion,
                        iOSSafariVersion: iOSSafariVersion,
                        androidVersion: androidVersion
                    };
                }).call(this, typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {});
            }, {}], 178: [function (require, module, exports) {
                'use strict';
                var busEvents = require(158).events;
                function tokenize(err, payload, coinbase) {
                    if (err) {
                        // TODO: make payload in line with onError()
                        coinbase.bus.emit(busEvents.ERROR, err.error);
                        coinbase.bus.emit(busEvents.SEND_ANALYTICS_EVENTS, 'coinbase.generate.nonce.failed');
                        return;
                    }
                    coinbase.bus.emit(busEvents.PAYMENT_METHOD_GENERATED, payload);
                    coinbase.bus.emit(busEvents.SEND_ANALYTICS_EVENTS, 'coinbase.generate.nonce.succeeded');
                }
                module.exports = { tokenize: tokenize };
            }, { "158": 158 }], 179: [function (require, module, exports) {
                (function (global) {
                    'use strict';
                    var bind = require(87);
                    var utils = require(73);
                    var Destructor = require(77);
                    var DOMComposer = require(183);
                    var urlComposer = require(186);
                    var callbacks = require(178);
                    var constants = require(180);
                    var detector = require(181);
                    var Bus = require(158);
                    var api = require(14);
                    function _getPopupParams(configuration) {
                        return {
                            clientId: configuration.gatewayConfiguration.coinbase.clientId,
                            redirectUrl: configuration.gatewayConfiguration.coinbase.redirectUrl,
                            scopes: configuration.gatewayConfiguration.coinbase.scopes || constants.SCOPES,
                            meta: {
                                authorizations_merchant_account: configuration.gatewayConfiguration.coinbase.merchantAccount || '' // eslint-disable-line camelcase
                            }
                        };
                    }
                    function _error(bus) {
                        return function (message, type) {
                            bus.emit(Bus.events.ERROR, { type: type, message: message });
                        };
                    }
                    function _optionsAreValid(configuration, bus) {
                        var cbOptions = (configuration.merchantConfiguration || {}).coinbase;
                        var busError = _error(bus);
                        if (configuration.apiClient == null) {
                            busError('apiClient is required for coinbase', constants.CONFIGURATION_ERROR);
                        }
                        else if (!configuration.gatewayConfiguration.coinbaseEnabled) {
                            busError('Coinbase is not enabled for your merchant account', constants.CONFIGURATION_ERROR);
                        }
                        else if (!cbOptions || !cbOptions.container && !cbOptions.button) {
                            busError('Either options.coinbase.container or options.coinbase.button is required for Coinbase integrations', constants.CONFIGURATION_ERROR);
                        }
                        else if (cbOptions.container && cbOptions.button) {
                            busError('options.coinbase.container and options.coinbase.button are mutually exclusive', constants.CONFIGURATION_ERROR);
                        }
                        else if (!detector.isSupportedBrowser()) {
                            busError('Coinbase is not supported by your browser. Please consider upgrading', constants.UNSUPPORTED_BROWSER_ERROR);
                        }
                        else {
                            return true;
                        }
                        return false;
                    }
                    function Coinbase(configuration) {
                        var context, busOptions;
                        var self = this;
                        this.configuration = configuration;
                        this.destructor = new Destructor();
                        busOptions = { channel: configuration.channel };
                        try {
                            if (configuration.coinbase.container) {
                                busOptions.merchantUrl = global.location.href;
                            }
                        }
                        catch (e) { }
                        this.bus = configuration.bus || new Bus(busOptions);
                        this.canCreateIntegration = _optionsAreValid(configuration, this.bus);
                        if (!this.canCreateIntegration) {
                            return;
                        }
                        this.buttonId = configuration.merchantConfiguration.coinbase.button || constants.BUTTON_ID;
                        this.apiClient = configuration.apiClient || new api.Client(configuration);
                        this._onOAuthSuccess = bind(this._onOAuthSuccess, this);
                        this._handleButtonClick = bind(this._handleButtonClick, this);
                        this.popupParams = _getPopupParams(configuration);
                        this.redirectDoneInterval = null;
                        if (configuration.merchantConfiguration.coinbase.container) {
                            context = utils.normalizeElement(configuration.merchantConfiguration.coinbase.container);
                            this._insertFrame(context);
                        }
                        else {
                            global.braintreeCoinbasePopupCallback = this._onOAuthSuccess;
                            context = document.body;
                            utils.addEventListener(context, 'click', this._handleButtonClick);
                            this.bus.emit(Bus.events.SEND_ANALYTICS_EVENTS, 'coinbase.initialized');
                            this.destructor.registerFunctionForTeardown(function () {
                                self._closePopup();
                            });
                            this.bus.on(constants.TEARDOWN_EVENT, bind(this.destructor.teardown, this.destructor));
                        }
                    }
                    Coinbase.prototype._insertFrame = function (container) {
                        var self = this;
                        var frame = DOMComposer.createFrame({ channel: this.configuration.channel });
                        this.bus.emit(Bus.events.ASYNC_DEPENDENCY_INITIALIZING);
                        container.appendChild(frame);
                        this.destructor.registerFunctionForTeardown(function () {
                            container.removeChild(frame);
                        });
                        // Delayed to make sure browser caches are busted.
                        setTimeout(function () {
                            frame.src = self.configuration.gatewayConfiguration.assetsUrl + '/coinbase/' + constants.VERSION + '/coinbase-frame.html#' + self.configuration.channel;
                        }, 0);
                    };
                    Coinbase.prototype._onOAuthSuccess = function (data) {
                        var self = this;
                        if (!data.code) {
                            this.bus.emit(Bus.events.SEND_ANALYTICS_EVENTS, 'coinbase.popup.denied');
                            this._closePopup();
                            return;
                        }
                        this.bus.emit('coinbase:view:navigate', 'loading');
                        this.bus.emit(Bus.events.SEND_ANALYTICS_EVENTS, 'coinbase.popup.authorized');
                        this.apiClient.tokenizeCoinbase({ code: data.code, query: urlComposer.getQueryString() }, function (err, payload) {
                            callbacks.tokenize.apply(null, [err, payload, self]);
                        });
                        this._closePopup();
                    };
                    Coinbase.prototype._clearPollForRedirectDone = function () {
                        if (this.redirectDoneInterval) {
                            clearInterval(this.redirectDoneInterval);
                            this.redirectDoneInterval = null;
                        }
                    };
                    Coinbase.prototype._closePopup = function (popup) {
                        popup = popup || this.popup;
                        if (popup == null) {
                            return;
                        }
                        if (detector.shouldCloseFromParent()) {
                            popup.close();
                        }
                        this._popupCleanup();
                    };
                    Coinbase.prototype._popupCleanup = function () {
                        this._clearPollForRedirectDone();
                        this.bus.emit(Bus.events.UI_POPUP_DID_CLOSE, { source: constants.INTEGRATION_NAME });
                    };
                    Coinbase.prototype._pollForRedirectDone = function (popup) {
                        var self = this;
                        var interval = setInterval(function () {
                            var code;
                            if (popup == null || popup.closed) {
                                self.bus.emit(Bus.events.SEND_ANALYTICS_EVENTS, 'coinbase.popup.aborted');
                                self._popupCleanup();
                                return;
                            }
                            try {
                                if (popup.location.href === 'about:blank') {
                                    throw new Error('Not finished loading');
                                }
                                code = utils.decodeQueryString(popup.location.search.replace(/^\?/, '')).code;
                            }
                            catch (e) {
                                return;
                            }
                            self._onOAuthSuccess({ code: code });
                        }, 100);
                        this.redirectDoneInterval = interval;
                        return interval;
                    };
                    Coinbase.prototype._openPopup = function () {
                        var popup;
                        this.bus.emit(Bus.events.SEND_ANALYTICS_EVENTS, 'coinbase.popup.started');
                        popup = DOMComposer.createPopup(urlComposer.compose(this._getOAuthBaseUrl(), this.popupParams));
                        popup.focus();
                        this._pollForRedirectDone(popup);
                        this.bus.emit(Bus.events.UI_POPUP_DID_OPEN, { source: constants.INTEGRATION_NAME });
                        this.bus.on(Bus.events.UI_POPUP_FORCE_CLOSE, function (payload) {
                            if (payload.target === constants.INTEGRATION_NAME) {
                                popup.close();
                            }
                        });
                        this.popup = popup;
                    };
                    Coinbase.prototype._getOAuthBaseUrl = function () {
                        var baseUrl;
                        if (this.configuration.gatewayConfiguration.coinbase.environment === 'shared_sandbox') {
                            baseUrl = constants.SANDBOX_OAUTH_BASE_URL;
                        }
                        else {
                            baseUrl = constants.PRODUCTION_OAUTH_BASE_URL;
                        }
                        return baseUrl;
                    };
                    Coinbase.prototype._handleButtonClick = function (event) {
                        var target = event.target || event.srcElement;
                        while (true) {
                            if (target == null) {
                                return;
                            }
                            if (target === event.currentTarget) {
                                return;
                            }
                            if (target.id === this.buttonId) {
                                break;
                            }
                            target = target.parentNode;
                        }
                        if (event && event.preventDefault) {
                            event.preventDefault();
                        }
                        else {
                            event.returnValue = false;
                        }
                        this._openPopup();
                    };
                    Coinbase.prototype.teardown = function (done) {
                        var self = this;
                        if (!this.canCreateIntegration) {
                            done(null);
                            return;
                        }
                        this.bus.emit(constants.TEARDOWN_EVENT, function () {
                            self.destructor.teardown(function (err) {
                                if (err) {
                                    return done(err);
                                }
                                self.bus.teardown();
                                done(null);
                            });
                        });
                    };
                    module.exports = Coinbase;
                }).call(this, typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {});
            }, { "14": 14, "158": 158, "178": 178, "180": 180, "181": 181, "183": 183, "186": 186, "73": 73, "77": 77, "87": 87 }], 180: [function (require, module, exports) {
                'use strict';
                module.exports = {
                    PRODUCTION_OAUTH_BASE_URL: 'https://coinbase.com',
                    SANDBOX_OAUTH_BASE_URL: 'https://sandbox.coinbase.com',
                    ORIGIN_URL: 'https://www.coinbase.com',
                    FRAME_NAME: 'braintree-coinbase-frame',
                    POPUP_NAME: 'coinbase',
                    BUTTON_ID: 'bt-coinbase-button',
                    SCOPES: 'send',
                    VERSION: "2.26.0",
                    INTEGRATION_NAME: 'Coinbase',
                    CONFIGURATION_ERROR: 'CONFIGURATION',
                    UNSUPPORTED_BROWSER_ERROR: 'UNSUPPORTED_BROWSER',
                    TEARDOWN_EVENT: 'coinbase:TEARDOWN'
                };
            }, {}], 181: [function (require, module, exports) {
                'use strict';
                var browser = require(177);
                function isSupportedBrowser() {
                    var version = browser.ieVersion();
                    return !version || version > 8;
                }
                function shouldDisplayLollipopClose() {
                    var version = browser.androidVersion();
                    if (version == null) {
                        return false;
                    }
                    return /^5/.test(version);
                }
                function shouldCloseFromParent() {
                    return !(shouldDisplayLollipopClose() || shouldDisplayIOSClose());
                }
                function shouldDisplayIOSClose() {
                    var version = browser.iOSSafariVersion();
                    if (version == null) {
                        return false;
                    }
                    return /^8\.0/.test(version) || /^8\.1$/.test(version);
                }
                module.exports = {
                    isSupportedBrowser: isSupportedBrowser,
                    shouldCloseFromParent: shouldCloseFromParent,
                    shouldDisplayIOSClose: shouldDisplayIOSClose,
                    shouldDisplayLollipopClose: shouldDisplayLollipopClose
                };
            }, { "177": 177 }], 182: [function (require, module, exports) {
                'use strict';
                function createButton(config) {
                    var button = document.createElement('button');
                    config = config || {};
                    button.id = config.id || 'coinbase-button';
                    button.style.backgroundColor = config.backgroundColor || '#EEE';
                    button.style.color = config.color || '#4597C3';
                    button.style.border = config.border || '0';
                    button.style.borderRadius = config.borderRadius || '6px';
                    button.style.padding = config.padding || '12px';
                    button.innerHTML = config.innerHTML || 'coinbase';
                    return button;
                }
                module.exports = { create: createButton };
            }, {}], 183: [function (require, module, exports) {
                'use strict';
                var popup = require(185);
                var button = require(182);
                var frame = require(184);
                module.exports = {
                    createButton: button.create,
                    createPopup: popup.create,
                    createFrame: frame.create
                };
            }, { "182": 182, "184": 184, "185": 185 }], 184: [function (require, module, exports) {
                'use strict';
                var constants = require(180);
                var iframer = require(82);
                function createFrame() {
                    return iframer({
                        name: constants.FRAME_NAME,
                        height: '70px',
                        width: '100%',
                        style: {
                            padding: 0,
                            margin: 0,
                            border: 0,
                            outline: 'none'
                        }
                    });
                }
                module.exports = { create: createFrame };
            }, { "180": 180, "82": 82 }], 185: [function (require, module, exports) {
                (function (global) {
                    'use strict';
                    var constants = require(180);
                    function _stringifyParams(payload) {
                        var param;
                        var params = [];
                        for (param in payload) {
                            if (payload.hasOwnProperty(param)) {
                                params.push([param, payload[param]].join('='));
                            }
                        }
                        return params.join(',');
                    }
                    function _getParams() {
                        var baseWidth = 580;
                        var baseHeight = 810;
                        return _stringifyParams({
                            width: baseWidth,
                            height: baseHeight,
                            left: (screen.width - baseWidth) / 2,
                            top: (screen.height - baseHeight) / 4
                        });
                    }
                    function createPopup(url) {
                        return global.open(url, constants.POPUP_NAME, _getParams());
                    }
                    module.exports = { create: createPopup };
                }).call(this, typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {});
            }, { "180": 180 }], 186: [function (require, module, exports) {
                'use strict';
                var constants = require(180);
                function getQueryString() {
                    return 'version=' + constants.VERSION;
                }
                function compose(baseUrl, params) {
                    var key;
                    var url = baseUrl + '/oauth/authorize?response_type=code';
                    var redirectUri = params.redirectUrl + '?' + getQueryString();
                    url += '&redirect_uri=' + encodeURIComponent(redirectUri);
                    url += '&client_id=' + params.clientId;
                    if (params.scopes) {
                        url += '&scope=' + encodeURIComponent(params.scopes);
                    }
                    if (params.meta) {
                        for (key in params.meta) {
                            if (params.meta.hasOwnProperty(key)) {
                                url += '&meta[' + encodeURIComponent(key) + ']=' + encodeURIComponent(params.meta[key]);
                            }
                        }
                    }
                    return url;
                }
                module.exports = {
                    compose: compose,
                    getQueryString: getQueryString
                };
            }, { "180": 180 }], 187: [function (require, module, exports) {
                'use strict';
                function setup() {
                    return new Fraudnet();
                }
                function Fraudnet() {
                    this.sessionId = _generateSessionId();
                    this._beaconId = _generateBeaconId(this.sessionId);
                    this._parameterBlock = _createParameterBlock(this.sessionId, this._beaconId);
                    this._thirdPartyBlock = _createThirdPartyBlock();
                }
                Fraudnet.prototype.teardown = function () {
                    this._thirdPartyBlock.parentNode.removeChild(this._thirdPartyBlock);
                };
                function _generateSessionId() {
                    var i;
                    var id = '';
                    for (i = 0; i < 32; i++) {
                        id += Math.floor(Math.random() * 16).toString(16);
                    }
                    return id;
                }
                function _generateBeaconId(sessionId) {
                    var timestamp = new Date().getTime() / 1000;
                    return 'https://b.stats.paypal.com/counter.cgi' +
                        '?i=127.0.0.1' +
                        '&p=' + sessionId +
                        '&t=' + timestamp +
                        '&a=14';
                }
                function _createParameterBlock(sessionId, beaconId) {
                    var el = document.body.appendChild(document.createElement('script'));
                    el.type = 'application/json';
                    el.setAttribute('fncls', 'fnparams-dede7cc5-15fd-4c75-a9f4-36c430ee3a99');
                    el.text = JSON.stringify({
                        f: sessionId,
                        s: 'BRAINTREE_SIGNIN',
                        b: beaconId
                    });
                    return el;
                }
                function _createThirdPartyBlock() {
                    var dom, doc;
                    var scriptBaseURL = 'https://www.paypalobjects.com/webstatic/r/fb/';
                    var iframe = document.createElement('iframe');
                    iframe.src = 'about:blank';
                    iframe.title = '';
                    iframe.role = 'presentation'; // a11y
                    (iframe.frameElement || iframe).style.cssText = 'width: 0; height: 0; border: 0';
                    document.body.appendChild(iframe);
                    try {
                        doc = iframe.contentWindow.document;
                    }
                    catch (e) {
                        dom = document.domain;
                        iframe.src = 'javascript:var d=document.open();d.domain="' + dom + '";void(0);'; // eslint-disable-line
                        doc = iframe.contentWindow.document;
                    }
                    doc.open()._l = function () {
                        var js = this.createElement('script');
                        if (dom) {
                            this.domain = dom;
                        }
                        js.id = 'js-iframe-async';
                        js.src = scriptBaseURL + 'fb-all-prod.pp.min.js';
                        this.body.appendChild(js);
                    };
                    function listener() { doc._l(); }
                    if (iframe.addEventListener) {
                        iframe.addEventListener('load', listener, false);
                    }
                    else if (iframe.attachEvent) {
                        iframe.attachEvent('onload', listener);
                    }
                    else {
                        doc.write('<body onload="document._l();">');
                    }
                    doc.close();
                    return iframe;
                }
                module.exports = {
                    setup: setup
                };
            }, {}], 188: [function (require, module, exports) {
                'use strict';
                /* eslint-disable camelcase */
                var kount = require(189);
                var fraudnet = require(187);
                function setup(options) {
                    var data, kountInstance, fraudnetInstance;
                    var instances = [];
                    function teardown() {
                        var i;
                        for (i = 0; i < instances.length; i++) {
                            instances[i].teardown();
                        }
                    }
                    if (options.kount != null) {
                        kountInstance = kount.setup(options.kount);
                        data = kountInstance.deviceData;
                        instances.push(kountInstance);
                    }
                    else {
                        data = {};
                    }
                    if (options.paypal === true) {
                        fraudnetInstance = fraudnet.setup();
                        data.correlation_id = fraudnetInstance.sessionId;
                        instances.push(fraudnetInstance);
                    }
                    return {
                        deviceData: JSON.stringify(data),
                        teardown: teardown
                    };
                }
                module.exports = {
                    setup: setup
                };
            }, { "187": 187, "189": 189 }], 189: [function (require, module, exports) {
                (function (global) {
                    'use strict';
                    /* eslint-disable camelcase */
                    var sjcl = global.Braintree.sjcl;
                    var IFRAME_ID = 'braintreeDataFrame';
                    var BRAINTREE_KOUNT_ID = '600000';
                    var QA_URL = 'https://assets.qa.braintreepayments.com/data';
                    var environmentUrls = {
                        development: QA_URL,
                        qa: QA_URL,
                        sandbox: 'https://assets.braintreegateway.com/sandbox/data',
                        production: 'https://assets.braintreegateway.com/data'
                    };
                    function setup(o) {
                        var options = o != null ? o : {};
                        return new Kount(options);
                    }
                    function Kount(options) {
                        sjcl.random.startCollectors();
                        this._currentEnvironment = this._initializeEnvironment(options);
                        this._deviceSessionId = this._generateDeviceSessionId();
                        this.deviceData = this._getDeviceData();
                        this._iframe = this._setupIFrame();
                    }
                    Kount.prototype.teardown = function () {
                        sjcl.random.stopCollectors();
                        this._removeIframe();
                    };
                    Kount.prototype._removeIframe = function () {
                        this._iframe.parentNode.removeChild(this._iframe);
                    };
                    Kount.prototype._getDeviceData = function () {
                        return {
                            device_session_id: this._deviceSessionId,
                            fraud_merchant_id: this._currentEnvironment.id
                        };
                    };
                    Kount.prototype._generateDeviceSessionId = function () {
                        var bits, hexString;
                        bits = sjcl.random.randomWords(4, 0);
                        hexString = sjcl.codec.hex.fromBits(bits);
                        return hexString;
                    };
                    Kount.prototype._setupIFrame = function () {
                        var params;
                        var self = this;
                        var iframe = document.getElementById(IFRAME_ID);
                        if (iframe != null) {
                            return iframe;
                        }
                        params = '?m=' + this._currentEnvironment.id + '&s=' + this._deviceSessionId;
                        iframe = document.createElement('iframe');
                        iframe.width = 1;
                        iframe.id = IFRAME_ID;
                        iframe.height = 1;
                        iframe.frameBorder = 0;
                        iframe.scrolling = 'no';
                        document.body.appendChild(iframe);
                        setTimeout(function () {
                            iframe.src = self._currentEnvironment.url + '/logo.htm' + params;
                            // This is in a try/catch because it throws an error in IE8.
                            // Kount will still work even if this fails.
                            try {
                                iframe.innerHTML = '<img src="' + self._currentEnvironment.url + '/logo.gif' + params + '" />';
                            }
                            catch (e) { }
                        }, 10);
                        return iframe;
                    };
                    Kount.prototype._initializeEnvironment = function (options) {
                        var url = environmentUrls[options.environment];
                        if (url == null) {
                            throw new Error(options.environment + ' is not a valid environment for kount.environment');
                        }
                        return {
                            url: url,
                            name: options.environment,
                            id: options.merchantId == null ? BRAINTREE_KOUNT_ID : options.merchantId
                        };
                    };
                    module.exports = {
                        setup: setup,
                        Kount: Kount,
                        environmentUrls: environmentUrls
                    };
                }).call(this, typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {});
            }, {}], 190: [function (require, module, exports) {
                'use strict';
                var RPC_METHOD_NAMES = ['unlockCreditCard'];
                function APIProxyServer(apiClient) {
                    this.apiClient = apiClient;
                }
                APIProxyServer.prototype.attach = function (rpcServer) {
                    var self = this;
                    var i = 0;
                    var len = RPC_METHOD_NAMES.length;
                    function attachDefine(name) {
                        rpcServer.define(name, function () {
                            self.apiClient[name].apply(self.apiClient, arguments);
                        });
                    }
                    for (i; i < len; i++) {
                        attachDefine(RPC_METHOD_NAMES[i]);
                    }
                };
                module.exports = APIProxyServer;
            }, {}], 191: [function (require, module, exports) {
                (function (global) {
                    'use strict';
                    var htmlNode, bodyNode;
                    var api = require(14);
                    var BraintreeBus = require(158);
                    var Destructor = require(77);
                    var rpc = require(55);
                    var utils = require(73);
                    var normalizeElement = utils.normalizeElement;
                    var bind = require(87);
                    var APIProxyServer = require(190);
                    var MerchantFormManager = require(194);
                    var FrameContainer = require(193);
                    var constants = require(196);
                    var version = "2.26.0";
                    var PayPalModalView = require(213);
                    function getElementStyle(element, style) {
                        var computedStyle = window.getComputedStyle ? getComputedStyle(element) : element.currentStyle;
                        return computedStyle[style];
                    }
                    function getMerchantPageDefaultStyles() {
                        return {
                            html: {
                                height: htmlNode.style.height || '',
                                overflow: getElementStyle(htmlNode, 'overflow'),
                                position: getElementStyle(htmlNode, 'position')
                            },
                            body: {
                                height: bodyNode.style.height || '',
                                overflow: getElementStyle(bodyNode, 'overflow')
                            }
                        };
                    }
                    function isMobile() {
                        var isMobileUserAgent = /Android|iPhone|iPod|iPad/i.test(window.navigator.userAgent);
                        return isMobileUserAgent;
                    }
                    function Client(configuration) {
                        var inlineFramePath, modalFramePath, formElement;
                        var self = this;
                        this.configuration = configuration;
                        this.destructor = new Destructor();
                        this.container = null;
                        this.merchantFormManager = null;
                        this.configurationRequests = [];
                        this.braintreeApiClient = new api.Client(this.configuration);
                        this.braintreeBus = new BraintreeBus({
                            merchantUrl: global.location.href,
                            channel: this.configuration.channel
                        });
                        this.bus = new rpc.MessageBus(this.configuration.root, this.configuration.channel);
                        this.rpcServer = new rpc.RPCServer(this.bus);
                        this.apiProxyServer = new APIProxyServer(this.braintreeApiClient);
                        this.apiProxyServer.attach(this.rpcServer);
                        inlineFramePath = this.configuration.inlineFramePath || this.configuration.gatewayConfiguration.assetsUrl + '/dropin/' + version + '/inline-frame.html';
                        modalFramePath = this.configuration.modalFramePath || this.configuration.gatewayConfiguration.assetsUrl + '/dropin/' + version + '/modal-frame.html';
                        htmlNode = document.documentElement;
                        bodyNode = document.body;
                        this.frames = {
                            inline: this._createFrame(inlineFramePath, constants.INLINE_FRAME_NAME),
                            modal: this._createFrame(modalFramePath, constants.MODAL_FRAME_NAME)
                        };
                        this.container = normalizeElement(this.configuration.merchantConfiguration.container, 'Unable to find valid container.');
                        formElement = normalizeElement(this.configuration.merchantConfiguration.form || this._findClosest(this.container, 'form'));
                        this.merchantFormManager = new MerchantFormManager({
                            form: formElement,
                            frames: this.frames,
                            onSubmit: this.configuration.merchantConfiguration.paymentMethodNonceReceived,
                            apiClient: this.braintreeApiClient
                        }).initialize();
                        this.destructor.registerFunctionForTeardown(function () {
                            self.merchantFormManager.teardown();
                        });
                        if (this.configuration.gatewayConfiguration.paypalEnabled) {
                            this._configurePayPal();
                        }
                        this.braintreeApiClient.sendAnalyticsEvents('dropin.web.initialized');
                    }
                    Client.prototype.initialize = function () {
                        var i;
                        var self = this;
                        this._initializeModal();
                        this.braintreeBus.emit(BraintreeBus.events.ASYNC_DEPENDENCY_INITIALIZING);
                        this.container.appendChild(this.frames.inline.element);
                        bodyNode.appendChild(this.frames.modal.element);
                        this.destructor.registerFunctionForTeardown(function (done) {
                            self._hideModal(function () {
                                self.container.removeChild(self.frames.inline.element);
                                bodyNode.removeChild(self.frames.modal.element);
                                done();
                            });
                        });
                        this.rpcServer.define('receiveSharedCustomerIdentifier', function (sharedCustomerIdentifier) {
                            self.braintreeApiClient.attrs.sharedCustomerIdentifier = sharedCustomerIdentifier;
                            self.braintreeApiClient.attrs.sharedCustomerIdentifierType = 'browser_session_cookie_store';
                            for (i = 0; i < self.configurationRequests.length; i++) {
                                self.configurationRequests[i](self.encodedClientToken);
                            }
                            self.configurationRequests = [];
                        });
                        this.braintreeBus.on(BraintreeBus.events.PAYMENT_METHOD_GENERATED, bind(this._handleAltPayData, this));
                        this.rpcServer.define('selectPaymentMethod', function (paymentMethods) {
                            self.frames.modal.rpcClient.invoke('selectPaymentMethod', [paymentMethods]);
                            self._showModal();
                        });
                        this.rpcServer.define('sendAddedPaymentMethod', function (paymentMethod) {
                            self.merchantFormManager.setNoncePayload(paymentMethod);
                            self.frames.inline.rpcClient.invoke('receiveNewPaymentMethod', [paymentMethod]);
                        });
                        this.rpcServer.define('sendUsedPaymentMethod', function (paymentMethod) {
                            self.frames.inline.rpcClient.invoke('selectPaymentMethod', [paymentMethod]);
                        });
                        this.rpcServer.define('sendUnlockedNonce', function (paymentMethod) {
                            self.merchantFormManager.setNoncePayload(paymentMethod);
                        });
                        this.rpcServer.define('clearNonce', function () {
                            self.merchantFormManager.clearNoncePayload();
                        });
                        this.rpcServer.define('closeDropInModal', function () {
                            self._hideModal();
                        });
                        this.rpcServer.define('setInlineFrameHeight', function (height) {
                            self.frames.inline.element.style.height = height + 'px';
                        });
                        this.bus.register('ready', function (message) {
                            if (message.source === self.frames.inline.element.contentWindow) {
                                self.frames.inline.rpcClient = new rpc.RPCClient(self.bus, message.source);
                            }
                            else if (message.source === self.frames.modal.element.contentWindow) {
                                self.frames.modal.rpcClient = new rpc.RPCClient(self.bus, message.source);
                            }
                        });
                    };
                    Client.prototype._createFrame = function (endpoint, name) {
                        return new FrameContainer(endpoint, name, this.braintreeBus);
                    };
                    Client.prototype._initializeModal = function () {
                        this.frames.modal.element.style.display = 'none';
                        this.frames.modal.element.style.position = isMobile() ? 'absolute' : 'fixed';
                        this.frames.modal.element.style.top = '0';
                        this.frames.modal.element.style.left = '0';
                        this.frames.modal.element.style.height = '100%';
                        this.frames.modal.element.style.width = '100%';
                    };
                    Client.prototype._lockMerchantWindowSize = function () {
                        setTimeout(function () {
                            htmlNode.style.overflow = 'hidden';
                            bodyNode.style.overflow = 'hidden';
                            bodyNode.style.height = '100%';
                            if (isMobile()) {
                                htmlNode.style.position = 'relative';
                                htmlNode.style.height = window.innerHeight + 'px';
                            }
                        }, 160);
                    };
                    Client.prototype._unlockMerchantWindowSize = function () {
                        var defaultStyles = this.merchantPageDefaultStyles;
                        if (!defaultStyles) {
                            return;
                        }
                        bodyNode.style.height = defaultStyles.body.height;
                        bodyNode.style.overflow = defaultStyles.body.overflow;
                        htmlNode.style.overflow = defaultStyles.html.overflow;
                        if (isMobile()) {
                            htmlNode.style.height = defaultStyles.html.height;
                            htmlNode.style.position = defaultStyles.html.position;
                        }
                        delete this.merchantPageDefaultStyles;
                    };
                    Client.prototype._showModal = function () {
                        var self = this;
                        var el = this.frames.modal.element;
                        this.merchantPageDefaultStyles = getMerchantPageDefaultStyles();
                        el.style.display = 'block';
                        this.frames.modal.rpcClient.invoke('open', [], function () {
                            setTimeout(function () {
                                self._lockMerchantWindowSize();
                                el.contentWindow.focus();
                            }, 200);
                        });
                    };
                    Client.prototype._hideModal = function (done) {
                        this._unlockMerchantWindowSize();
                        this.frames.modal.element.style.display = 'none';
                        if (done) {
                            done();
                        }
                    };
                    Client.prototype._configurePayPal = function () {
                        var paypalOptions = this.configuration.merchantConfiguration.paypal || {};
                        this.paypalModalView = new PayPalModalView({
                            channel: this.configuration.channel,
                            insertFrameFunction: paypalOptions.insertFrame,
                            paypalAssetsUrl: this.configuration.gatewayConfiguration.paypal.assetsUrl,
                            isHermes: Boolean(paypalOptions.singleUse) && Boolean(paypalOptions.amount) && Boolean(paypalOptions.currency)
                        });
                    };
                    Client.prototype._handleAltPayData = function (payload) {
                        this.merchantFormManager.setNoncePayload(payload);
                        this.frames.inline.rpcClient.invoke('receiveNewPaymentMethod', [payload]);
                        this.frames.modal.rpcClient.invoke('modalViewClose');
                    };
                    Client.prototype._findClosest = function (node, tagName) {
                        tagName = tagName.toUpperCase();
                        do {
                            if (node.nodeName === tagName) {
                                return node;
                            }
                            node = node.parentNode;
                        } while (node);
                        throw new Error('Unable to find a valid ' + tagName);
                    };
                    Client.prototype.teardown = function (done) {
                        var self = this;
                        if (this.paypalModalView) {
                            this.paypalModalView.teardown();
                        }
                        this.braintreeBus.emit(constants.MODAL_FRAME_TEARDOWN_EVENT, function () {
                            self.braintreeBus.emit(constants.INLINE_FRAME_TEARDOWN_EVENT, function () {
                                self.destructor.teardown(function (err) {
                                    if (err) {
                                        return done(err);
                                    }
                                    self.braintreeBus.teardown();
                                    done();
                                });
                            });
                        });
                    };
                    module.exports = Client;
                }).call(this, typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {});
            }, { "14": 14, "158": 158, "190": 190, "193": 193, "194": 194, "196": 196, "213": 213, "55": 55, "73": 73, "77": 77, "87": 87 }], 192: [function (require, module, exports) {
                'use strict';
                var Client = require(191);
                var VERSION = "2.26.0";
                function create(options) {
                    var client = new Client(options);
                    client.initialize();
                    return client;
                }
                module.exports = {
                    create: create,
                    VERSION: VERSION
                };
            }, { "191": 191 }], 193: [function (require, module, exports) {
                'use strict';
                var BraintreeBus = require(158);
                var constants = require(196);
                var iFramer = require(82);
                // TODO: move to shared and deduplicate from src/internal/util/dropin-util.js
                var TRANSITION_END_EVENT_NAMES = {
                    transition: 'transitionend',
                    '-o-transition': 'otransitionEnd',
                    '-moz-transition': 'transitionend',
                    '-webkit-transition': 'webkitTransitionEnd'
                };
                function getTransitionEndEventName() {
                    var eventName;
                    var fakeEl = document.createElement('fakeelement');
                    for (eventName in TRANSITION_END_EVENT_NAMES) {
                        if (typeof fakeEl.style[eventName] !== 'undefined') {
                            return TRANSITION_END_EVENT_NAMES[eventName];
                        }
                    }
                    return null;
                }
                function listenForReady(el, braintreeBus) {
                    var transitionEndEvent = getTransitionEndEventName();
                    function handler(event) {
                        if (event.target === el && event.propertyName === 'height') {
                            braintreeBus.emit(BraintreeBus.events.ASYNC_DEPENDENCY_READY);
                            el.removeEventListener(transitionEndEvent, handler);
                        }
                    }
                    if (transitionEndEvent) {
                        el.addEventListener(transitionEndEvent, handler);
                    }
                    else {
                        setTimeout(function () {
                            braintreeBus.emit(BraintreeBus.events.ASYNC_DEPENDENCY_READY);
                        }, 500);
                    }
                }
                function FrameContainer(endpoint, name, braintreeBus) {
                    var transition = 'height 210ms cubic-bezier(0.390, 0.575, 0.565, 1.000)';
                    var element = iFramer({
                        name: name,
                        width: '100%',
                        height: '68',
                        style: {
                            transition: transition,
                            WebkitTransition: transition,
                            MozTransition: transition,
                            msTransition: transition,
                            OTransition: transition,
                            border: '0',
                            zIndex: '9999'
                        }
                    });
                    this.element = element;
                    // Delayed so that browsers won't cache iframe URLs.
                    setTimeout(function () {
                        element.src = endpoint + '#' + braintreeBus.channel;
                    }, 0);
                    if (name === constants.INLINE_FRAME_NAME) {
                        listenForReady(element, braintreeBus);
                    }
                }
                module.exports = FrameContainer;
            }, { "158": 158, "196": 196, "82": 82 }], 194: [function (require, module, exports) {
                'use strict';
                var bind = require(87);
                var FormNapper = require(80);
                function MerchantFormManager(options) {
                    this.formNapper = new FormNapper(options.form);
                    this.frames = options.frames;
                    this.onSubmit = options.onSubmit;
                    this.apiClient = options.apiClient;
                }
                MerchantFormManager.prototype.initialize = function () {
                    if (this._isSubmitBased()) {
                        this._setElements();
                    }
                    this._setEvents();
                    return this;
                };
                MerchantFormManager.prototype.setNoncePayload = function (payload) {
                    this.noncePayload = payload;
                };
                MerchantFormManager.prototype.clearNoncePayload = function () {
                    this.noncePayload = null;
                };
                MerchantFormManager.prototype._isSubmitBased = function () {
                    return !this.onSubmit;
                };
                MerchantFormManager.prototype._isCallbackBased = function () {
                    return Boolean(this.onSubmit);
                };
                MerchantFormManager.prototype._setElements = function () {
                    this.nonceInput = this.formNapper.inject('payment_method_nonce', '');
                };
                MerchantFormManager.prototype._setEvents = function () {
                    this.formNapper.hijack(bind(this._handleFormSubmit, this));
                };
                MerchantFormManager.prototype._handleFormSubmit = function (event) {
                    var self = this;
                    if (this.noncePayload && this.noncePayload.nonce) {
                        this._handleNonceReply(event);
                    }
                    else {
                        this.frames.inline.rpcClient.invoke('requestNonce', [], function (payload) {
                            self.setNoncePayload(payload);
                            self._handleNonceReply(event);
                        });
                    }
                };
                MerchantFormManager.prototype._handleNonceReply = function (event) {
                    var self = this;
                    if (this._isCallbackBased()) {
                        this.apiClient.sendAnalyticsEvents('dropin.web.end.callback', function () {
                            var payload = self.noncePayload;
                            payload.originalEvent = event;
                            self.onSubmit(payload);
                            setTimeout(function () {
                                delete payload.originalEvent;
                                self.frames.inline.rpcClient.invoke('clearLoadingState');
                                self.frames.inline.rpcClient.invoke('receiveNewPaymentMethod', [payload]);
                            }, 200);
                        });
                    }
                    else {
                        this._triggerFormSubmission();
                    }
                };
                MerchantFormManager.prototype._triggerFormSubmission = function () {
                    var self = this;
                    this.nonceInput = this.formNapper.inject('payment_method_nonce', this.noncePayload.nonce);
                    this.apiClient.sendAnalyticsEvents('dropin.web.end.auto-submit', function () {
                        self.formNapper.submit();
                    });
                };
                MerchantFormManager.prototype.teardown = function () {
                    var form;
                    if (this.nonceInput) {
                        form = this.formNapper.htmlForm;
                        form.removeChild(this.nonceInput);
                    }
                    this.formNapper.detach();
                };
                module.exports = MerchantFormManager;
            }, { "80": 80, "87": 87 }], 195: [function (require, module, exports) {
                'use strict';
                module.exports = require(192);
            }, { "192": 192 }], 196: [function (require, module, exports) {
                module.exports = {
                    "PAYPAL_INTEGRATION_NAME": "PayPal",
                    "INLINE_FRAME_NAME": "braintree-dropin-frame",
                    "MODAL_FRAME_NAME": "braintree-dropin-modal-frame",
                    "PAYMENT_METHOD_TYPES": ["CoinbaseAccount", "PayPalAccount", "CreditCard"],
                    "cssClassMap": {
                        "American Express": "american-express",
                        "Diners Club": "diners-club",
                        "DinersClub": "diners-club",
                        "Discover": "discover",
                        "JCB": "jcb",
                        "Maestro": "maestro",
                        "MasterCard": "master-card",
                        "Solo": "solo",
                        "Switch": "switch",
                        "UKMaestro": "maestro",
                        "UnionPay": "unionpay",
                        "Visa": "visa"
                    },
                    "INLINE_FRAME_TEARDOWN_EVENT": "dropin:TEARDOWN_INLINE_FRAME",
                    "MODAL_FRAME_TEARDOWN_EVENT": "dropin:TEARDOWN_MODAL_FRAME"
                };
            }, {}], 197: [function (require, module, exports) {
                'use strict';
                var Form = require(199);
                var validateAnnotations = require(202);
                function setup(apiClient, configuration) {
                    var merchantConfiguration = configuration.merchantConfiguration || {};
                    var htmlForm = document.getElementById(merchantConfiguration.id);
                    var isCreditCardForm = merchantConfiguration.useCreditCard !== false;
                    if (!htmlForm) {
                        throw new Error('Unable to find form with id: "' + merchantConfiguration.id + '"');
                    }
                    if (isCreditCardForm) {
                        validateAnnotations(htmlForm);
                    }
                    return new Form(apiClient, configuration);
                }
                module.exports = { setup: setup };
            }, { "199": 199, "202": 202 }], 198: [function (require, module, exports) {
                (function (global) {
                    'use strict';
                    var ELEMENT_NODE = global.Node ? global.Node.ELEMENT_NODE : 1;
                    function extractValues(node, results) {
                        var child, i, dataAttr;
                        var children = node.children;
                        results = results || {};
                        for (i = 0; i < children.length; i++) {
                            child = children[i];
                            if (isBraintreeNode(child)) {
                                dataAttr = child.getAttribute('data-braintree-name');
                                if (dataAttr === 'postal_code') {
                                    results.billingAddress = {
                                        postalCode: child.value
                                    };
                                }
                                else {
                                    results[dataAttr] = child.value;
                                }
                                scrubAttributes(child);
                            }
                            else if (child.children && child.children.length > 0) {
                                extractValues(child, results);
                            }
                        }
                        return results;
                    }
                    function scrubAttributes(node) {
                        try {
                            node.attributes.removeNamedItem('name');
                        }
                        catch (e) { }
                    }
                    function scrubAllAttributes(node) {
                        extractValues(node);
                    }
                    function isBraintreeNode(node) {
                        return node.nodeType === ELEMENT_NODE && node.attributes['data-braintree-name'];
                    }
                    module.exports = {
                        extractValues: extractValues,
                        scrubAllAttributes: scrubAllAttributes,
                        scrubAttributes: scrubAttributes,
                        isBraintreeNode: isBraintreeNode
                    };
                }).call(this, typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {});
            }, {}], 199: [function (require, module, exports) {
                (function (global) {
                    'use strict';
                    var bind = require(87);
                    var util = require(73);
                    var fields = require(198);
                    var Destructor = require(77);
                    var Bus = require(158);
                    var PaymentMethodModel = require(201);
                    var getNonceInput = require(200);
                    var ERROR_PAYLOAD = {
                        message: 'Unable to process payments at this time',
                        type: 'IMMEDIATE'
                    };
                    function Form(apiClient, configuration) {
                        var merchantConfiguration = configuration.merchantConfiguration;
                        var hasExistingInput = typeof merchantConfiguration.paymentMethodNonceInputField === 'object';
                        var self = this;
                        this.destructor = new Destructor();
                        this.apiClient = apiClient;
                        this.isCreditCardForm = merchantConfiguration.useCreditCard !== false;
                        this.htmlForm = document.getElementById(merchantConfiguration.id);
                        this.paymentMethodNonceInput = getNonceInput(merchantConfiguration.paymentMethodNonceInputField);
                        this.htmlForm.appendChild(this.paymentMethodNonceInput);
                        this.destructor.registerFunctionForTeardown(function () {
                            if (hasExistingInput) {
                                self.paymentMethodNonceInput.value = '';
                            }
                            else {
                                self.htmlForm.removeChild(self.paymentMethodNonceInput);
                            }
                        });
                        this.model = new PaymentMethodModel();
                        this.bus = new Bus({
                            merchantUrl: global.location.href,
                            channel: configuration.channel
                        });
                        this.setEvents();
                        this.destructor.registerFunctionForTeardown(function () {
                            self.bus.teardown();
                        });
                    }
                    Form.prototype.setEvents = function () {
                        var self = this;
                        this.onSubmitHandler = bind(this.handleSubmit, this);
                        this.onExternalNonceReceived = bind(this.onExternalNonceReceived, this);
                        this.clearExternalNonce = bind(this.clearExternalNonce, this);
                        util.addEventListener(this.htmlForm, 'submit', this.onSubmitHandler);
                        this.destructor.registerFunctionForTeardown(function () {
                            util.removeEventListener(self.htmlForm, 'submit', self.onSubmitHandler);
                        });
                        this.bus.on(Bus.events.PAYMENT_METHOD_GENERATED, this.onExternalNonceReceived);
                        this.bus.on(Bus.events.PAYMENT_METHOD_CANCELLED, this.clearExternalNonce);
                    };
                    Form.prototype.handleSubmit = function (event) {
                        var type;
                        var self = this;
                        if (event.preventDefault) {
                            event.preventDefault();
                        }
                        else {
                            event.returnValue = false;
                        }
                        if (!this.isCreditCardForm) {
                            this.onNonceReceived(null, this.model.attributes);
                            return;
                        }
                        type = this.model.get('type');
                        if (type && type !== 'CreditCard') {
                            fields.scrubAllAttributes(this.htmlForm);
                            this.onNonceReceived(null, this.model.attributes);
                            return;
                        }
                        this.apiClient.tokenizeCard(fields.extractValues(this.htmlForm), function (err, nonce, payload) {
                            if (err) {
                                self.onNonceReceived(ERROR_PAYLOAD, null);
                            }
                            else {
                                self.model.set({
                                    nonce: nonce,
                                    type: payload.type,
                                    details: payload.details
                                });
                                self.onNonceReceived(null, self.model.attributes);
                            }
                        });
                    };
                    Form.prototype.writeNonceToDOM = function () {
                        this.paymentMethodNonceInput.value = this.model.get('nonce');
                    };
                    Form.prototype.onExternalNonceReceived = function (payload) {
                        this.model.set(payload);
                        this.writeNonceToDOM();
                    };
                    Form.prototype.clearExternalNonce = function () {
                        this.model.reset();
                    };
                    Form.prototype.onNonceReceived = function (err) {
                        var form = this.htmlForm;
                        if (err) {
                            this.bus.emit(Bus.events.ERROR, ERROR_PAYLOAD);
                            return;
                        }
                        util.removeEventListener(form, 'submit', this.onSubmitHandler);
                        this.writeNonceToDOM();
                        if (form.submit && (typeof form.submit === 'function' || form.submit.call)) {
                            form.submit();
                        }
                        else {
                            setTimeout(function () {
                                form.querySelector('[type="submit"]').click();
                            }, 1);
                        }
                    };
                    Form.prototype.teardown = function () {
                        this.destructor.teardown();
                    };
                    module.exports = Form;
                }).call(this, typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {});
            }, { "158": 158, "198": 198, "200": 200, "201": 201, "73": 73, "77": 77, "87": 87 }], 200: [function (require, module, exports) {
                'use strict';
                module.exports = function getNonceInput(paymentMethodNonceInputField) {
                    var nonceInputName, nonceInput;
                    if (typeof paymentMethodNonceInputField === 'object') {
                        return paymentMethodNonceInputField;
                    }
                    nonceInputName = 'payment_method_nonce';
                    if (typeof paymentMethodNonceInputField === 'string') {
                        nonceInputName = paymentMethodNonceInputField;
                    }
                    nonceInput = document.createElement('input');
                    nonceInput.name = nonceInputName;
                    nonceInput.type = 'hidden';
                    return nonceInput;
                };
            }, {}], 201: [function (require, module, exports) {
                'use strict';
                function PaymentMethodModel() {
                    this.reset();
                }
                PaymentMethodModel.prototype.get = function (key) {
                    return this.attributes[key];
                };
                PaymentMethodModel.prototype.set = function (payload) {
                    this.attributes = payload || {};
                };
                PaymentMethodModel.prototype.reset = function () {
                    this.attributes = {};
                };
                module.exports = PaymentMethodModel;
            }, {}], 202: [function (require, module, exports) {
                'use strict';
                module.exports = function validateAnnotations(htmlForm) {
                    var i, field;
                    var inputs = htmlForm.getElementsByTagName('*');
                    var valid = {};
                    for (i = 0; i < inputs.length; i++) {
                        field = inputs[i].getAttribute('data-braintree-name');
                        valid[field] = true;
                    }
                    if (!valid.number) {
                        throw new Error('Unable to find an input with data-braintree-name="number" in your form. Please add one.');
                    }
                    if (valid.expiration_date) {
                        if (valid.expiration_month || valid.expiration_year) {
                            throw new Error('You have inputs with data-braintree-name="expiration_date" AND data-braintree-name="expiration_(year|month)". Please use either "expiration_date" or "expiration_year" and "expiration_month".');
                        }
                    }
                    else {
                        if (!valid.expiration_month && !valid.expiration_year) {
                            throw new Error('Unable to find an input with data-braintree-name="expiration_date" in your form. Please add one.');
                        }
                        if (!valid.expiration_month) {
                            throw new Error('Unable to find an input with data-braintree-name="expiration_month" in your form. Please add one.');
                        }
                        if (!valid.expiration_year) {
                            throw new Error('Unable to find an input with data-braintree-name="expiration_year" in your form. Please add one.');
                        }
                    }
                };
            }, {}], 203: [function (require, module, exports) {
                'use strict';
                var HostedFields = require(205);
                var events = require(207).events;
                var VERSION = "2.26.0";
                module.exports = {
                    create: function (configuration) {
                        return new HostedFields(configuration);
                    },
                    events: events,
                    VERSION: VERSION
                };
            }, { "205": 205, "207": 207 }], 204: [function (require, module, exports) {
                'use strict';
                var constants = require(207);
                module.exports = function composeUrl(assetsUrl, channel) {
                    return assetsUrl +
                        '/hosted-fields/' +
                        constants.VERSION +
                        '/hosted-fields-frame.html#' +
                        channel;
                };
            }, { "207": 207 }], 205: [function (require, module, exports) {
                'use strict';
                var Destructor = require(77);
                var classListManager = require(74);
                var iFramer = require(82);
                var Bus = require(158);
                var composeUrl = require(204);
                var constants = require(207);
                var nodeListToArray = require(157);
                var utils = require(73);
                var findParentTags = require(208);
                var shouldUseLabelFocus = require(206);
                var events = constants.events;
                function injectFrame(frame, container) {
                    var clearboth = document.createElement('div');
                    clearboth.style.clear = 'both';
                    container = container || document.body;
                    container.appendChild(frame);
                    container.appendChild(clearboth);
                    return {
                        parent: container,
                        children: [frame, clearboth]
                    };
                }
                function inputEventHandler(fields, onFieldEvent) {
                    return function (eventData) {
                        var container = fields[eventData.fieldKey].containerElement;
                        var classList = classListManager(container);
                        eventData.target = {
                            fieldKey: eventData.fieldKey,
                            container: container
                        };
                        classList
                            .toggle(constants.externalClasses.FOCUSED, eventData.isFocused)
                            .toggle(constants.externalClasses.VALID, eventData.isValid);
                        if (eventData.isStrictlyValidating) {
                            classList.toggle(constants.externalClasses.INVALID, !eventData.isValid);
                        }
                        else {
                            classList.toggle(constants.externalClasses.INVALID, !eventData.isPotentiallyValid);
                        }
                        delete eventData.fieldKey;
                        delete eventData.isStrictlyValidating;
                        if (onFieldEvent) {
                            onFieldEvent(eventData);
                        }
                    };
                }
                function HostedFieldsIntegration(configuration) {
                    var field, container, frame, key, msg;
                    var self = this;
                    var fields = {};
                    var fieldCount = 0;
                    this.injectedNodes = [];
                    this.destructor = new Destructor();
                    this.bus = new Bus({
                        channel: configuration.channel,
                        merchantUrl: location.href
                    });
                    this.destructor.registerFunctionForTeardown(function () {
                        self.bus.teardown();
                    });
                    this.bus.emit(Bus.events.ASYNC_DEPENDENCY_INITIALIZING);
                    this.bus.emit(Bus.events.SEND_ANALYTICS_EVENTS, 'hosted-fields.initialized');
                    for (key in constants.whitelistedFields) {
                        if (constants.whitelistedFields.hasOwnProperty(key)) {
                            field = configuration.merchantConfiguration.hostedFields[key];
                            if (!field) {
                                continue;
                            }
                            container = document.querySelector(field.selector);
                            if (!container) {
                                msg = 'Unable to find element with selector "' + field.selector + '" for hostedFields.' + key;
                                this.bus.emit(Bus.events.ERROR, {
                                    message: msg
                                });
                                continue;
                            }
                            else if (container.querySelector('iframe[name^="braintree-"]')) {
                                this.bus.emit(Bus.events.ERROR, {
                                    message: 'Cannot place two elements in "' + field.selector + '"'
                                });
                                continue;
                            }
                            frame = iFramer({
                                type: key,
                                name: 'braintree-hosted-field-' + key,
                                style: constants.defaultIFrameStyle
                            });
                            this.injectedNodes.push(injectFrame(frame, container));
                            this.setupLabelFocus(key, container);
                            fields[key] = {
                                frameElement: frame,
                                containerElement: container
                            };
                            fieldCount++;
                            /* eslint-disable no-loop-func */
                            setTimeout((function (f) {
                                return function () {
                                    f.src = composeUrl(configuration.gatewayConfiguration.assetsUrl, configuration.channel);
                                };
                            })(frame), 0);
                        }
                    } /* eslint-enable no-loop-func */
                    this.bus.on(events.FRAME_READY, function (reply) {
                        fieldCount--;
                        reply(fieldCount === 0);
                    });
                    this.bus.on(events.INPUT_EVENT, inputEventHandler(fields, configuration.merchantConfiguration.hostedFields.onFieldEvent));
                    this.destructor.registerFunctionForTeardown(function () {
                        var j, k, nodeGroup;
                        for (j = 0; j < self.injectedNodes.length; j++) {
                            nodeGroup = self.injectedNodes[j];
                            for (k = 0; k < nodeGroup.children.length; k++) {
                                nodeGroup.parent.removeChild(nodeGroup.children[k]);
                            }
                            classListManager(nodeGroup.parent).remove(constants.externalClasses.FOCUSED, constants.externalClasses.INVALID, constants.externalClasses.VALID);
                        }
                    });
                }
                HostedFieldsIntegration.prototype.setupLabelFocus = function (type, container) {
                    var labels, i;
                    var bus = this.bus;
                    if (!shouldUseLabelFocus()) {
                        return;
                    }
                    if (container.id == null) {
                        return;
                    }
                    function triggerFocus() {
                        bus.emit(events.TRIGGER_INPUT_FOCUS, type);
                    }
                    labels = nodeListToArray(document.querySelectorAll('label[for="' + container.id + '"]'));
                    labels = labels.concat(findParentTags(container, 'label'));
                    for (i = 0; i < labels.length; i++) {
                        utils.addEventListener(labels[i], 'click', triggerFocus, false);
                    }
                    this.destructor.registerFunctionForTeardown(function () {
                        for (i = 0; i < labels.length; i++) {
                            utils.removeEventListener(labels[i], 'click', triggerFocus, false);
                        }
                    });
                };
                HostedFieldsIntegration.prototype.teardown = function (done) {
                    this.destructor.teardown(done);
                };
                module.exports = HostedFieldsIntegration;
            }, { "157": 157, "158": 158, "204": 204, "206": 206, "207": 207, "208": 208, "73": 73, "74": 74, "77": 77, "82": 82 }], 206: [function (require, module, exports) {
                'use strict';
                module.exports = function shouldUseLabelFocus() {
                    return !/(iPad|iPhone|iPod)/i.test(navigator.userAgent);
                };
            }, {}], 207: [function (require, module, exports) {
                'use strict';
                /* eslint-disable no-reserved-keys */
                var VERSION = "2.26.0";
                module.exports = {
                    VERSION: VERSION,
                    events: {
                        FRAME_READY: 'hosted-fields:FRAME_READY',
                        VALIDATE_STRICT: 'hosted-fields:VALIDATE_STRICT',
                        CONFIGURATION: 'hosted-fields:CONFIGURATION',
                        TOKENIZATION_REQUEST: 'hosted-fields:TOKENIZATION_REQUEST',
                        INPUT_EVENT: 'hosted-fields:INPUT_EVENT',
                        TRIGGER_INPUT_FOCUS: 'hosted-fields:TRIGGER_INPUT_FOCUS'
                    },
                    externalEvents: {
                        FOCUS: 'focus',
                        BLUR: 'blur',
                        FIELD_STATE_CHANGE: 'fieldStateChange'
                    },
                    defaultMaxLengths: {
                        number: 19,
                        postalCode: 8,
                        expirationDate: 7,
                        expirationMonth: 2,
                        expirationYear: 4,
                        cvv: 3
                    },
                    externalClasses: {
                        FOCUSED: 'braintree-hosted-fields-focused',
                        INVALID: 'braintree-hosted-fields-invalid',
                        VALID: 'braintree-hosted-fields-valid'
                    },
                    defaultIFrameStyle: {
                        border: 'none',
                        width: '100%',
                        height: '100%',
                        'float': 'left'
                    },
                    whitelistedStyles: [
                        '-moz-osx-font-smoothing',
                        '-moz-transition',
                        '-moz-tap-highlight-color',
                        '-webkit-font-smoothing',
                        '-webkit-transition',
                        '-webkit-tap-highlight-color',
                        'color',
                        'font',
                        'font-family',
                        'font-size',
                        'font-size-adjust',
                        'font-stretch',
                        'font-style',
                        'font-variant',
                        'font-variant-alternates',
                        'font-variant-caps',
                        'font-variant-east-asian',
                        'font-variant-ligatures',
                        'font-variant-numeric',
                        'font-weight',
                        'line-height',
                        'opacity',
                        'outline',
                        'text-shadow',
                        'transition'
                    ],
                    whitelistedFields: {
                        number: {
                            name: 'credit-card-number',
                            label: 'Credit Card Number'
                        },
                        cvv: {
                            name: 'cvv',
                            label: 'CVV'
                        },
                        expirationDate: {
                            name: 'expiration',
                            label: 'Expiration Date'
                        },
                        expirationMonth: {
                            name: 'expiration-month',
                            label: 'Expiration Month'
                        },
                        expirationYear: {
                            name: 'expiration-year',
                            label: 'Expiration Year'
                        },
                        postalCode: {
                            name: 'postal-code',
                            label: 'Postal Code'
                        }
                    }
                };
            }, {}], 208: [function (require, module, exports) {
                'use strict';
                function findParentTags(element, tag) {
                    var parent = element.parentNode;
                    var parents = [];
                    while (parent != null) {
                        if (parent.tagName != null && parent.tagName.toLowerCase() === tag) {
                            parents.push(parent);
                        }
                        parent = parent.parentNode;
                    }
                    return parents;
                }
                module.exports = findParentTags;
            }, {}], 209: [function (require, module, exports) {
                'use strict';
                module.exports = require(211);
            }, { "211": 211 }], 210: [function (require, module, exports) {
                (function (global) {
                    'use strict';
                    var braintreeUtil = require(73);
                    var bind = require(87);
                    var isFunction = require(146);
                    var Destructor = require(77);
                    var Bus = require(158);
                    var AppView = require(213);
                    var LoggedInView = require(215);
                    var LoggedOutView = require(216);
                    var OverlayView = require(219);
                    var MerchantPageView = require(217);
                    var PaymentMethodNonceInputFieldView = require(220);
                    var BridgeIframeView = require(214);
                    var browser = require(230);
                    var ua = require(226);
                    var constants = require(222);
                    var util = require(232);
                    var bindAll = require(88);
                    function Client(configuration) {
                        this.configuration = configuration;
                        this.destructor = new Destructor();
                        this.bus = new Bus({
                            merchantUrl: global.location.href,
                            channel: this.configuration.channel
                        });
                        this.container = braintreeUtil.normalizeElement(this.configuration.merchantConfiguration.paypal.container || document.body);
                        this.loggedInView = null;
                        this.loggedOutView = null;
                        this.appView = null;
                        this.merchantPageView = null;
                        this.paymentMethodNonceInputFieldView = null;
                        this.overlayView = null;
                        this.bridgeIframeView = null;
                        bindAll(this, ['initAuthFlow', 'closeAuthFlow']);
                    }
                    Client.prototype.initialize = function () {
                        var clickLoginHandler = bind(this._handleClickLogin, this);
                        this._createViews();
                        this.bus.on(Bus.events.PAYMENT_METHOD_CANCELLED, bind(this._handlePaymentMethodCancelled, this));
                        if (this.configuration.integrationType !== 'dropin') {
                            this.bus.on(Bus.events.PAYMENT_METHOD_GENERATED, bind(this._handlePaymentMethodGenerated, this));
                        }
                        braintreeUtil.addEventListener(document.body, 'click', clickLoginHandler);
                        this.destructor.registerFunctionForTeardown(function () {
                            braintreeUtil.removeEventListener(document.body, 'click', clickLoginHandler);
                        });
                    };
                    Client.prototype._createViews = function () {
                        var i;
                        var views = [];
                        var self = this;
                        var isDropin = this.configuration.integrationType === 'dropin';
                        function overlayOnFocus() {
                            if (ua.isFirefox()) {
                                self.closeAuthFlow();
                                self.initAuthFlow();
                            }
                            else {
                                self.bus.emit(constants.events.FOCUS_APP);
                            }
                        }
                        if (browser.isBridgeIframeRequired()) {
                            this.bridgeIframeView = new BridgeIframeView({
                                container: this.container,
                                paypalAssetsUrl: this.configuration.gatewayConfiguration.paypal.assetsUrl,
                                channel: this.configuration.channel
                            });
                            views.push(this.bridgeIframeView);
                        }
                        this.appView = new AppView({
                            insertFrameFunction: this.configuration.merchantConfiguration.paypal.insertFrameFunction,
                            paypalAssetsUrl: this.configuration.gatewayConfiguration.paypal.assetsUrl,
                            isHermes: util.isHermesConfiguration(this.configuration),
                            isDropin: isDropin,
                            channel: this.configuration.channel
                        });
                        views.push(this.appView);
                        if (!isDropin) {
                            this.merchantPageView = new MerchantPageView({
                                channel: this.configuration.channel
                            });
                            views.push(this.merchantPageView);
                            if (browser.isPopupSupported() && browser.isOverlaySupported()) {
                                this.overlayView = new OverlayView({
                                    paypalAssetsUrl: this.configuration.gatewayConfiguration.paypal.assetsUrl,
                                    onFocus: overlayOnFocus,
                                    onClose: function () { self.bus.emit(constants.events.CLOSE_APP); },
                                    locale: this.configuration.merchantConfiguration.paypal.locale,
                                    channel: this.configuration.channel
                                });
                                views.push(this.overlayView);
                            }
                        }
                        if (!(isDropin || this.configuration.merchantConfiguration.paypal.headless)) {
                            this.paymentMethodNonceInputFieldView = new PaymentMethodNonceInputFieldView({
                                container: this.container,
                                el: this.configuration.merchantConfiguration.paypal.paymentMethodNonceInputField,
                                channel: this.configuration.channel
                            });
                            views.push(this.paymentMethodNonceInputFieldView);
                            this.loggedInView = new LoggedInView({
                                paypalAssetsUrl: this.configuration.gatewayConfiguration.paypal.assetsUrl,
                                container: this.container,
                                locale: this.configuration.merchantConfiguration.paypal.locale,
                                channel: this.configuration.channel
                            });
                            views.push(this.loggedInView);
                            this.loggedOutView = new LoggedOutView({
                                paypalAssetsUrl: this.configuration.gatewayConfiguration.paypal.assetsUrl,
                                container: this.container,
                                enablePayPalButton: util.isOnetimeHermesConfiguration(this.configuration),
                                locale: this.configuration.merchantConfiguration.paypal.locale,
                                channel: this.configuration.channel
                            });
                            views.push(this.loggedOutView);
                        }
                        this.destructor.registerFunctionForTeardown(function () {
                            for (i = 0; i < views.length; i++) {
                                views[i].teardown();
                            }
                        });
                    };
                    Client.prototype._handleClickLogin = function (event) {
                        var target = event.target || event.srcElement;
                        while (true) {
                            if (target == null) {
                                return;
                            }
                            if (target === event.currentTarget) {
                                return;
                            }
                            if (this._isButton(target)) {
                                break;
                            }
                            target = target.parentNode;
                        }
                        util.preventDefault(event);
                        this.initAuthFlow();
                    };
                    Client.prototype.initAuthFlow = function () {
                        this.appView.open();
                    };
                    Client.prototype.closeAuthFlow = function () {
                        this.appView.close();
                    };
                    Client.prototype._isButton = function (node) {
                        var isPayPalButton = node.id === 'braintree-paypal-button';
                        var isHermesButton = util.isOnetimeHermesConfiguration(this.configuration) &&
                            node.className.match(/paypal-button(?!-widget)/);
                        return isPayPalButton || isHermesButton;
                    };
                    Client.prototype._handlePaymentMethodGenerated = function (bundle) {
                        var onSuccess = this.configuration.merchantConfiguration.paypal.onSuccess;
                        if (bundle.type === constants.NONCE_TYPE && isFunction(onSuccess)) {
                            onSuccess(bundle);
                        }
                    };
                    Client.prototype._handlePaymentMethodCancelled = function (payload) {
                        var onCancelled = this.configuration.merchantConfiguration.paypal.onCancelled;
                        if (payload.source === constants.PAYPAL_INTEGRATION_NAME && isFunction(onCancelled)) {
                            onCancelled();
                        }
                    };
                    Client.prototype.teardown = function () {
                        var self = this;
                        this.destructor.teardown(function () {
                            self.bus.teardown();
                        });
                    };
                    module.exports = Client;
                }).call(this, typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {});
            }, { "146": 146, "158": 158, "213": 213, "214": 214, "215": 215, "216": 216, "217": 217, "219": 219, "220": 220, "222": 222, "226": 226, "230": 230, "232": 232, "73": 73, "77": 77, "87": 87, "88": 88 }], 211: [function (require, module, exports) {
                'use strict';
                var Client = require(210);
                var browser = require(230);
                var constants = require(222);
                var getLocale = require(224);
                var util = require(232);
                var VERSION = "2.26.0";
                var braintreeUtil = require(73);
                function create(configuration) {
                    var client, onUnsupported;
                    onUnsupported = configuration.merchantConfiguration.onUnsupported;
                    if (typeof onUnsupported !== 'function') {
                        onUnsupported = function (error) {
                            try {
                                console.log(error); // eslint-disable-line no-console
                            }
                            catch (e) { } // eslint-disable-line
                        };
                    }
                    if (!configuration.gatewayConfiguration.paypalEnabled) {
                        onUnsupported(new Error('PayPal is not enabled'));
                        return null;
                    }
                    if (!browser.detectedPostMessage()) {
                        onUnsupported(new Error('unsupported browser detected'));
                        return null;
                    }
                    if (!configuration.merchantConfiguration.paypal.container && !configuration.merchantConfiguration.paypal.headless) {
                        onUnsupported(new Error('Please supply a container for the PayPal button to be appended to'));
                        return null;
                    }
                    if (!isBrowserSecure(configuration)) {
                        onUnsupported(new Error('unsupported protocol detected'));
                        return null;
                    }
                    if (isMisconfiguredUnvettedMerchant(configuration)) {
                        onUnsupported(new Error('Unvetted merchant client token does not include a payee email'));
                        return null;
                    }
                    if (util.isHermesConfiguration(configuration)) {
                        if (!isHermesSupportedCountry(configuration.merchantConfiguration.paypal.locale)) {
                            onUnsupported(new Error('This PayPal integration does not support this country'));
                            return null;
                        }
                    }
                    if (util.isOnetimeHermesConfiguration(configuration)) {
                        if (!isHermesSupportedCurrency(configuration.merchantConfiguration.paypal.currency)) {
                            onUnsupported(new Error('This PayPal integration does not support this currency'));
                            return null;
                        }
                        if (!isValidAmount(configuration.merchantConfiguration.paypal.amount)) {
                            onUnsupported(new Error('Amount must be a number'));
                            return null;
                        }
                    }
                    client = new Client(configuration);
                    client.initialize();
                    return client;
                }
                function isSupportedOption(option, supported) {
                    var i;
                    var supportedLength = supported.length;
                    var isSupported = false;
                    for (i = 0; i < supportedLength; i++) {
                        if (option.toLowerCase() === supported[i].toLowerCase()) {
                            isSupported = true;
                        }
                    }
                    return isSupported;
                }
                function isHermesSupportedCurrency(currency) {
                    return isSupportedOption(currency, constants.HERMES_SUPPORTED_CURRENCIES);
                }
                function isHermesSupportedCountry(locale) {
                    return isSupportedOption(getLocale(locale).split('_')[1], constants.HERMES_SUPPORTED_COUNTRIES);
                }
                function isValidAmount(amount) {
                    amount = parseFloat(amount);
                    return typeof amount === 'number' && !isNaN(amount) && amount >= 0;
                }
                function isMisconfiguredUnvettedMerchant(configuration) {
                    return configuration.gatewayConfiguration.paypal.unvettedMerchant && (!util.isHermesConfiguration(configuration) || !configuration.gatewayConfiguration.paypal.payeeEmail);
                }
                function isBrowserSecure(configuration) {
                    if (configuration.gatewayConfiguration.paypal.allowHttp) {
                        return true;
                    }
                    if (browser.isPopupSupported()) {
                        return true;
                    }
                    if ('isMerchantPageHttps' in configuration) {
                        return configuration.isMerchantPageHttps;
                    }
                    return braintreeUtil.isBrowserHttps();
                }
                module.exports = {
                    create: create,
                    VERSION: VERSION
                };
            }, { "210": 210, "222": 222, "224": 224, "230": 230, "232": 232, "73": 73 }], 212: [function (require, module, exports) {
                module.exports = {
                    "en_us": {
                        "cancel": "Cancel",
                        "overlay_text": "Don't see the secure PayPal browser? We'll help you re-launch the window to complete your purchase.",
                        "continue_link": "Continue"
                    },
                    "en_uk": {
                        "cancel": "Cancel",
                        "overlay_text": "Don't see the secure PayPal browser? We'll help you re-launch the window to complete your purchase.",
                        "continue_link": "Continue"
                    },
                    "en_au": {
                        "cancel": "Cancel",
                        "overlay_text": "Don't see the secure PayPal browser? We'll help you re-launch the window to complete your purchase.",
                        "continue_link": "Continue"
                    },
                    "sv_se": {
                        "cancel": "Avbryt",
                        "overlay_text": "Ser du inte den sÃ¤kra PayPal-webbl&auml;saren? Vi hj&auml;lper dig att starta om f&ouml;nstret f&ouml;r att slutf&ouml;ra k&ouml;pet.",
                        "continue_link": "Forts&auml;tt"
                    },
                    "de_de": {
                        "cancel": "Abbrechen",
                        "overlay_text": "Sie sehen das sichere Browserfenster von PayPal nicht? Das Fenster wird neu ge&ouml;ffnet, damit Sie Ihren Einkauf abschlie&szlig;en k&ouml;nnen.",
                        "continue_link": "Weiter"
                    },
                    "fr_fr": {
                        "cancel": "Annuler",
                        "overlay_text": "Vous ne voyez pas le navigateur s&eacute;curis&eacute; PayPal ? Nous allons vous aider &agrave; relancer la fen&ecirc;tre pour effectuer votre achat.",
                        "continue_link": "Continuer"
                    },
                    "en_ca": {
                        "cancel": "Cancel",
                        "overlay_text": "Don't see the secure PayPal browser? We'll help you re-launch the window to complete your purchase.",
                        "continue_link": "Continue"
                    },
                    "fr_ca": {
                        "cancel": "Annuler",
                        "overlay_text": "Vous ne voyez pas le navigateur s&eacute;curis&eacute; de PayPal ? Nous vous aiderons &agrave; relancer la fen&ecirc;tre afin d'effectuer votre achat.",
                        "continue_link": "Continuer"
                    },
                    "es_es": {
                        "cancel": "Cancelar",
                        "overlay_text": "&iquest;No ves el s&iacute;mbolo de navegaci&oacute;n segura de PayPal? Te ayudaremos a abrir de nuevo la ventana para completar la compra.",
                        "continue_link": "Continuar"
                    },
                    "es_xc": {
                        "cancel": "Cancelar",
                        "overlay_text": "&iquest;No ve el s&iacute;mbolo de navegaci&oacute;n segura de PayPal? Abriremos la ventana nuevamente para que pueda completar su compra.",
                        "continue_link": "Continuar"
                    },
                    "fr_xc": {
                        "cancel": "Annuler",
                        "overlay_text": "Le navigateur s&eacute;curis&eacute; de PayPal n'appara&icirc;t pas ? Nous allons vous aider &agrave; rouvrir la fen&ecirc;tre pour finaliser votre achat.",
                        "continue_link": "Continuer"
                    },
                    "nl_nl": {
                        "cancel": "Annuleren",
                        "overlay_text": "Ziet u de beveiligde PayPal-browser niet? We helpen u het venster opnieuw te openen zodat u uw aankoop kunt voltooien.",
                        "continue_link": "Doorgaan"
                    },
                    "pt_pt": {
                        "cancel": "Cancelar",
                        "overlay_text": "N&atilde;o est&aacute; a ver a indica&ccedil;&atilde;o de liga&ccedil;&atilde;o segura PayPal no browser? Vamos ent&atilde;o voltar a abrir a janela para concluir a sua compra.",
                        "continue_link": "Continuar"
                    },
                    "ru_ru": {
                        "cancel": "ÐžÑ‚Ð¼ÐµÐ½Ð°",
                        "overlay_text": "ÐÐµ Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶Ð°ÐµÑ‚ÑÑ Ð±ÐµÐ·Ð¾Ð¿Ð°ÑÐ½Ð°Ñ ÑÑ‚Ñ€Ð°Ð½Ð¸Ñ†Ð° PayPal Ð² Ð±Ñ€Ð°ÑƒÐ·ÐµÑ€Ðµ? ÐœÑ‹ Ð¿Ð¾Ð¼Ð¾Ð¶ÐµÐ¼ Ð²Ð°Ð¼ Ð¿Ð¾Ð²Ñ‚Ð¾Ñ€Ð½Ð¾ Ð·Ð°Ð³Ñ€ÑƒÐ·Ð¸Ñ‚ÑŒ Ð¾ÐºÐ½Ð¾, Ñ‡Ñ‚Ð¾Ð±Ñ‹ Ð·Ð°Ð²ÐµÑ€ÑˆÐ¸Ñ‚ÑŒ Ð¿Ð¾ÐºÑƒÐ¿ÐºÑƒ.",
                        "continue_link": "ÐŸÑ€Ð¾Ð´Ð¾Ð»Ð¶Ð¸Ñ‚ÑŒ"
                    },
                    "da_dk": {
                        "cancel": "Annuller",
                        "overlay_text": "Kan du ikke se PayPals sikre browser? Vi hj&aelig;lper dig med at &aring;bne vinduet igen, s&aring; du kan betale.",
                        "continue_link": "Forts&aelig;t"
                    },
                    "it_it": {
                        "cancel": "Annulla",
                        "overlay_text": "Non vedi il browser sicuro di PayPal? Ti aiuteremo a riavviare la pagina per completare l'acquisto.",
                        "continue_link": "Continua"
                    },
                    "no_no": {
                        "cancel": "Avbryt",
                        "overlay_text": "Ser du ikke den sikre PayPal-nettleseren? Vi hjelper deg med &aring; &aring;pne vinduet p&aring; nytt s&aring; du kan fullf&oslash;re kj&oslash;pet.",
                        "continue_link": "Fortsett"
                    },
                    "pl_pl": {
                        "cancel": "Anuluj",
                        "overlay_text": "Nie widzisz bezpiecznej przeglÄ…darki PayPal? PomoÅ¼emy Ci ponownie uruchomiÄ‡ to okno w celu dokonania zakupu.",
                        "continue_link": "Kontynuuj"
                    },
                    "tr_tr": {
                        "cancel": "Ä°ptal",
                        "overlay_text": "G&uuml;venli PayPal tarayÄ±cÄ±sÄ±nÄ± g&ouml;rm&uuml;yor musunuz? AlÄ±ÅŸveriÅŸinizi tamamlamak i&ccedil;in pencereyi yeniden baÅŸlatmanÄ±za yardÄ±mcÄ± olacaÄŸÄ±z.",
                        "continue_link": "Devam"
                    },
                    "zh_xc": {
                        "cancel": "å–æ¶ˆ",
                        "overlay_text": "æ²¡æœ‰çœ‹åˆ°å®‰å…¨çš„PayPalæµè§ˆå™¨ï¼Ÿæˆ‘ä»¬å°†å¸®åŠ©æ‚¨é‡å¯çª—å£ä»¥å®Œæˆè´­ç‰©ã€‚",
                        "continue_link": "ç»§ç»­"
                    },
                    "en_hk": {
                        "cancel": "Cancel",
                        "overlay_text": "Don't see the secure PayPal browser? We'll help you re-launch the window to complete your purchase.",
                        "continue_link": "Continue"
                    },
                    "zh_hk": {
                        "cancel": "å–æ¶ˆ",
                        "overlay_text": "çœ‹ä¸åˆ°å®‰å…¨çš„ PayPal ç€è¦½å™¨è¦–çª—ï¼Ÿæˆ‘å€‘æœƒåŠ©ä½ é‡æ–°å•Ÿå‹•è¦–çª—ï¼Œä»¥å®Œæˆè³¼ç‰©ã€‚",
                        "continue_link": "ç¹¼çºŒ"
                    },
                    "en_my": {
                        "cancel": "Cancel",
                        "overlay_text": "Don't see the secure PayPal browser? We'll help you re-launch the window to complete your purchase.",
                        "continue_link": "Continue"
                    },
                    "en_nz": {
                        "cancel": "Cancel",
                        "overlay_text": "Don't see the secure PayPal browser? We'll help you re-launch the window to complete your purchase.",
                        "continue_link": "Continue"
                    },
                    "en_sg": {
                        "cancel": "Cancel",
                        "overlay_text": "Don't see the secure PayPal browser? We'll help you re-launch the window to complete your purchase.",
                        "continue_link": "Continue"
                    }
                };
            }, {}], 213: [function (require, module, exports) {
                (function (global) {
                    'use strict';
                    var bind = require(87);
                    var isFunction = require(146);
                    var browser = require(230);
                    var Destructor = require(77);
                    var Bus = require(158);
                    var constants = require(222);
                    var PopupView = require(221);
                    var ModalView = require(218);
                    function AppView(options) {
                        var self = this;
                        this.options = options || {};
                        this.destructor = new Destructor();
                        this.bus = new Bus({
                            merchantUrl: global.location.href,
                            channel: this.options.channel
                        });
                        this.destructor.registerFunctionForTeardown(function () {
                            self.bus.teardown();
                        });
                        this._initialize();
                    }
                    AppView.prototype._initialize = function () {
                        var self = this;
                        if (browser.isPopupSupported()) {
                            this.app = new PopupView({
                                src: this._buildUrl(),
                                isHermes: this.options.isHermes,
                                channel: this.options.channel
                            });
                        }
                        else {
                            this.app = new ModalView({
                                src: this._buildUrl(),
                                isDropin: this.options.isDropin,
                                isHermes: this.options.isHermes,
                                insertFrameFunction: this.options.insertFrameFunction,
                                channel: this.options.channel
                            });
                        }
                        this.destructor.registerFunctionForTeardown(function () {
                            self.app.teardown();
                        });
                        this.bus.on(constants.events.CLOSE_APP, bind(this.close, this));
                        this.bus.on(constants.events.FOCUS_APP, bind(this.focus, this));
                        this.bus.on(Bus.events.PAYMENT_METHOD_GENERATED, bind(this._handlePaymentMethodGenerated, this));
                        this.bus.on(Bus.events.UI_POPUP_FORCE_CLOSE, bind(this._handleForceClose, this));
                    };
                    AppView.prototype._buildUrl = function () {
                        var url = this.options.paypalAssetsUrl;
                        url += '/pwpp/';
                        url += constants.VERSION;
                        url += '/html/braintree-frame.html';
                        url += '#' + this.options.channel;
                        return url;
                    };
                    AppView.prototype.open = function () {
                        this.focus();
                        this.app.open();
                        this.poll();
                    };
                    AppView.prototype._handleForceClose = function (event) {
                        if (event.target === constants.PAYPAL_INTEGRATION_NAME) {
                            this.close();
                        }
                    };
                    AppView.prototype.close = function () {
                        this.app.close();
                    };
                    AppView.prototype.focus = function () {
                        if (isFunction(this.app.focus)) {
                            this.app.focus();
                        }
                    };
                    AppView.prototype.isClosed = function () {
                        return this.app.isClosed();
                    };
                    AppView.prototype.stopPolling = function () {
                        clearInterval(this.pollId);
                    };
                    AppView.prototype.poll = function () {
                        var self = this;
                        this.pollId = setInterval(function () {
                            if (self.isClosed()) {
                                self._handleClosed();
                            }
                        }, 100);
                    };
                    AppView.prototype._handlePaymentMethodGenerated = function (bundle) {
                        if (bundle.type === constants.NONCE_TYPE) {
                            this.close();
                        }
                    };
                    AppView.prototype._handleClosed = function () {
                        this.stopPolling();
                        this.close();
                        if (browser.isPopupSupported()) {
                            this.app.el = null;
                        }
                    };
                    AppView.prototype.teardown = function () {
                        this.destructor.teardown();
                    };
                    module.exports = AppView;
                }).call(this, typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {});
            }, { "146": 146, "158": 158, "218": 218, "221": 221, "222": 222, "230": 230, "77": 77, "87": 87 }], 214: [function (require, module, exports) {
                'use strict';
                var constants = require(222);
                var iframer = require(82);
                function BridgeIframeView(options) {
                    this.options = options || {};
                    this.el = iframer({
                        src: this._buildUrl(),
                        name: constants.BRIDGE_FRAME_NAME,
                        height: 1,
                        width: 1,
                        style: {
                            position: 'static',
                            top: 0,
                            left: 0,
                            bottom: 0,
                            padding: 0,
                            margin: 0,
                            border: 0,
                            outline: 'none',
                            background: 'transparent'
                        }
                    });
                    this.options.container.appendChild(this.el);
                }
                BridgeIframeView.prototype._buildUrl = function () {
                    var url = this.options.paypalAssetsUrl;
                    url += '/pwpp/';
                    url += constants.VERSION;
                    url += '/html/bridge-frame.html';
                    url += '#' + this.options.channel;
                    return url;
                };
                BridgeIframeView.prototype.teardown = function () {
                    this.options.container.removeChild(this.el);
                };
                module.exports = BridgeIframeView;
            }, { "222": 222, "82": 82 }], 215: [function (require, module, exports) {
                (function (global) {
                    'use strict';
                    var braintreeUtil = require(73);
                    var bind = require(87);
                    var Destructor = require(77);
                    var Bus = require(158);
                    var util = require(232);
                    var dom = require(231);
                    var constants = require(222);
                    var getLocalizationData = require(225);
                    var translations = require(212);
                    function LoggedInView(options) {
                        var localizationData;
                        this.options = options || {};
                        this.wrapper = this.options.container || document.body;
                        this.destructor = new Destructor();
                        this.bus = new Bus({
                            merchantUrl: global.location.href,
                            channel: options.channel
                        });
                        localizationData = getLocalizationData(this.options.locale, translations);
                        this.translation = localizationData.translation;
                        this._initialize();
                    }
                    LoggedInView.prototype._initialize = function () {
                        var self = this;
                        var clickLogoutHandler = bind(this._handleClickLogout, this);
                        this._createViewContainer();
                        this._createPayPalName();
                        this._createEmailNode();
                        this._createLogoutNode();
                        braintreeUtil.addEventListener(this.logoutNode, 'click', clickLogoutHandler);
                        this.destructor.registerFunctionForTeardown(function () {
                            braintreeUtil.removeEventListener(self.logoutNode, 'click', clickLogoutHandler);
                        });
                        this.bus.on(Bus.events.PAYMENT_METHOD_GENERATED, bind(this._handlePaymentMethodGenerated, this));
                        this.bus.on(Bus.events.PAYMENT_METHOD_CANCELLED, bind(this._handlePaymentMethodCancelled, this));
                    };
                    LoggedInView.prototype._createViewContainer = function () {
                        var cssStyles = [
                            'display: none',
                            'max-width: 500px',
                            'overflow: hidden',
                            'padding: 16px',
                            'background-image: url(' + this.options.paypalAssetsUrl + '/pwpp/' + constants.VERSION + '/images/paypal-small.png)',
                            'background-image: url(' + this.options.paypalAssetsUrl + '/pwpp/' + constants.VERSION + '/images/paypal-small.svg), none',
                            'background-position: 20px 50%',
                            'background-repeat: no-repeat',
                            'background-size: 13px 15px',
                            'border-top: 1px solid #d1d4d6',
                            'border-bottom: 1px solid #d1d4d6'
                        ].join(';');
                        this.container = document.createElement('div');
                        this.container.id = 'braintree-paypal-loggedin';
                        this.container.style.cssText = cssStyles;
                        this.wrapper.appendChild(this.container);
                    };
                    LoggedInView.prototype._createPayPalName = function () {
                        var cssStyles = [
                            'color: #283036',
                            'font-size: 13px',
                            'font-weight: 800',
                            'font-family: "Helvetica Neue", Helvetica, Arial, sans-serif',
                            'margin-left: 36px',
                            '-webkit-font-smoothing: antialiased',
                            '-moz-font-smoothing: antialiased',
                            '-ms-font-smoothing: antialiased',
                            'font-smoothing: antialiased'
                        ].join(';');
                        this.payPalName = document.createElement('span');
                        this.payPalName.id = 'bt-pp-name';
                        this.payPalName.innerHTML = 'PayPal';
                        this.payPalName.style.cssText = cssStyles;
                        return this.container.appendChild(this.payPalName);
                    };
                    LoggedInView.prototype._createEmailNode = function () {
                        var cssStyles = [
                            'color: #6e787f',
                            'font-size: 13px',
                            'font-family: "Helvetica Neue", Helvetica, Arial, sans-serif',
                            'margin-left: 5px',
                            '-webkit-font-smoothing: antialiased',
                            '-moz-font-smoothing: antialiased',
                            '-ms-font-smoothing: antialiased',
                            'font-smoothing: antialiased'
                        ].join(';');
                        this.emailNode = document.createElement('span');
                        this.emailNode.id = 'bt-pp-email';
                        this.emailNode.style.cssText = cssStyles;
                        this.container.appendChild(this.emailNode);
                    };
                    LoggedInView.prototype._createLogoutNode = function () {
                        var cssStyles = [
                            'color: #3d95ce',
                            'font-size: 11px',
                            'font-family: "Helvetica Neue", Helvetica, Arial, sans-serif',
                            'line-height: 20px',
                            'margin: 0 0 0 25px',
                            'padding: 0',
                            'background-color: transparent',
                            'border: 0',
                            'cursor: pointer',
                            'text-decoration: underline',
                            'float: right',
                            '-webkit-font-smoothing: antialiased',
                            '-moz-font-smoothing: antialiased',
                            '-ms-font-smoothing: antialiased',
                            'font-smoothing: antialiased'
                        ].join(';');
                        this.logoutNode = document.createElement('button');
                        this.logoutNode.id = 'bt-pp-cancel';
                        this.logoutNode.innerHTML = this.translation.cancel;
                        this.logoutNode.setAttribute('type', 'button');
                        this.logoutNode.style.cssText = cssStyles;
                        this.container.appendChild(this.logoutNode);
                    };
                    LoggedInView.prototype.show = function (email) {
                        this.container.style.display = 'block';
                        dom.setTextContent(this.emailNode, email);
                    };
                    LoggedInView.prototype.hide = function () {
                        this.container.style.display = 'none';
                    };
                    LoggedInView.prototype._handleClickLogout = function (event) {
                        util.preventDefault(event);
                        this.bus.emit(Bus.events.PAYMENT_METHOD_CANCELLED, { source: constants.PAYPAL_INTEGRATION_NAME });
                    };
                    LoggedInView.prototype._handlePaymentMethodGenerated = function (bundle) {
                        var email;
                        if (bundle.type === constants.NONCE_TYPE) {
                            email = bundle && bundle.details && bundle.details.email ? bundle.details.email : '';
                            this.show(email);
                        }
                    };
                    LoggedInView.prototype._handlePaymentMethodCancelled = function (event) {
                        if (event.source === constants.PAYPAL_INTEGRATION_NAME) {
                            this.hide();
                        }
                    };
                    LoggedInView.prototype.teardown = function () {
                        this.wrapper.removeChild(this.container);
                        this.destructor.teardown();
                        this.bus.teardown();
                    };
                    module.exports = LoggedInView;
                }).call(this, typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {});
            }, { "158": 158, "212": 212, "222": 222, "225": 225, "231": 231, "232": 232, "73": 73, "77": 77, "87": 87 }], 216: [function (require, module, exports) {
                (function (global) {
                    'use strict';
                    var bind = require(87);
                    var Bus = require(158);
                    var constants = require(222);
                    var getLocale = require(224);
                    function LoggedOutView(options) {
                        this.options = options;
                        this.wrapper = this.options.container || document.body;
                        this.bus = new Bus({
                            merchantUrl: global.location.href,
                            channel: options.channel
                        });
                        this._initialize();
                    }
                    LoggedOutView.prototype._initialize = function () {
                        this.createViewContainer();
                        if (this.options.enablePayPalButton) {
                            this.createCheckoutWithPayPalButton();
                        }
                        else {
                            this.createPayWithPayPalButton();
                        }
                        this.bus.on(Bus.events.PAYMENT_METHOD_GENERATED, bind(this._handlePaymentMethodGenerated, this));
                        this.bus.on(Bus.events.PAYMENT_METHOD_CANCELLED, bind(this._handlePaymentMethodCancelled, this));
                    };
                    LoggedOutView.prototype.createViewContainer = function () {
                        this.container = document.createElement('div');
                        this.container.id = 'braintree-paypal-loggedout';
                        this.wrapper.appendChild(this.container);
                        this.loginNode = this.container;
                    };
                    LoggedOutView.prototype.createPayWithPayPalButton = function () {
                        var element = document.createElement('a');
                        var image = new Image();
                        var imageCssText = [
                            'max-width: 100%',
                            'display: block',
                            'width: 100%',
                            'height: 100%',
                            'outline: none',
                            'border: 0'
                        ].join(';');
                        var cssStyles = [
                            'display: block',
                            'width: 115px',
                            'height: 44px',
                            'overflow: hidden'
                        ].join(';');
                        element.id = 'braintree-paypal-button';
                        element.href = '#';
                        element.style.cssText = cssStyles;
                        image.src = this.options.paypalAssetsUrl + '/pwpp/' + constants.VERSION + '/images/pay-with-paypal.png';
                        image.setAttribute('alt', 'Pay with PayPal');
                        image.style.cssText = imageCssText;
                        element.appendChild(image);
                        this.container.appendChild(element);
                    };
                    LoggedOutView.prototype.createCheckoutWithPayPalButton = function () {
                        var script = document.createElement('script');
                        var attr;
                        var scriptAttrs = {
                            'data-merchant': 'merchant-id',
                            'data-button': 'checkout',
                            'data-type': 'button',
                            'data-color': 'blue',
                            'data-lc': getLocale(this.options.locale)
                        };
                        script.src = '//www.paypalobjects.com/api/button.js';
                        script.async = true;
                        for (attr in scriptAttrs) {
                            if (scriptAttrs.hasOwnProperty(attr)) {
                                script.setAttribute(attr, scriptAttrs[attr]);
                            }
                        }
                        this.container.appendChild(script);
                    };
                    LoggedOutView.prototype.show = function () {
                        this.container.style.display = 'block';
                    };
                    LoggedOutView.prototype.hide = function () {
                        this.container.style.display = 'none';
                    };
                    LoggedOutView.prototype._handlePaymentMethodGenerated = function (bundle) {
                        if (bundle.type === constants.NONCE_TYPE) {
                            this.hide();
                        }
                    };
                    LoggedOutView.prototype._handlePaymentMethodCancelled = function (event) {
                        if (event.source === constants.PAYPAL_INTEGRATION_NAME) {
                            this.show();
                        }
                    };
                    LoggedOutView.prototype.teardown = function () {
                        this.wrapper.removeChild(this.container);
                        this.bus.teardown();
                    };
                    module.exports = LoggedOutView;
                }).call(this, typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {});
            }, { "158": 158, "222": 222, "224": 224, "87": 87 }], 217: [function (require, module, exports) {
                (function (global) {
                    'use strict';
                    var Bus = require(158);
                    var bind = require(87);
                    var constants = require(222);
                    function MerchantPageView(options) {
                        this.options = options;
                        this.bus = new Bus({
                            merchantUrl: global.location.href,
                            channel: options.channel
                        });
                        this.bus.on(Bus.events.UI_MODAL_DID_OPEN, bind(this.lockWindowSize, this));
                        this.bus.on(Bus.events.UI_MODAL_DID_CLOSE, bind(this.unlockWindowSize, this));
                    }
                    MerchantPageView.prototype.lockWindowSize = function () {
                        this.defaultStyles = getMerchantPageDefaultStyles();
                        document.documentElement.style.height = '100%';
                        document.documentElement.style.overflow = 'hidden';
                        document.body.style.height = '100%';
                        document.body.style.overflow = 'hidden';
                    };
                    MerchantPageView.prototype.unlockWindowSize = function () {
                        if (this.defaultStyles) {
                            document.documentElement.style.height = this.defaultStyles.html.styles.height;
                            document.documentElement.style.overflow = this.defaultStyles.html.styles.overflow;
                            document.body.style.height = this.defaultStyles.body.styles.height;
                            document.body.style.overflow = this.defaultStyles.body.styles.overflow;
                            delete this.defaultStyles;
                        }
                    };
                    MerchantPageView.prototype._handleUIModalDidOpen = function (event) {
                        if (event.source === constants.PAYPAL_INTEGRATION_NAME) {
                            this.lockWindowSize();
                        }
                    };
                    MerchantPageView.prototype._handleUIModalDidClose = function (event) {
                        if (event.source === constants.PAYPAL_INTEGRATION_NAME) {
                            this.unlockWindowSize();
                        }
                    };
                    MerchantPageView.prototype.teardown = function () {
                        this.unlockWindowSize();
                        this.bus.teardown();
                    };
                    function getStyles(element) {
                        var computedStyles = window.getComputedStyle ? getComputedStyle(element) : element.currentStyle;
                        return {
                            overflow: computedStyles.overflow || '',
                            height: element.style.height || ''
                        };
                    }
                    function getMerchantPageDefaultStyles() {
                        return {
                            html: {
                                node: document.documentElement,
                                styles: getStyles(document.documentElement)
                            },
                            body: {
                                node: document.body,
                                styles: getStyles(document.body)
                            }
                        };
                    }
                    module.exports = MerchantPageView;
                }).call(this, typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {});
            }, { "158": 158, "222": 222, "87": 87 }], 218: [function (require, module, exports) {
                (function (global) {
                    'use strict';
                    var bind = require(87);
                    var assign = require(150);
                    var isFunction = require(146);
                    var platform = require(228);
                    var constants = require(222);
                    var Bus = require(158);
                    var iframer = require(82);
                    var isIosUIWebView = require(230).isIosUIWebView;
                    var ELEMENT_STYLES = {
                        position: 'fixed',
                        top: 0,
                        left: 0,
                        bottom: 0,
                        padding: 0,
                        margin: 0,
                        border: 0,
                        outline: 'none',
                        zIndex: 20001,
                        background: '#FFFFFF'
                    };
                    function ModalView(options) {
                        this.options = options || {};
                        this.container = document.body;
                        this.bus = new Bus({
                            merchantUrl: global.location.href,
                            channel: options.channel
                        });
                        if (this.options.isDropin) {
                            this._open = this._openHeadless;
                        }
                        else {
                            this._attachBusEvents();
                        }
                        this._initialize();
                    }
                    ModalView.prototype._attachBusEvents = function () {
                        this.bus.on(constants.events.OPEN_MODAL, bind(this.open, this));
                    };
                    ModalView.prototype._initialize = function () {
                        var name = this.options.isHermes ? constants.HERMES_FRAME_NAME : constants.FRAME_NAME;
                        if (platform.isIos()) {
                            this.el = document.createElement('div');
                            this.el.className = constants.FRAME_CONTAINER_NAME;
                            assign(this.el.style, ELEMENT_STYLES, {
                                height: this.options.height || '100%',
                                width: this.options.width || '100%',
                                overflow: 'scroll'
                            });
                            if (!isIosUIWebView()) {
                                this.el.style.webkitOverflowScrolling = 'touch';
                            }
                            this.el.appendChild(iframer({
                                src: this.options.src,
                                name: name,
                                scrolling: 'yes',
                                height: '100%',
                                width: '100%',
                                style: {
                                    position: 'absolute',
                                    top: 0,
                                    left: 0,
                                    border: 0,
                                    outline: 'none',
                                    background: '#FFFFFF'
                                }
                            }));
                        }
                        else {
                            this.el = iframer({
                                src: this.options.src,
                                name: name,
                                scrolling: 'yes',
                                height: this.options.height || '100%',
                                width: this.options.width || '100%',
                                style: ELEMENT_STYLES
                            });
                        }
                    };
                    ModalView.prototype.isClosed = function () {
                        return !this.container.contains(this.el);
                    };
                    ModalView.prototype._openHeadless = function () {
                        this.bus.emit(constants.events.OPEN_MODAL);
                    };
                    ModalView.prototype._open = function () {
                        if (isFunction(this.options.insertFrameFunction)) {
                            this.options.insertFrameFunction(this.el.src);
                        }
                        else {
                            this.container.appendChild(this.el);
                        }
                        this.bus.emit(Bus.events.UI_MODAL_DID_OPEN, { source: constants.PAYPAL_INTEGRATION_NAME });
                    };
                    ModalView.prototype.open = function () {
                        if (this.isClosed()) {
                            this._open();
                        }
                    };
                    ModalView.prototype.close = function () {
                        if (!this.isClosed()) {
                            this.container.removeChild(this.el);
                            this.bus.emit(Bus.events.UI_MODAL_DID_CLOSE, { source: constants.PAYPAL_INTEGRATION_NAME });
                        }
                    };
                    ModalView.prototype.teardown = function () {
                        this.close();
                        this.bus.teardown();
                    };
                    module.exports = ModalView;
                }).call(this, typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {});
            }, { "146": 146, "150": 150, "158": 158, "222": 222, "228": 228, "230": 230, "82": 82, "87": 87 }], 219: [function (require, module, exports) {
                (function (global) {
                    'use strict';
                    var braintreeUtil = require(73);
                    var bind = require(87);
                    var isFunction = require(146);
                    var Destructor = require(77);
                    var Bus = require(158);
                    var constants = require(222);
                    var getLocalizationData = require(225);
                    var translations = require(212);
                    function OverlayView(options) {
                        var localizationData;
                        this.options = options;
                        this.spriteSrc = this.options.paypalAssetsUrl + '/pwpp/' + constants.VERSION + '/images/pp_overlay_sprite.png';
                        this.bus = new Bus({
                            merchantUrl: global.location.href,
                            channel: options.channel
                        });
                        this.destructor = new Destructor();
                        localizationData = getLocalizationData(this.options.locale, translations);
                        this.translation = localizationData.translation;
                        this._create();
                        this._setupEvents();
                        this.bus.on(Bus.events.UI_POPUP_DID_OPEN, bind(this._handleUIPopupDidOpen, this));
                        this.bus.on(Bus.events.UI_POPUP_DID_CLOSE, bind(this._handleUIPopupDidClose, this));
                    }
                    OverlayView.prototype.open = function () {
                        if (document.body.contains(this.el)) {
                            return;
                        }
                        document.body.appendChild(this.el);
                    };
                    OverlayView.prototype.close = function () {
                        if (document.body.contains(this.el)) {
                            document.body.removeChild(this.el);
                        }
                    };
                    OverlayView.prototype._handleUIPopupDidClose = function (event) {
                        if (event.source === constants.PAYPAL_INTEGRATION_NAME) {
                            this.close();
                        }
                    };
                    OverlayView.prototype._handleUIPopupDidOpen = function (event) {
                        if (event.source === constants.PAYPAL_INTEGRATION_NAME) {
                            this.open();
                        }
                    };
                    OverlayView.prototype._create = function () {
                        this.el = document.createElement('div');
                        this.el.className = 'bt-overlay';
                        this._setStyles(this.el, [
                            'z-index: 20001',
                            'position: fixed',
                            'top: 0',
                            'left: 0',
                            'height: 100%',
                            'width: 100%',
                            'text-align: center',
                            'background: #000',
                            'background: rgba(0,0,0,0.7)',
                            '-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=52)"'
                        ]);
                        this.el.appendChild(this._createCloseIcon());
                        this.el.appendChild(this._createMessage());
                    };
                    OverlayView.prototype._createCloseIcon = function () {
                        this.closeIcon = document.createElement('div');
                        this.closeIcon.className = 'bt-close-overlay';
                        this._setStyles(this.closeIcon, [
                            'position: absolute',
                            'top: 10px',
                            'right: 10px',
                            'cursor: pointer',
                            'background: url(' + this.spriteSrc + ') no-repeat 0 -67px',
                            'height: 14px',
                            'width: 14px'
                        ]);
                        return this.closeIcon;
                    };
                    OverlayView.prototype._createMessage = function () {
                        var message = document.createElement('div');
                        this._setStyles(message, [
                            'position: relative',
                            'top: 50%',
                            'max-width: 350px',
                            'font-family: "HelveticaNeue", "HelveticaNeue-Light", "Helvetica Neue Light", helvetica, arial, sans-serif',
                            'font-size: 14px',
                            'line-height: 20px',
                            'margin: -70px auto 0'
                        ]);
                        message.appendChild(this._createLogo());
                        message.appendChild(this._createExplanation());
                        message.appendChild(this._createFocusLink());
                        return message;
                    };
                    OverlayView.prototype._createExplanation = function () {
                        this.explanation = document.createElement('div');
                        this._setStyles(this.explanation, [
                            'color: #FFF',
                            'margin-bottom: 20px'
                        ]);
                        this.explanation.innerHTML = this.translation.overlay_text;
                        return this.explanation;
                    };
                    OverlayView.prototype._createLogo = function () {
                        var logo = document.createElement('div');
                        this._setStyles(logo, [
                            'background: url(' + this.spriteSrc + ') no-repeat 0 0',
                            'width: 94px',
                            'height: 25px',
                            'margin: 0 auto 26px auto'
                        ]);
                        return logo;
                    };
                    OverlayView.prototype._createFocusLink = function () {
                        this.focusLink = document.createElement('a');
                        this._setStyles(this.focusLink, [
                            'color: #009be1',
                            'cursor: pointer'
                        ]);
                        this.focusLink.innerHTML = this.translation.continue_link;
                        return this.focusLink;
                    };
                    OverlayView.prototype._setStyles = function (el, styles) {
                        var cssStyles = styles.join(';');
                        el.style.cssText = cssStyles;
                    };
                    OverlayView.prototype._setupEvents = function () {
                        var self = this;
                        var clickCloseHandler = bind(this._handleClose, this);
                        var clickFocusHandler = bind(this._handleFocus, this);
                        braintreeUtil.addEventListener(this.closeIcon, 'click', clickCloseHandler);
                        braintreeUtil.addEventListener(this.focusLink, 'click', clickFocusHandler);
                        this.destructor.registerFunctionForTeardown(function () {
                            braintreeUtil.removeEventListener(self.closeIcon, 'click', clickCloseHandler);
                            braintreeUtil.removeEventListener(self.focusLink, 'click', clickFocusHandler);
                        });
                    };
                    OverlayView.prototype._handleClose = function (event) {
                        event.preventDefault();
                        this.close();
                        if (isFunction(this.options.onClose)) {
                            this.options.onClose();
                        }
                    };
                    OverlayView.prototype._handleFocus = function (event) {
                        event.preventDefault();
                        if (isFunction(this.options.onFocus)) {
                            this.options.onFocus();
                        }
                    };
                    OverlayView.prototype.teardown = function () {
                        this.bus.teardown();
                        this.destructor.teardown();
                        this.close();
                    };
                    module.exports = OverlayView;
                }).call(this, typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {});
            }, { "146": 146, "158": 158, "212": 212, "222": 222, "225": 225, "73": 73, "77": 77, "87": 87 }], 220: [function (require, module, exports) {
                (function (global) {
                    'use strict';
                    var braintreeUtil = require(73);
                    var bind = require(87);
                    var isFunction = require(146);
                    var Destructor = require(77);
                    var Bus = require(158);
                    var constants = require(222);
                    function PaymentMethodNonceInputFieldView(options) {
                        this.options = options || {};
                        this.container = this.options.container || document.body;
                        this.el = this.options.el;
                        this.destructor = new Destructor();
                        this.bus = new Bus({
                            merchantUrl: global.location.href,
                            channel: options.channel
                        });
                        this._initialize();
                    }
                    PaymentMethodNonceInputFieldView.prototype._initialize = function () {
                        var self = this;
                        if (!isFunction(this.el)) {
                            if (this.el != null) {
                                this.el = braintreeUtil.normalizeElement(this.el);
                                this.destructor.registerFunctionForTeardown(function () {
                                    self.clear();
                                });
                            }
                            else {
                                this.el = this.create();
                            }
                        }
                        this.bus.on(Bus.events.PAYMENT_METHOD_GENERATED, bind(this._handlePaymentMethodGenerated, this));
                        this.bus.on(Bus.events.PAYMENT_METHOD_CANCELLED, bind(this._handlePaymentMethodCancelled, this));
                    };
                    PaymentMethodNonceInputFieldView.prototype.create = function () {
                        var self = this;
                        var input = document.createElement('input');
                        input.name = 'payment_method_nonce';
                        input.type = 'hidden';
                        this.container.appendChild(input);
                        this.destructor.registerFunctionForTeardown(function () {
                            self.container.removeChild(input);
                        });
                        return input;
                    };
                    PaymentMethodNonceInputFieldView.prototype.value = function (value) {
                        if (isFunction(this.el)) {
                            this.el(value);
                        }
                        else {
                            this.el.value = value;
                        }
                    };
                    PaymentMethodNonceInputFieldView.prototype.clear = function () {
                        this.value('');
                    };
                    PaymentMethodNonceInputFieldView.prototype._handlePaymentMethodCancelled = function (event) {
                        if (event.source === constants.PAYPAL_INTEGRATION_NAME) {
                            this.clear();
                        }
                    };
                    PaymentMethodNonceInputFieldView.prototype._handlePaymentMethodGenerated = function (bundle) {
                        if (bundle.type === constants.NONCE_TYPE) {
                            this.value(bundle.nonce);
                        }
                    };
                    PaymentMethodNonceInputFieldView.prototype.teardown = function () {
                        this.destructor.teardown();
                        this.bus.teardown();
                    };
                    module.exports = PaymentMethodNonceInputFieldView;
                }).call(this, typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {});
            }, { "146": 146, "158": 158, "222": 222, "73": 73, "77": 77, "87": 87 }], 221: [function (require, module, exports) {
                (function (global) {
                    'use strict';
                    var constants = require(222);
                    var Bus = require(158);
                    var browser = require(226);
                    function PopupView(options) {
                        this.options = options;
                        this.bus = new Bus({
                            merchantUrl: global.location.href,
                            channel: this.options.channel
                        });
                        if (options.isHermes) {
                            this.name = constants.HERMES_POPUP_NAME;
                            this.popupHeight = constants.HERMES_POPUP_HEIGHT;
                            this.popupWidth = constants.HERMES_POPUP_WIDTH;
                        }
                        else {
                            this.name = constants.POPUP_NAME;
                            this.popupHeight = constants.POPUP_HEIGHT;
                            this.popupWidth = constants.POPUP_WIDTH;
                        }
                    }
                    PopupView.prototype._getPopupOptions = function () {
                        return [
                            'height=' + this.popupHeight,
                            'width=' + this.popupWidth,
                            'top=' + this._getTopPosition(),
                            'left=' + this._getLeftPosition(),
                            constants.POPUP_OPTIONS
                        ].join(',');
                    };
                    PopupView.prototype._centerPosition = function (windowMetric, popupMetric, offset) {
                        return (windowMetric - popupMetric) / 2 + offset;
                    };
                    PopupView.prototype._getTopPosition = function () {
                        var windowHeight = window.outerHeight || document.documentElement.clientHeight;
                        var windowTop = typeof window.screenY === 'undefined' ? window.screenTop : window.screenY;
                        return this._centerPosition(windowHeight, this.popupHeight, windowTop);
                    };
                    PopupView.prototype._getLeftPosition = function () {
                        var windowWidth = window.outerWidth || document.documentElement.clientWidth;
                        var windowLeft = typeof window.screenX === 'undefined' ? window.screenLeft : window.screenX;
                        return this._centerPosition(windowWidth, this.popupWidth, windowLeft);
                    };
                    PopupView.prototype.isClosed = function () {
                        if (this.el) {
                            return this.el.closed;
                        }
                    };
                    PopupView.prototype.open = function () {
                        if (!this.el || this.isClosed()) {
                            this.el = window.open(this.options.src, this.name, this._getPopupOptions());
                            this.focus();
                            this.bus.emit(Bus.events.UI_POPUP_DID_OPEN, { source: constants.PAYPAL_INTEGRATION_NAME });
                        }
                    };
                    PopupView.prototype.close = function () {
                        if (this.el) {
                            if (browser.isIE8() && !this.isClosed() || !browser.isIE8()) {
                                this.el.close();
                            }
                            this.bus.emit(Bus.events.UI_POPUP_DID_CLOSE, { source: constants.PAYPAL_INTEGRATION_NAME });
                        }
                    };
                    PopupView.prototype.focus = function () {
                        if (this.el) {
                            this.el.focus();
                        }
                    };
                    PopupView.prototype.teardown = function () {
                        this.close();
                        this.bus.teardown();
                    };
                    module.exports = PopupView;
                }).call(this, typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {});
            }, { "158": 158, "222": 222, "226": 226 }], 222: [function (require, module, exports) {
                'use strict';
                var i;
                var version = "2.26.0";
                var events = [
                    'GET_CLIENT_TOKEN',
                    'GET_CLIENT_OPTIONS',
                    'OPEN_MODAL',
                    'CLOSE_APP',
                    'FOCUS_APP'
                ];
                var configurationTypes = {
                    LEGACY_ONETIME: 'Legacy Onetime',
                    HERMES_ONETIME: 'Hermes Onetime',
                    LEGACY_FUTURE_PAYMENTS: 'Legacy Future Payments',
                    HERMES_BILLING_AGREEMENTS: 'Hermes Billing Agreements'
                };
                exports.VERSION = version;
                exports.POPUP_NAME = 'braintree_paypal_popup';
                exports.HERMES_POPUP_NAME = 'PPFrameRedirect';
                exports.FRAME_NAME = 'braintree-paypal-frame';
                exports.HERMES_FRAME_NAME = 'PPFrameRedirect';
                exports.FRAME_CONTAINER_NAME = 'braintree-paypal-frame-container';
                exports.POPUP_PATH = '/pwpp/' + version + '/html/braintree-frame.html';
                exports.POPUP_OPTIONS = 'resizable,scrollbars';
                exports.POPUP_HEIGHT = 470;
                exports.POPUP_WIDTH = 410;
                exports.HERMES_POPUP_HEIGHT = 535;
                exports.HERMES_POPUP_WIDTH = 450;
                exports.BRIDGE_FRAME_NAME = 'bt-proxy-frame';
                exports.HERMES_SUPPORTED_CURRENCIES = ['USD', 'GBP', 'EUR', 'AUD', 'CAD', 'DKK', 'NOK', 'PLN', 'SEK', 'CHF', 'TRY', 'BRL', 'MXN', 'ILS', 'SGD', 'THB', 'PHP', 'NZD', 'HKD', 'MYR', 'CZK', 'JPY', 'RUB'];
                exports.HERMES_SUPPORTED_COUNTRIES = ['US', 'GB', 'AU', 'CA', 'ES', 'FR', 'DE', 'IT', 'NL', 'NO', 'PL', 'CH', 'TR', 'DK', 'BE', 'AT', 'SE', 'HK', 'BR', 'XC'];
                exports.NONCE_TYPE = 'PayPalAccount';
                exports.PAYPAL_INTEGRATION_NAME = 'PayPal';
                exports.ILLEGAL_XHR_ERROR = 'Illegal XHR request attempted';
                exports.CONFIGURATION_TYPES = configurationTypes;
                exports.events = {};
                for (i = 0; i < events.length; i++) {
                    exports.events[events[i]] = 'paypal:' + events[i];
                }
            }, {}], 223: [function (require, module, exports) {
                'use strict';
                module.exports = {
                    us: 'en_us',
                    gb: 'en_uk',
                    uk: 'en_uk',
                    de: 'de_de',
                    fr: 'fr_fr',
                    it: 'it_it',
                    es: 'es_es',
                    ca: 'en_ca',
                    au: 'en_au',
                    at: 'de_de',
                    be: 'en_us',
                    ch: 'de_de',
                    dk: 'da_dk',
                    nl: 'nl_nl',
                    no: 'no_no',
                    pl: 'pl_pl',
                    se: 'sv_se',
                    tr: 'tr_tr',
                    bg: 'en_us',
                    cy: 'en_us',
                    hr: 'en_us',
                    is: 'en_us',
                    kh: 'en_us',
                    mt: 'en_us',
                    my: 'en_us',
                    ru: 'ru_ru'
                };
            }, {}], 224: [function (require, module, exports) {
                'use strict';
                var countryCodeLookupTable = require(223);
                function isFormatted(code) {
                    return code.indexOf('_') !== -1 && code.length === 5;
                }
                function queryTable(code) {
                    var key, match;
                    for (key in countryCodeLookupTable) {
                        if (countryCodeLookupTable.hasOwnProperty(key)) {
                            if (key === code) {
                                match = countryCodeLookupTable[key];
                            }
                            else if (countryCodeLookupTable[key] === code) {
                                match = countryCodeLookupTable[key];
                            }
                        }
                    }
                    return match;
                }
                function getLocale(code) {
                    var match, pieces;
                    code = code ? code.toLowerCase() : 'us';
                    code = code.replace(/-/g, '_');
                    match = isFormatted(code) ? code : queryTable(code);
                    if (match) {
                        pieces = match.split('_');
                        return [pieces[0], pieces[1].toUpperCase()].join('_');
                    }
                    return 'en_US';
                }
                module.exports = getLocale;
            }, { "223": 223 }], 225: [function (require, module, exports) {
                'use strict';
                var countryCodeLookupTable = require(223);
                var getLocale = require(224);
                function getCountry(code) {
                    var country = code ? code.toLowerCase().replace(/-/g, '_') : 'us';
                    if (country.indexOf('_') !== -1) {
                        country = country.split('_')[1];
                    }
                    country = countryCodeLookupTable[country] ? country : 'us';
                    if (country === 'uk') {
                        country = 'gb';
                    }
                    return country;
                }
                function getTranslation(locale, translations) {
                    locale = locale.toLowerCase();
                    return translations[locale] ? translations[locale] : translations.en_us;
                }
                function getLocalizationData(code, translations) {
                    var country = getCountry(code);
                    var locale = getLocale(code);
                    var translation = getTranslation(locale, translations);
                    return {
                        country: country,
                        locale: locale,
                        translation: translation
                    };
                }
                module.exports = getLocalizationData;
            }, { "223": 223, "224": 224 }], 226: [function (require, module, exports) {
                'use strict';
                var userAgent = require(229);
                var platform = require(228);
                function isAndroid() {
                    return userAgent.matchUserAgent('Android') && !isChrome();
                }
                function isChrome() {
                    return userAgent.matchUserAgent('Chrome') || userAgent.matchUserAgent('CriOS');
                }
                function isFirefox() {
                    return userAgent.matchUserAgent('Firefox');
                }
                function isIE() {
                    return userAgent.matchUserAgent('Trident') || userAgent.matchUserAgent('MSIE');
                }
                function isIE8() {
                    return userAgent.matchUserAgent(/MSIE 8\.0/);
                }
                function isOpera() {
                    return userAgent.matchUserAgent('Opera') || userAgent.matchUserAgent('OPR');
                }
                function isOperaMini() {
                    return isOpera() && Object.prototype.toString.call(window.operamini) === '[object OperaMini]';
                }
                function isSafari() {
                    return userAgent.matchUserAgent('Safari') && !isChrome() && !isAndroid();
                }
                function isIosWebView() {
                    return platform.isIos() && !isChrome() && !isSafari();
                }
                function isAndroidWebView() {
                    var androidWebviewRegExp = /Version\/[\w\.]+ Chrome\/[\w\.]+ Mobile/;
                    return platform.isAndroid() && userAgent.matchUserAgent(androidWebviewRegExp);
                }
                module.exports = {
                    isAndroid: isAndroid,
                    isChrome: isChrome,
                    isFirefox: isFirefox,
                    isIE: isIE,
                    isIE8: isIE8,
                    isOpera: isOpera,
                    isOperaMini: isOperaMini,
                    isSafari: isSafari,
                    isIosWebView: isIosWebView,
                    isAndroidWebView: isAndroidWebView
                };
            }, { "228": 228, "229": 229 }], 227: [function (require, module, exports) {
                'use strict';
                var userAgent = require(229);
                var platform = require(228);
                function isMobile() {
                    return !isTablet() &&
                        (platform.isAndroid() || platform.isIpod() || platform.isIphone() ||
                            userAgent.matchUserAgent('IEMobile'));
                }
                function isTablet() {
                    return platform.isIpad() || platform.isAndroid() &&
                        !userAgent.matchUserAgent('Mobile');
                }
                function isDesktop() {
                    return !isMobile() && !isTablet();
                }
                module.exports = {
                    isMobile: isMobile,
                    isTablet: isTablet,
                    isDesktop: isDesktop
                };
            }, { "228": 228, "229": 229 }], 228: [function (require, module, exports) {
                'use strict';
                var userAgent = require(229);
                function isAndroid() {
                    return userAgent.matchUserAgent('Android');
                }
                function isIpad() {
                    return userAgent.matchUserAgent('iPad');
                }
                function isIpod() {
                    return userAgent.matchUserAgent('iPod');
                }
                function isIphone() {
                    return userAgent.matchUserAgent('iPhone') && !isIpod();
                }
                function isIos() {
                    return isIpad() || isIpod() || isIphone();
                }
                function isIos9() {
                    return userAgent.matchUserAgent('(iPhone|iPod|iPad) OS 9');
                }
                module.exports = {
                    isAndroid: isAndroid,
                    isIpad: isIpad,
                    isIpod: isIpod,
                    isIphone: isIphone,
                    isIos: isIos,
                    isIos9: isIos9
                };
            }, { "229": 229 }], 229: [function (require, module, exports) {
                'use strict';
                var nativeUserAgent = window.navigator.userAgent;
                function getNativeUserAgent() {
                    return nativeUserAgent;
                }
                function matchUserAgent(pattern) {
                    var userAgent = exports.getNativeUserAgent();
                    var matches = userAgent.match(pattern);
                    if (matches) {
                        return true;
                    }
                    return false;
                }
                exports.getNativeUserAgent = getNativeUserAgent;
                exports.matchUserAgent = matchUserAgent;
            }, {}], 230: [function (require, module, exports) {
                'use strict';
                /* globals ActiveXObject */
                var browser = require(226);
                var device = require(227);
                var platform = require(228);
                var userAgent = require(229);
                var uaString = window.navigator.userAgent;
                var mobileRe = /[Mm]obi|tablet|iOS|Android|IEMobile|Windows\sPhone/;
                function isMobile() {
                    return isMobileDevice() && window.outerWidth < 600;
                }
                function isMobileDevice() {
                    return mobileRe.test(uaString);
                }
                function detectedPostMessage() {
                    return Boolean(window.postMessage);
                }
                function isPopupSupported() {
                    if (browser.isOperaMini()) {
                        return false;
                    }
                    if (platform.isIos9() && browser.isChrome()) {
                        return true;
                    }
                    if (device.isDesktop()) {
                        return true;
                    }
                    if (device.isMobile() || device.isTablet()) {
                        if (browser.isIE()) {
                            return false;
                        }
                        if (platform.isAndroid()) {
                            if (browser.isAndroidWebView()) {
                                return false;
                            }
                            return true;
                        }
                        if (platform.isIos()) {
                            // Chrome, Safari Versions 8.0-8.1, or WebViews
                            if (browser.isChrome()) {
                                return false;
                            }
                            if (browser.isSafari() && userAgent.matchUserAgent(/OS (?:8_1|8_0|8)(?!_\d)/i)) {
                                return false;
                            }
                            if (browser.isIosWebView()) {
                                return false;
                            }
                            return true;
                        }
                    }
                    return false;
                }
                function isOverlaySupported() {
                    if (browser.isIE8()) {
                        return false;
                    }
                    try {
                        return window.self === window.top;
                    }
                    catch (e) {
                        return false;
                    }
                }
                function isBridgeIframeRequired() {
                    return browser.isIE();
                }
                function isMetroBrowser() {
                    var supported = null;
                    var errorName = '';
                    try {
                        new ActiveXObject(''); // eslint-disable-line
                    }
                    catch (e) {
                        errorName = e.name;
                    }
                    try {
                        supported = Boolean(new ActiveXObject('htmlfile'));
                    }
                    catch (e) {
                        supported = false;
                    }
                    if (errorName !== 'ReferenceError' && supported === false) {
                        supported = false;
                    }
                    else {
                        supported = true;
                    }
                    return !supported;
                }
                function isIosUIWebView() {
                    return browser.isIosWebView() && !window.indexedDB;
                }
                module.exports = {
                    isMobile: isMobile,
                    isMobileDevice: isMobileDevice,
                    detectedPostMessage: detectedPostMessage,
                    isPopupSupported: isPopupSupported,
                    isOverlaySupported: isOverlaySupported,
                    isBridgeIframeRequired: isBridgeIframeRequired,
                    isMetroBrowser: isMetroBrowser,
                    isIosUIWebView: isIosUIWebView
                };
            }, { "226": 226, "227": 227, "228": 228, "229": 229 }], 231: [function (require, module, exports) {
                'use strict';
                function setTextContent(element, content) {
                    var property = 'innerText';
                    if (document && document.body) {
                        if ('textContent' in document.body) {
                            property = 'textContent';
                        }
                    }
                    element[property] = content;
                }
                module.exports = {
                    setTextContent: setTextContent
                };
            }, {}], 232: [function (require, module, exports) {
                'use strict';
                var constants = require(222);
                var trim = typeof String.prototype.trim === 'function' ?
                    function (str) { return str.trim(); } :
                    function (str) { return str.replace(/^\s+|\s+$/, ''); };
                var b2a = typeof window.btoa === 'function' ?
                    function (str) { return window.btoa(str); } :
                    function (str) {
                        var keyStr = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
                        var output = '';
                        var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
                        var i = 0;
                        while (i < str.length) {
                            chr1 = str.charCodeAt(i++);
                            chr2 = str.charCodeAt(i++);
                            chr3 = str.charCodeAt(i++);
                            enc1 = chr1 >> 2;
                            enc2 = (chr1 & 3) << 4 | chr2 >> 4;
                            enc3 = (chr2 & 15) << 2 | chr3 >> 6;
                            enc4 = chr3 & 63;
                            if (isNaN(chr2)) {
                                enc3 = enc4 = 64;
                            }
                            else if (isNaN(chr3)) {
                                enc4 = 64;
                            }
                            output = output + keyStr.charAt(enc1) + keyStr.charAt(enc2) +
                                keyStr.charAt(enc3) + keyStr.charAt(enc4);
                        }
                        return output;
                    };
                function generateUid() {
                    var i, r;
                    var uid = '';
                    for (i = 0; i < 32; i++) {
                        r = Math.floor(Math.random() * 16);
                        uid += r.toString(16);
                    }
                    return uid;
                }
                function castToBoolean(value) {
                    return /^(true|1)$/i.test(value);
                }
                function htmlEscape(str) {
                    return str.replace(/&/g, '&amp;')
                        .replace(/</g, '&lt;')
                        .replace(/>/g, '&gt;')
                        .replace(/\"/g, '&quot;')
                        .replace(/\'/g, '&apos;');
                }
                function parseUrlParams(url) {
                    var arr, i, n, parts, index, key, value, encodedValue;
                    var startIndex = url.indexOf('?');
                    var values = {};
                    if (startIndex >= 0) {
                        url = url.substr(startIndex + 1);
                    }
                    if (url.length === 0) {
                        return null;
                    }
                    arr = url.split('&');
                    for (i = 0, n = arr.length; i < n; i++) {
                        parts = arr[i];
                        index = parts.indexOf('=');
                        key = parts.substr(0, index);
                        encodedValue = parts.substr(index + 1);
                        value = decodeURIComponent(encodedValue);
                        value = value.replace(/</g, '&lt;').replace(/>/g, '&gt;');
                        if (value === 'false') {
                            value = false;
                        }
                        if (value == null || value === 'true') {
                            value = true;
                        }
                        values[key] = value;
                    }
                    return values;
                }
                function preventDefault(event) {
                    if (event.preventDefault) {
                        event.preventDefault();
                    }
                    else {
                        event.returnValue = false;
                    }
                }
                function getOnetimeConfigurationType(configuration) {
                    var configurationType;
                    if (Boolean(configuration.merchantConfiguration.paypal.amount) && Boolean(configuration.merchantConfiguration.paypal.currency)) {
                        configurationType = constants.CONFIGURATION_TYPES.HERMES_ONETIME;
                    }
                    else {
                        configurationType = constants.CONFIGURATION_TYPES.LEGACY_ONETIME;
                    }
                    return configurationType;
                }
                function getFuturePaymentsConfigurationType(configuration) {
                    var configurationType;
                    if (Boolean(configuration.gatewayConfiguration.paypal.billingAgreementsEnabled)) {
                        configurationType = constants.CONFIGURATION_TYPES.HERMES_BILLING_AGREEMENTS;
                    }
                    else {
                        configurationType = constants.CONFIGURATION_TYPES.LEGACY_FUTURE_PAYMENTS;
                    }
                    return configurationType;
                }
                function getConfigurationType(configuration) {
                    var configurationType;
                    if (Boolean(configuration.merchantConfiguration.paypal.singleUse)) {
                        configurationType = getOnetimeConfigurationType(configuration);
                    }
                    else {
                        configurationType = getFuturePaymentsConfigurationType(configuration);
                    }
                    return configurationType;
                }
                function isHermesConfiguration(configuration) {
                    var configurationType = getConfigurationType(configuration);
                    return configurationType === constants.CONFIGURATION_TYPES.HERMES_ONETIME || configurationType === constants.CONFIGURATION_TYPES.HERMES_BILLING_AGREEMENTS;
                }
                function isOnetimeHermesConfiguration(configuration) {
                    var configurationType = getConfigurationType(configuration);
                    return configurationType === constants.CONFIGURATION_TYPES.HERMES_ONETIME;
                }
                module.exports = {
                    trim: trim,
                    btoa: b2a,
                    generateUid: generateUid,
                    castToBoolean: castToBoolean,
                    htmlEscape: htmlEscape,
                    parseUrlParams: parseUrlParams,
                    preventDefault: preventDefault,
                    isHermesConfiguration: isHermesConfiguration,
                    isOnetimeHermesConfiguration: isOnetimeHermesConfiguration,
                    getConfigurationType: getConfigurationType
                };
            }, { "222": 222 }]
    }, {}, [175])(175);
});
//# sourceMappingURL=braintree.js.map 
//# sourceMappingURL=braintree.js.map 
//# sourceMappingURL=braintree.js.map 
//# sourceMappingURL=braintree.js.map 
//# sourceMappingURL=braintree.js.map;
/*!
 * Chart.js
 * http://chartjs.org/
 * Version: 2.6.0
 *
 * Copyright 2017 Nick Downie
 * Released under the MIT license
 * https://github.com/chartjs/Chart.js/blob/master/LICENSE.md
 */
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Chart = f()}})(function(){var define,module,exports;return (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);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.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){

},{}],2:[function(require,module,exports){
/* MIT license */
var colorNames = require(6);

module.exports = {
   getRgba: getRgba,
   getHsla: getHsla,
   getRgb: getRgb,
   getHsl: getHsl,
   getHwb: getHwb,
   getAlpha: getAlpha,

   hexString: hexString,
   rgbString: rgbString,
   rgbaString: rgbaString,
   percentString: percentString,
   percentaString: percentaString,
   hslString: hslString,
   hslaString: hslaString,
   hwbString: hwbString,
   keyword: keyword
}

function getRgba(string) {
   if (!string) {
      return;
   }
   var abbr =  /^#([a-fA-F0-9]{3})$/,
       hex =  /^#([a-fA-F0-9]{6})$/,
       rgba = /^rgba?\(\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/,
       per = /^rgba?\(\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/,
       keyword = /(\w+)/;

   var rgb = [0, 0, 0],
       a = 1,
       match = string.match(abbr);
   if (match) {
      match = match[1];
      for (var i = 0; i < rgb.length; i++) {
         rgb[i] = parseInt(match[i] + match[i], 16);
      }
   }
   else if (match = string.match(hex)) {
      match = match[1];
      for (var i = 0; i < rgb.length; i++) {
         rgb[i] = parseInt(match.slice(i * 2, i * 2 + 2), 16);
      }
   }
   else if (match = string.match(rgba)) {
      for (var i = 0; i < rgb.length; i++) {
         rgb[i] = parseInt(match[i + 1]);
      }
      a = parseFloat(match[4]);
   }
   else if (match = string.match(per)) {
      for (var i = 0; i < rgb.length; i++) {
         rgb[i] = Math.round(parseFloat(match[i + 1]) * 2.55);
      }
      a = parseFloat(match[4]);
   }
   else if (match = string.match(keyword)) {
      if (match[1] == "transparent") {
         return [0, 0, 0, 0];
      }
      rgb = colorNames[match[1]];
      if (!rgb) {
         return;
      }
   }

   for (var i = 0; i < rgb.length; i++) {
      rgb[i] = scale(rgb[i], 0, 255);
   }
   if (!a && a != 0) {
      a = 1;
   }
   else {
      a = scale(a, 0, 1);
   }
   rgb[3] = a;
   return rgb;
}

function getHsla(string) {
   if (!string) {
      return;
   }
   var hsl = /^hsla?\(\s*([+-]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)/;
   var match = string.match(hsl);
   if (match) {
      var alpha = parseFloat(match[4]);
      var h = scale(parseInt(match[1]), 0, 360),
          s = scale(parseFloat(match[2]), 0, 100),
          l = scale(parseFloat(match[3]), 0, 100),
          a = scale(isNaN(alpha) ? 1 : alpha, 0, 1);
      return [h, s, l, a];
   }
}

function getHwb(string) {
   if (!string) {
      return;
   }
   var hwb = /^hwb\(\s*([+-]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)/;
   var match = string.match(hwb);
   if (match) {
    var alpha = parseFloat(match[4]);
      var h = scale(parseInt(match[1]), 0, 360),
          w = scale(parseFloat(match[2]), 0, 100),
          b = scale(parseFloat(match[3]), 0, 100),
          a = scale(isNaN(alpha) ? 1 : alpha, 0, 1);
      return [h, w, b, a];
   }
}

function getRgb(string) {
   var rgba = getRgba(string);
   return rgba && rgba.slice(0, 3);
}

function getHsl(string) {
  var hsla = getHsla(string);
  return hsla && hsla.slice(0, 3);
}

function getAlpha(string) {
   var vals = getRgba(string);
   if (vals) {
      return vals[3];
   }
   else if (vals = getHsla(string)) {
      return vals[3];
   }
   else if (vals = getHwb(string)) {
      return vals[3];
   }
}

// generators
function hexString(rgb) {
   return "#" + hexDouble(rgb[0]) + hexDouble(rgb[1])
              + hexDouble(rgb[2]);
}

function rgbString(rgba, alpha) {
   if (alpha < 1 || (rgba[3] && rgba[3] < 1)) {
      return rgbaString(rgba, alpha);
   }
   return "rgb(" + rgba[0] + ", " + rgba[1] + ", " + rgba[2] + ")";
}

function rgbaString(rgba, alpha) {
   if (alpha === undefined) {
      alpha = (rgba[3] !== undefined ? rgba[3] : 1);
   }
   return "rgba(" + rgba[0] + ", " + rgba[1] + ", " + rgba[2]
           + ", " + alpha + ")";
}

function percentString(rgba, alpha) {
   if (alpha < 1 || (rgba[3] && rgba[3] < 1)) {
      return percentaString(rgba, alpha);
   }
   var r = Math.round(rgba[0]/255 * 100),
       g = Math.round(rgba[1]/255 * 100),
       b = Math.round(rgba[2]/255 * 100);

   return "rgb(" + r + "%, " + g + "%, " + b + "%)";
}

function percentaString(rgba, alpha) {
   var r = Math.round(rgba[0]/255 * 100),
       g = Math.round(rgba[1]/255 * 100),
       b = Math.round(rgba[2]/255 * 100);
   return "rgba(" + r + "%, " + g + "%, " + b + "%, " + (alpha || rgba[3] || 1) + ")";
}

function hslString(hsla, alpha) {
   if (alpha < 1 || (hsla[3] && hsla[3] < 1)) {
      return hslaString(hsla, alpha);
   }
   return "hsl(" + hsla[0] + ", " + hsla[1] + "%, " + hsla[2] + "%)";
}

function hslaString(hsla, alpha) {
   if (alpha === undefined) {
      alpha = (hsla[3] !== undefined ? hsla[3] : 1);
   }
   return "hsla(" + hsla[0] + ", " + hsla[1] + "%, " + hsla[2] + "%, "
           + alpha + ")";
}

// hwb is a bit different than rgb(a) & hsl(a) since there is no alpha specific syntax
// (hwb have alpha optional & 1 is default value)
function hwbString(hwb, alpha) {
   if (alpha === undefined) {
      alpha = (hwb[3] !== undefined ? hwb[3] : 1);
   }
   return "hwb(" + hwb[0] + ", " + hwb[1] + "%, " + hwb[2] + "%"
           + (alpha !== undefined && alpha !== 1 ? ", " + alpha : "") + ")";
}

function keyword(rgb) {
  return reverseNames[rgb.slice(0, 3)];
}

// helpers
function scale(num, min, max) {
   return Math.min(Math.max(min, num), max);
}

function hexDouble(num) {
  var str = num.toString(16).toUpperCase();
  return (str.length < 2) ? "0" + str : str;
}


//create a list of reverse color names
var reverseNames = {};
for (var name in colorNames) {
   reverseNames[colorNames[name]] = name;
}

},{"6":6}],3:[function(require,module,exports){
/* MIT license */
var convert = require(5);
var string = require(2);

var Color = function (obj) {
	if (obj instanceof Color) {
		return obj;
	}
	if (!(this instanceof Color)) {
		return new Color(obj);
	}

	this.valid = false;
	this.values = {
		rgb: [0, 0, 0],
		hsl: [0, 0, 0],
		hsv: [0, 0, 0],
		hwb: [0, 0, 0],
		cmyk: [0, 0, 0, 0],
		alpha: 1
	};

	// parse Color() argument
	var vals;
	if (typeof obj === 'string') {
		vals = string.getRgba(obj);
		if (vals) {
			this.setValues('rgb', vals);
		} else if (vals = string.getHsla(obj)) {
			this.setValues('hsl', vals);
		} else if (vals = string.getHwb(obj)) {
			this.setValues('hwb', vals);
		}
	} else if (typeof obj === 'object') {
		vals = obj;
		if (vals.r !== undefined || vals.red !== undefined) {
			this.setValues('rgb', vals);
		} else if (vals.l !== undefined || vals.lightness !== undefined) {
			this.setValues('hsl', vals);
		} else if (vals.v !== undefined || vals.value !== undefined) {
			this.setValues('hsv', vals);
		} else if (vals.w !== undefined || vals.whiteness !== undefined) {
			this.setValues('hwb', vals);
		} else if (vals.c !== undefined || vals.cyan !== undefined) {
			this.setValues('cmyk', vals);
		}
	}
};

Color.prototype = {
	isValid: function () {
		return this.valid;
	},
	rgb: function () {
		return this.setSpace('rgb', arguments);
	},
	hsl: function () {
		return this.setSpace('hsl', arguments);
	},
	hsv: function () {
		return this.setSpace('hsv', arguments);
	},
	hwb: function () {
		return this.setSpace('hwb', arguments);
	},
	cmyk: function () {
		return this.setSpace('cmyk', arguments);
	},

	rgbArray: function () {
		return this.values.rgb;
	},
	hslArray: function () {
		return this.values.hsl;
	},
	hsvArray: function () {
		return this.values.hsv;
	},
	hwbArray: function () {
		var values = this.values;
		if (values.alpha !== 1) {
			return values.hwb.concat([values.alpha]);
		}
		return values.hwb;
	},
	cmykArray: function () {
		return this.values.cmyk;
	},
	rgbaArray: function () {
		var values = this.values;
		return values.rgb.concat([values.alpha]);
	},
	hslaArray: function () {
		var values = this.values;
		return values.hsl.concat([values.alpha]);
	},
	alpha: function (val) {
		if (val === undefined) {
			return this.values.alpha;
		}
		this.setValues('alpha', val);
		return this;
	},

	red: function (val) {
		return this.setChannel('rgb', 0, val);
	},
	green: function (val) {
		return this.setChannel('rgb', 1, val);
	},
	blue: function (val) {
		return this.setChannel('rgb', 2, val);
	},
	hue: function (val) {
		if (val) {
			val %= 360;
			val = val < 0 ? 360 + val : val;
		}
		return this.setChannel('hsl', 0, val);
	},
	saturation: function (val) {
		return this.setChannel('hsl', 1, val);
	},
	lightness: function (val) {
		return this.setChannel('hsl', 2, val);
	},
	saturationv: function (val) {
		return this.setChannel('hsv', 1, val);
	},
	whiteness: function (val) {
		return this.setChannel('hwb', 1, val);
	},
	blackness: function (val) {
		return this.setChannel('hwb', 2, val);
	},
	value: function (val) {
		return this.setChannel('hsv', 2, val);
	},
	cyan: function (val) {
		return this.setChannel('cmyk', 0, val);
	},
	magenta: function (val) {
		return this.setChannel('cmyk', 1, val);
	},
	yellow: function (val) {
		return this.setChannel('cmyk', 2, val);
	},
	black: function (val) {
		return this.setChannel('cmyk', 3, val);
	},

	hexString: function () {
		return string.hexString(this.values.rgb);
	},
	rgbString: function () {
		return string.rgbString(this.values.rgb, this.values.alpha);
	},
	rgbaString: function () {
		return string.rgbaString(this.values.rgb, this.values.alpha);
	},
	percentString: function () {
		return string.percentString(this.values.rgb, this.values.alpha);
	},
	hslString: function () {
		return string.hslString(this.values.hsl, this.values.alpha);
	},
	hslaString: function () {
		return string.hslaString(this.values.hsl, this.values.alpha);
	},
	hwbString: function () {
		return string.hwbString(this.values.hwb, this.values.alpha);
	},
	keyword: function () {
		return string.keyword(this.values.rgb, this.values.alpha);
	},

	rgbNumber: function () {
		var rgb = this.values.rgb;
		return (rgb[0] << 16) | (rgb[1] << 8) | rgb[2];
	},

	luminosity: function () {
		// http://www.w3.org/TR/WCAG20/#relativeluminancedef
		var rgb = this.values.rgb;
		var lum = [];
		for (var i = 0; i < rgb.length; i++) {
			var chan = rgb[i] / 255;
			lum[i] = (chan <= 0.03928) ? chan / 12.92 : Math.pow(((chan + 0.055) / 1.055), 2.4);
		}
		return 0.2126 * lum[0] + 0.7152 * lum[1] + 0.0722 * lum[2];
	},

	contrast: function (color2) {
		// http://www.w3.org/TR/WCAG20/#contrast-ratiodef
		var lum1 = this.luminosity();
		var lum2 = color2.luminosity();
		if (lum1 > lum2) {
			return (lum1 + 0.05) / (lum2 + 0.05);
		}
		return (lum2 + 0.05) / (lum1 + 0.05);
	},

	level: function (color2) {
		var contrastRatio = this.contrast(color2);
		if (contrastRatio >= 7.1) {
			return 'AAA';
		}

		return (contrastRatio >= 4.5) ? 'AA' : '';
	},

	dark: function () {
		// YIQ equation from http://24ways.org/2010/calculating-color-contrast
		var rgb = this.values.rgb;
		var yiq = (rgb[0] * 299 + rgb[1] * 587 + rgb[2] * 114) / 1000;
		return yiq < 128;
	},

	light: function () {
		return !this.dark();
	},

	negate: function () {
		var rgb = [];
		for (var i = 0; i < 3; i++) {
			rgb[i] = 255 - this.values.rgb[i];
		}
		this.setValues('rgb', rgb);
		return this;
	},

	lighten: function (ratio) {
		var hsl = this.values.hsl;
		hsl[2] += hsl[2] * ratio;
		this.setValues('hsl', hsl);
		return this;
	},

	darken: function (ratio) {
		var hsl = this.values.hsl;
		hsl[2] -= hsl[2] * ratio;
		this.setValues('hsl', hsl);
		return this;
	},

	saturate: function (ratio) {
		var hsl = this.values.hsl;
		hsl[1] += hsl[1] * ratio;
		this.setValues('hsl', hsl);
		return this;
	},

	desaturate: function (ratio) {
		var hsl = this.values.hsl;
		hsl[1] -= hsl[1] * ratio;
		this.setValues('hsl', hsl);
		return this;
	},

	whiten: function (ratio) {
		var hwb = this.values.hwb;
		hwb[1] += hwb[1] * ratio;
		this.setValues('hwb', hwb);
		return this;
	},

	blacken: function (ratio) {
		var hwb = this.values.hwb;
		hwb[2] += hwb[2] * ratio;
		this.setValues('hwb', hwb);
		return this;
	},

	greyscale: function () {
		var rgb = this.values.rgb;
		// http://en.wikipedia.org/wiki/Grayscale#Converting_color_to_grayscale
		var val = rgb[0] * 0.3 + rgb[1] * 0.59 + rgb[2] * 0.11;
		this.setValues('rgb', [val, val, val]);
		return this;
	},

	clearer: function (ratio) {
		var alpha = this.values.alpha;
		this.setValues('alpha', alpha - (alpha * ratio));
		return this;
	},

	opaquer: function (ratio) {
		var alpha = this.values.alpha;
		this.setValues('alpha', alpha + (alpha * ratio));
		return this;
	},

	rotate: function (degrees) {
		var hsl = this.values.hsl;
		var hue = (hsl[0] + degrees) % 360;
		hsl[0] = hue < 0 ? 360 + hue : hue;
		this.setValues('hsl', hsl);
		return this;
	},

	/**
	 * Ported from sass implementation in C
	 * https://github.com/sass/libsass/blob/0e6b4a2850092356aa3ece07c6b249f0221caced/functions.cpp#L209
	 */
	mix: function (mixinColor, weight) {
		var color1 = this;
		var color2 = mixinColor;
		var p = weight === undefined ? 0.5 : weight;

		var w = 2 * p - 1;
		var a = color1.alpha() - color2.alpha();

		var w1 = (((w * a === -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0;
		var w2 = 1 - w1;

		return this
			.rgb(
				w1 * color1.red() + w2 * color2.red(),
				w1 * color1.green() + w2 * color2.green(),
				w1 * color1.blue() + w2 * color2.blue()
			)
			.alpha(color1.alpha() * p + color2.alpha() * (1 - p));
	},

	toJSON: function () {
		return this.rgb();
	},

	clone: function () {
		// NOTE(SB): using node-clone creates a dependency to Buffer when using browserify,
		// making the final build way to big to embed in Chart.js. So let's do it manually,
		// assuming that values to clone are 1 dimension arrays containing only numbers,
		// except 'alpha' which is a number.
		var result = new Color();
		var source = this.values;
		var target = result.values;
		var value, type;

		for (var prop in source) {
			if (source.hasOwnProperty(prop)) {
				value = source[prop];
				type = ({}).toString.call(value);
				if (type === '[object Array]') {
					target[prop] = value.slice(0);
				} else if (type === '[object Number]') {
					target[prop] = value;
				} else {
					console.error('unexpected color value:', value);
				}
			}
		}

		return result;
	}
};

Color.prototype.spaces = {
	rgb: ['red', 'green', 'blue'],
	hsl: ['hue', 'saturation', 'lightness'],
	hsv: ['hue', 'saturation', 'value'],
	hwb: ['hue', 'whiteness', 'blackness'],
	cmyk: ['cyan', 'magenta', 'yellow', 'black']
};

Color.prototype.maxes = {
	rgb: [255, 255, 255],
	hsl: [360, 100, 100],
	hsv: [360, 100, 100],
	hwb: [360, 100, 100],
	cmyk: [100, 100, 100, 100]
};

Color.prototype.getValues = function (space) {
	var values = this.values;
	var vals = {};

	for (var i = 0; i < space.length; i++) {
		vals[space.charAt(i)] = values[space][i];
	}

	if (values.alpha !== 1) {
		vals.a = values.alpha;
	}

	// {r: 255, g: 255, b: 255, a: 0.4}
	return vals;
};

Color.prototype.setValues = function (space, vals) {
	var values = this.values;
	var spaces = this.spaces;
	var maxes = this.maxes;
	var alpha = 1;
	var i;

	this.valid = true;

	if (space === 'alpha') {
		alpha = vals;
	} else if (vals.length) {
		// [10, 10, 10]
		values[space] = vals.slice(0, space.length);
		alpha = vals[space.length];
	} else if (vals[space.charAt(0)] !== undefined) {
		// {r: 10, g: 10, b: 10}
		for (i = 0; i < space.length; i++) {
			values[space][i] = vals[space.charAt(i)];
		}

		alpha = vals.a;
	} else if (vals[spaces[space][0]] !== undefined) {
		// {red: 10, green: 10, blue: 10}
		var chans = spaces[space];

		for (i = 0; i < space.length; i++) {
			values[space][i] = vals[chans[i]];
		}

		alpha = vals.alpha;
	}

	values.alpha = Math.max(0, Math.min(1, (alpha === undefined ? values.alpha : alpha)));

	if (space === 'alpha') {
		return false;
	}

	var capped;

	// cap values of the space prior converting all values
	for (i = 0; i < space.length; i++) {
		capped = Math.max(0, Math.min(maxes[space][i], values[space][i]));
		values[space][i] = Math.round(capped);
	}

	// convert to all the other color spaces
	for (var sname in spaces) {
		if (sname !== space) {
			values[sname] = convert[space][sname](values[space]);
		}
	}

	return true;
};

Color.prototype.setSpace = function (space, args) {
	var vals = args[0];

	if (vals === undefined) {
		// color.rgb()
		return this.getValues(space);
	}

	// color.rgb(10, 10, 10)
	if (typeof vals === 'number') {
		vals = Array.prototype.slice.call(args);
	}

	this.setValues(space, vals);
	return this;
};

Color.prototype.setChannel = function (space, index, val) {
	var svalues = this.values[space];
	if (val === undefined) {
		// color.red()
		return svalues[index];
	} else if (val === svalues[index]) {
		// color.red(color.red())
		return this;
	}

	// color.red(100)
	svalues[index] = val;
	this.setValues(space, svalues);

	return this;
};

if (typeof window !== 'undefined') {
	window.Color = Color;
}

module.exports = Color;

},{"2":2,"5":5}],4:[function(require,module,exports){
/* MIT license */

module.exports = {
  rgb2hsl: rgb2hsl,
  rgb2hsv: rgb2hsv,
  rgb2hwb: rgb2hwb,
  rgb2cmyk: rgb2cmyk,
  rgb2keyword: rgb2keyword,
  rgb2xyz: rgb2xyz,
  rgb2lab: rgb2lab,
  rgb2lch: rgb2lch,

  hsl2rgb: hsl2rgb,
  hsl2hsv: hsl2hsv,
  hsl2hwb: hsl2hwb,
  hsl2cmyk: hsl2cmyk,
  hsl2keyword: hsl2keyword,

  hsv2rgb: hsv2rgb,
  hsv2hsl: hsv2hsl,
  hsv2hwb: hsv2hwb,
  hsv2cmyk: hsv2cmyk,
  hsv2keyword: hsv2keyword,

  hwb2rgb: hwb2rgb,
  hwb2hsl: hwb2hsl,
  hwb2hsv: hwb2hsv,
  hwb2cmyk: hwb2cmyk,
  hwb2keyword: hwb2keyword,

  cmyk2rgb: cmyk2rgb,
  cmyk2hsl: cmyk2hsl,
  cmyk2hsv: cmyk2hsv,
  cmyk2hwb: cmyk2hwb,
  cmyk2keyword: cmyk2keyword,

  keyword2rgb: keyword2rgb,
  keyword2hsl: keyword2hsl,
  keyword2hsv: keyword2hsv,
  keyword2hwb: keyword2hwb,
  keyword2cmyk: keyword2cmyk,
  keyword2lab: keyword2lab,
  keyword2xyz: keyword2xyz,

  xyz2rgb: xyz2rgb,
  xyz2lab: xyz2lab,
  xyz2lch: xyz2lch,

  lab2xyz: lab2xyz,
  lab2rgb: lab2rgb,
  lab2lch: lab2lch,

  lch2lab: lch2lab,
  lch2xyz: lch2xyz,
  lch2rgb: lch2rgb
}


function rgb2hsl(rgb) {
  var r = rgb[0]/255,
      g = rgb[1]/255,
      b = rgb[2]/255,
      min = Math.min(r, g, b),
      max = Math.max(r, g, b),
      delta = max - min,
      h, s, l;

  if (max == min)
    h = 0;
  else if (r == max)
    h = (g - b) / delta;
  else if (g == max)
    h = 2 + (b - r) / delta;
  else if (b == max)
    h = 4 + (r - g)/ delta;

  h = Math.min(h * 60, 360);

  if (h < 0)
    h += 360;

  l = (min + max) / 2;

  if (max == min)
    s = 0;
  else if (l <= 0.5)
    s = delta / (max + min);
  else
    s = delta / (2 - max - min);

  return [h, s * 100, l * 100];
}

function rgb2hsv(rgb) {
  var r = rgb[0],
      g = rgb[1],
      b = rgb[2],
      min = Math.min(r, g, b),
      max = Math.max(r, g, b),
      delta = max - min,
      h, s, v;

  if (max == 0)
    s = 0;
  else
    s = (delta/max * 1000)/10;

  if (max == min)
    h = 0;
  else if (r == max)
    h = (g - b) / delta;
  else if (g == max)
    h = 2 + (b - r) / delta;
  else if (b == max)
    h = 4 + (r - g) / delta;

  h = Math.min(h * 60, 360);

  if (h < 0)
    h += 360;

  v = ((max / 255) * 1000) / 10;

  return [h, s, v];
}

function rgb2hwb(rgb) {
  var r = rgb[0],
      g = rgb[1],
      b = rgb[2],
      h = rgb2hsl(rgb)[0],
      w = 1/255 * Math.min(r, Math.min(g, b)),
      b = 1 - 1/255 * Math.max(r, Math.max(g, b));

  return [h, w * 100, b * 100];
}

function rgb2cmyk(rgb) {
  var r = rgb[0] / 255,
      g = rgb[1] / 255,
      b = rgb[2] / 255,
      c, m, y, k;

  k = Math.min(1 - r, 1 - g, 1 - b);
  c = (1 - r - k) / (1 - k) || 0;
  m = (1 - g - k) / (1 - k) || 0;
  y = (1 - b - k) / (1 - k) || 0;
  return [c * 100, m * 100, y * 100, k * 100];
}

function rgb2keyword(rgb) {
  return reverseKeywords[JSON.stringify(rgb)];
}

function rgb2xyz(rgb) {
  var r = rgb[0] / 255,
      g = rgb[1] / 255,
      b = rgb[2] / 255;

  // assume sRGB
  r = r > 0.04045 ? Math.pow(((r + 0.055) / 1.055), 2.4) : (r / 12.92);
  g = g > 0.04045 ? Math.pow(((g + 0.055) / 1.055), 2.4) : (g / 12.92);
  b = b > 0.04045 ? Math.pow(((b + 0.055) / 1.055), 2.4) : (b / 12.92);

  var x = (r * 0.4124) + (g * 0.3576) + (b * 0.1805);
  var y = (r * 0.2126) + (g * 0.7152) + (b * 0.0722);
  var z = (r * 0.0193) + (g * 0.1192) + (b * 0.9505);

  return [x * 100, y *100, z * 100];
}

function rgb2lab(rgb) {
  var xyz = rgb2xyz(rgb),
        x = xyz[0],
        y = xyz[1],
        z = xyz[2],
        l, a, b;

  x /= 95.047;
  y /= 100;
  z /= 108.883;

  x = x > 0.008856 ? Math.pow(x, 1/3) : (7.787 * x) + (16 / 116);
  y = y > 0.008856 ? Math.pow(y, 1/3) : (7.787 * y) + (16 / 116);
  z = z > 0.008856 ? Math.pow(z, 1/3) : (7.787 * z) + (16 / 116);

  l = (116 * y) - 16;
  a = 500 * (x - y);
  b = 200 * (y - z);

  return [l, a, b];
}

function rgb2lch(args) {
  return lab2lch(rgb2lab(args));
}

function hsl2rgb(hsl) {
  var h = hsl[0] / 360,
      s = hsl[1] / 100,
      l = hsl[2] / 100,
      t1, t2, t3, rgb, val;

  if (s == 0) {
    val = l * 255;
    return [val, val, val];
  }

  if (l < 0.5)
    t2 = l * (1 + s);
  else
    t2 = l + s - l * s;
  t1 = 2 * l - t2;

  rgb = [0, 0, 0];
  for (var i = 0; i < 3; i++) {
    t3 = h + 1 / 3 * - (i - 1);
    t3 < 0 && t3++;
    t3 > 1 && t3--;

    if (6 * t3 < 1)
      val = t1 + (t2 - t1) * 6 * t3;
    else if (2 * t3 < 1)
      val = t2;
    else if (3 * t3 < 2)
      val = t1 + (t2 - t1) * (2 / 3 - t3) * 6;
    else
      val = t1;

    rgb[i] = val * 255;
  }

  return rgb;
}

function hsl2hsv(hsl) {
  var h = hsl[0],
      s = hsl[1] / 100,
      l = hsl[2] / 100,
      sv, v;

  if(l === 0) {
      // no need to do calc on black
      // also avoids divide by 0 error
      return [0, 0, 0];
  }

  l *= 2;
  s *= (l <= 1) ? l : 2 - l;
  v = (l + s) / 2;
  sv = (2 * s) / (l + s);
  return [h, sv * 100, v * 100];
}

function hsl2hwb(args) {
  return rgb2hwb(hsl2rgb(args));
}

function hsl2cmyk(args) {
  return rgb2cmyk(hsl2rgb(args));
}

function hsl2keyword(args) {
  return rgb2keyword(hsl2rgb(args));
}


function hsv2rgb(hsv) {
  var h = hsv[0] / 60,
      s = hsv[1] / 100,
      v = hsv[2] / 100,
      hi = Math.floor(h) % 6;

  var f = h - Math.floor(h),
      p = 255 * v * (1 - s),
      q = 255 * v * (1 - (s * f)),
      t = 255 * v * (1 - (s * (1 - f))),
      v = 255 * v;

  switch(hi) {
    case 0:
      return [v, t, p];
    case 1:
      return [q, v, p];
    case 2:
      return [p, v, t];
    case 3:
      return [p, q, v];
    case 4:
      return [t, p, v];
    case 5:
      return [v, p, q];
  }
}

function hsv2hsl(hsv) {
  var h = hsv[0],
      s = hsv[1] / 100,
      v = hsv[2] / 100,
      sl, l;

  l = (2 - s) * v;
  sl = s * v;
  sl /= (l <= 1) ? l : 2 - l;
  sl = sl || 0;
  l /= 2;
  return [h, sl * 100, l * 100];
}

function hsv2hwb(args) {
  return rgb2hwb(hsv2rgb(args))
}

function hsv2cmyk(args) {
  return rgb2cmyk(hsv2rgb(args));
}

function hsv2keyword(args) {
  return rgb2keyword(hsv2rgb(args));
}

// http://dev.w3.org/csswg/css-color/#hwb-to-rgb
function hwb2rgb(hwb) {
  var h = hwb[0] / 360,
      wh = hwb[1] / 100,
      bl = hwb[2] / 100,
      ratio = wh + bl,
      i, v, f, n;

  // wh + bl cant be > 1
  if (ratio > 1) {
    wh /= ratio;
    bl /= ratio;
  }

  i = Math.floor(6 * h);
  v = 1 - bl;
  f = 6 * h - i;
  if ((i & 0x01) != 0) {
    f = 1 - f;
  }
  n = wh + f * (v - wh);  // linear interpolation

  switch (i) {
    default:
    case 6:
    case 0: r = v; g = n; b = wh; break;
    case 1: r = n; g = v; b = wh; break;
    case 2: r = wh; g = v; b = n; break;
    case 3: r = wh; g = n; b = v; break;
    case 4: r = n; g = wh; b = v; break;
    case 5: r = v; g = wh; b = n; break;
  }

  return [r * 255, g * 255, b * 255];
}

function hwb2hsl(args) {
  return rgb2hsl(hwb2rgb(args));
}

function hwb2hsv(args) {
  return rgb2hsv(hwb2rgb(args));
}

function hwb2cmyk(args) {
  return rgb2cmyk(hwb2rgb(args));
}

function hwb2keyword(args) {
  return rgb2keyword(hwb2rgb(args));
}

function cmyk2rgb(cmyk) {
  var c = cmyk[0] / 100,
      m = cmyk[1] / 100,
      y = cmyk[2] / 100,
      k = cmyk[3] / 100,
      r, g, b;

  r = 1 - Math.min(1, c * (1 - k) + k);
  g = 1 - Math.min(1, m * (1 - k) + k);
  b = 1 - Math.min(1, y * (1 - k) + k);
  return [r * 255, g * 255, b * 255];
}

function cmyk2hsl(args) {
  return rgb2hsl(cmyk2rgb(args));
}

function cmyk2hsv(args) {
  return rgb2hsv(cmyk2rgb(args));
}

function cmyk2hwb(args) {
  return rgb2hwb(cmyk2rgb(args));
}

function cmyk2keyword(args) {
  return rgb2keyword(cmyk2rgb(args));
}


function xyz2rgb(xyz) {
  var x = xyz[0] / 100,
      y = xyz[1] / 100,
      z = xyz[2] / 100,
      r, g, b;

  r = (x * 3.2406) + (y * -1.5372) + (z * -0.4986);
  g = (x * -0.9689) + (y * 1.8758) + (z * 0.0415);
  b = (x * 0.0557) + (y * -0.2040) + (z * 1.0570);

  // assume sRGB
  r = r > 0.0031308 ? ((1.055 * Math.pow(r, 1.0 / 2.4)) - 0.055)
    : r = (r * 12.92);

  g = g > 0.0031308 ? ((1.055 * Math.pow(g, 1.0 / 2.4)) - 0.055)
    : g = (g * 12.92);

  b = b > 0.0031308 ? ((1.055 * Math.pow(b, 1.0 / 2.4)) - 0.055)
    : b = (b * 12.92);

  r = Math.min(Math.max(0, r), 1);
  g = Math.min(Math.max(0, g), 1);
  b = Math.min(Math.max(0, b), 1);

  return [r * 255, g * 255, b * 255];
}

function xyz2lab(xyz) {
  var x = xyz[0],
      y = xyz[1],
      z = xyz[2],
      l, a, b;

  x /= 95.047;
  y /= 100;
  z /= 108.883;

  x = x > 0.008856 ? Math.pow(x, 1/3) : (7.787 * x) + (16 / 116);
  y = y > 0.008856 ? Math.pow(y, 1/3) : (7.787 * y) + (16 / 116);
  z = z > 0.008856 ? Math.pow(z, 1/3) : (7.787 * z) + (16 / 116);

  l = (116 * y) - 16;
  a = 500 * (x - y);
  b = 200 * (y - z);

  return [l, a, b];
}

function xyz2lch(args) {
  return lab2lch(xyz2lab(args));
}

function lab2xyz(lab) {
  var l = lab[0],
      a = lab[1],
      b = lab[2],
      x, y, z, y2;

  if (l <= 8) {
    y = (l * 100) / 903.3;
    y2 = (7.787 * (y / 100)) + (16 / 116);
  } else {
    y = 100 * Math.pow((l + 16) / 116, 3);
    y2 = Math.pow(y / 100, 1/3);
  }

  x = x / 95.047 <= 0.008856 ? x = (95.047 * ((a / 500) + y2 - (16 / 116))) / 7.787 : 95.047 * Math.pow((a / 500) + y2, 3);

  z = z / 108.883 <= 0.008859 ? z = (108.883 * (y2 - (b / 200) - (16 / 116))) / 7.787 : 108.883 * Math.pow(y2 - (b / 200), 3);

  return [x, y, z];
}

function lab2lch(lab) {
  var l = lab[0],
      a = lab[1],
      b = lab[2],
      hr, h, c;

  hr = Math.atan2(b, a);
  h = hr * 360 / 2 / Math.PI;
  if (h < 0) {
    h += 360;
  }
  c = Math.sqrt(a * a + b * b);
  return [l, c, h];
}

function lab2rgb(args) {
  return xyz2rgb(lab2xyz(args));
}

function lch2lab(lch) {
  var l = lch[0],
      c = lch[1],
      h = lch[2],
      a, b, hr;

  hr = h / 360 * 2 * Math.PI;
  a = c * Math.cos(hr);
  b = c * Math.sin(hr);
  return [l, a, b];
}

function lch2xyz(args) {
  return lab2xyz(lch2lab(args));
}

function lch2rgb(args) {
  return lab2rgb(lch2lab(args));
}

function keyword2rgb(keyword) {
  return cssKeywords[keyword];
}

function keyword2hsl(args) {
  return rgb2hsl(keyword2rgb(args));
}

function keyword2hsv(args) {
  return rgb2hsv(keyword2rgb(args));
}

function keyword2hwb(args) {
  return rgb2hwb(keyword2rgb(args));
}

function keyword2cmyk(args) {
  return rgb2cmyk(keyword2rgb(args));
}

function keyword2lab(args) {
  return rgb2lab(keyword2rgb(args));
}

function keyword2xyz(args) {
  return rgb2xyz(keyword2rgb(args));
}

var cssKeywords = {
  aliceblue:  [240,248,255],
  antiquewhite: [250,235,215],
  aqua: [0,255,255],
  aquamarine: [127,255,212],
  azure:  [240,255,255],
  beige:  [245,245,220],
  bisque: [255,228,196],
  black:  [0,0,0],
  blanchedalmond: [255,235,205],
  blue: [0,0,255],
  blueviolet: [138,43,226],
  brown:  [165,42,42],
  burlywood:  [222,184,135],
  cadetblue:  [95,158,160],
  chartreuse: [127,255,0],
  chocolate:  [210,105,30],
  coral:  [255,127,80],
  cornflowerblue: [100,149,237],
  cornsilk: [255,248,220],
  crimson:  [220,20,60],
  cyan: [0,255,255],
  darkblue: [0,0,139],
  darkcyan: [0,139,139],
  darkgoldenrod:  [184,134,11],
  darkgray: [169,169,169],
  darkgreen:  [0,100,0],
  darkgrey: [169,169,169],
  darkkhaki:  [189,183,107],
  darkmagenta:  [139,0,139],
  darkolivegreen: [85,107,47],
  darkorange: [255,140,0],
  darkorchid: [153,50,204],
  darkred:  [139,0,0],
  darksalmon: [233,150,122],
  darkseagreen: [143,188,143],
  darkslateblue:  [72,61,139],
  darkslategray:  [47,79,79],
  darkslategrey:  [47,79,79],
  darkturquoise:  [0,206,209],
  darkviolet: [148,0,211],
  deeppink: [255,20,147],
  deepskyblue:  [0,191,255],
  dimgray:  [105,105,105],
  dimgrey:  [105,105,105],
  dodgerblue: [30,144,255],
  firebrick:  [178,34,34],
  floralwhite:  [255,250,240],
  forestgreen:  [34,139,34],
  fuchsia:  [255,0,255],
  gainsboro:  [220,220,220],
  ghostwhite: [248,248,255],
  gold: [255,215,0],
  goldenrod:  [218,165,32],
  gray: [128,128,128],
  green:  [0,128,0],
  greenyellow:  [173,255,47],
  grey: [128,128,128],
  honeydew: [240,255,240],
  hotpink:  [255,105,180],
  indianred:  [205,92,92],
  indigo: [75,0,130],
  ivory:  [255,255,240],
  khaki:  [240,230,140],
  lavender: [230,230,250],
  lavenderblush:  [255,240,245],
  lawngreen:  [124,252,0],
  lemonchiffon: [255,250,205],
  lightblue:  [173,216,230],
  lightcoral: [240,128,128],
  lightcyan:  [224,255,255],
  lightgoldenrodyellow: [250,250,210],
  lightgray:  [211,211,211],
  lightgreen: [144,238,144],
  lightgrey:  [211,211,211],
  lightpink:  [255,182,193],
  lightsalmon:  [255,160,122],
  lightseagreen:  [32,178,170],
  lightskyblue: [135,206,250],
  lightslategray: [119,136,153],
  lightslategrey: [119,136,153],
  lightsteelblue: [176,196,222],
  lightyellow:  [255,255,224],
  lime: [0,255,0],
  limegreen:  [50,205,50],
  linen:  [250,240,230],
  magenta:  [255,0,255],
  maroon: [128,0,0],
  mediumaquamarine: [102,205,170],
  mediumblue: [0,0,205],
  mediumorchid: [186,85,211],
  mediumpurple: [147,112,219],
  mediumseagreen: [60,179,113],
  mediumslateblue:  [123,104,238],
  mediumspringgreen:  [0,250,154],
  mediumturquoise:  [72,209,204],
  mediumvioletred:  [199,21,133],
  midnightblue: [25,25,112],
  mintcream:  [245,255,250],
  mistyrose:  [255,228,225],
  moccasin: [255,228,181],
  navajowhite:  [255,222,173],
  navy: [0,0,128],
  oldlace:  [253,245,230],
  olive:  [128,128,0],
  olivedrab:  [107,142,35],
  orange: [255,165,0],
  orangered:  [255,69,0],
  orchid: [218,112,214],
  palegoldenrod:  [238,232,170],
  palegreen:  [152,251,152],
  paleturquoise:  [175,238,238],
  palevioletred:  [219,112,147],
  papayawhip: [255,239,213],
  peachpuff:  [255,218,185],
  peru: [205,133,63],
  pink: [255,192,203],
  plum: [221,160,221],
  powderblue: [176,224,230],
  purple: [128,0,128],
  rebeccapurple: [102, 51, 153],
  red:  [255,0,0],
  rosybrown:  [188,143,143],
  royalblue:  [65,105,225],
  saddlebrown:  [139,69,19],
  salmon: [250,128,114],
  sandybrown: [244,164,96],
  seagreen: [46,139,87],
  seashell: [255,245,238],
  sienna: [160,82,45],
  silver: [192,192,192],
  skyblue:  [135,206,235],
  slateblue:  [106,90,205],
  slategray:  [112,128,144],
  slategrey:  [112,128,144],
  snow: [255,250,250],
  springgreen:  [0,255,127],
  steelblue:  [70,130,180],
  tan:  [210,180,140],
  teal: [0,128,128],
  thistle:  [216,191,216],
  tomato: [255,99,71],
  turquoise:  [64,224,208],
  violet: [238,130,238],
  wheat:  [245,222,179],
  white:  [255,255,255],
  whitesmoke: [245,245,245],
  yellow: [255,255,0],
  yellowgreen:  [154,205,50]
};

var reverseKeywords = {};
for (var key in cssKeywords) {
  reverseKeywords[JSON.stringify(cssKeywords[key])] = key;
}

},{}],5:[function(require,module,exports){
var conversions = require(4);

var convert = function() {
   return new Converter();
}

for (var func in conversions) {
  // export Raw versions
  convert[func + "Raw"] =  (function(func) {
    // accept array or plain args
    return function(arg) {
      if (typeof arg == "number")
        arg = Array.prototype.slice.call(arguments);
      return conversions[func](arg);
    }
  })(func);

  var pair = /(\w+)2(\w+)/.exec(func),
      from = pair[1],
      to = pair[2];

  // export rgb2hsl and ["rgb"]["hsl"]
  convert[from] = convert[from] || {};

  convert[from][to] = convert[func] = (function(func) { 
    return function(arg) {
      if (typeof arg == "number")
        arg = Array.prototype.slice.call(arguments);
      
      var val = conversions[func](arg);
      if (typeof val == "string" || val === undefined)
        return val; // keyword

      for (var i = 0; i < val.length; i++)
        val[i] = Math.round(val[i]);
      return val;
    }
  })(func);
}


/* Converter does lazy conversion and caching */
var Converter = function() {
   this.convs = {};
};

/* Either get the values for a space or
  set the values for a space, depending on args */
Converter.prototype.routeSpace = function(space, args) {
   var values = args[0];
   if (values === undefined) {
      // color.rgb()
      return this.getValues(space);
   }
   // color.rgb(10, 10, 10)
   if (typeof values == "number") {
      values = Array.prototype.slice.call(args);        
   }

   return this.setValues(space, values);
};
  
/* Set the values for a space, invalidating cache */
Converter.prototype.setValues = function(space, values) {
   this.space = space;
   this.convs = {};
   this.convs[space] = values;
   return this;
};

/* Get the values for a space. If there's already
  a conversion for the space, fetch it, otherwise
  compute it */
Converter.prototype.getValues = function(space) {
   var vals = this.convs[space];
   if (!vals) {
      var fspace = this.space,
          from = this.convs[fspace];
      vals = convert[fspace][space](from);

      this.convs[space] = vals;
   }
  return vals;
};

["rgb", "hsl", "hsv", "cmyk", "keyword"].forEach(function(space) {
   Converter.prototype[space] = function(vals) {
      return this.routeSpace(space, arguments);
   }
});

module.exports = convert;
},{"4":4}],6:[function(require,module,exports){
module.exports = {
	"aliceblue": [240, 248, 255],
	"antiquewhite": [250, 235, 215],
	"aqua": [0, 255, 255],
	"aquamarine": [127, 255, 212],
	"azure": [240, 255, 255],
	"beige": [245, 245, 220],
	"bisque": [255, 228, 196],
	"black": [0, 0, 0],
	"blanchedalmond": [255, 235, 205],
	"blue": [0, 0, 255],
	"blueviolet": [138, 43, 226],
	"brown": [165, 42, 42],
	"burlywood": [222, 184, 135],
	"cadetblue": [95, 158, 160],
	"chartreuse": [127, 255, 0],
	"chocolate": [210, 105, 30],
	"coral": [255, 127, 80],
	"cornflowerblue": [100, 149, 237],
	"cornsilk": [255, 248, 220],
	"crimson": [220, 20, 60],
	"cyan": [0, 255, 255],
	"darkblue": [0, 0, 139],
	"darkcyan": [0, 139, 139],
	"darkgoldenrod": [184, 134, 11],
	"darkgray": [169, 169, 169],
	"darkgreen": [0, 100, 0],
	"darkgrey": [169, 169, 169],
	"darkkhaki": [189, 183, 107],
	"darkmagenta": [139, 0, 139],
	"darkolivegreen": [85, 107, 47],
	"darkorange": [255, 140, 0],
	"darkorchid": [153, 50, 204],
	"darkred": [139, 0, 0],
	"darksalmon": [233, 150, 122],
	"darkseagreen": [143, 188, 143],
	"darkslateblue": [72, 61, 139],
	"darkslategray": [47, 79, 79],
	"darkslategrey": [47, 79, 79],
	"darkturquoise": [0, 206, 209],
	"darkviolet": [148, 0, 211],
	"deeppink": [255, 20, 147],
	"deepskyblue": [0, 191, 255],
	"dimgray": [105, 105, 105],
	"dimgrey": [105, 105, 105],
	"dodgerblue": [30, 144, 255],
	"firebrick": [178, 34, 34],
	"floralwhite": [255, 250, 240],
	"forestgreen": [34, 139, 34],
	"fuchsia": [255, 0, 255],
	"gainsboro": [220, 220, 220],
	"ghostwhite": [248, 248, 255],
	"gold": [255, 215, 0],
	"goldenrod": [218, 165, 32],
	"gray": [128, 128, 128],
	"green": [0, 128, 0],
	"greenyellow": [173, 255, 47],
	"grey": [128, 128, 128],
	"honeydew": [240, 255, 240],
	"hotpink": [255, 105, 180],
	"indianred": [205, 92, 92],
	"indigo": [75, 0, 130],
	"ivory": [255, 255, 240],
	"khaki": [240, 230, 140],
	"lavender": [230, 230, 250],
	"lavenderblush": [255, 240, 245],
	"lawngreen": [124, 252, 0],
	"lemonchiffon": [255, 250, 205],
	"lightblue": [173, 216, 230],
	"lightcoral": [240, 128, 128],
	"lightcyan": [224, 255, 255],
	"lightgoldenrodyellow": [250, 250, 210],
	"lightgray": [211, 211, 211],
	"lightgreen": [144, 238, 144],
	"lightgrey": [211, 211, 211],
	"lightpink": [255, 182, 193],
	"lightsalmon": [255, 160, 122],
	"lightseagreen": [32, 178, 170],
	"lightskyblue": [135, 206, 250],
	"lightslategray": [119, 136, 153],
	"lightslategrey": [119, 136, 153],
	"lightsteelblue": [176, 196, 222],
	"lightyellow": [255, 255, 224],
	"lime": [0, 255, 0],
	"limegreen": [50, 205, 50],
	"linen": [250, 240, 230],
	"magenta": [255, 0, 255],
	"maroon": [128, 0, 0],
	"mediumaquamarine": [102, 205, 170],
	"mediumblue": [0, 0, 205],
	"mediumorchid": [186, 85, 211],
	"mediumpurple": [147, 112, 219],
	"mediumseagreen": [60, 179, 113],
	"mediumslateblue": [123, 104, 238],
	"mediumspringgreen": [0, 250, 154],
	"mediumturquoise": [72, 209, 204],
	"mediumvioletred": [199, 21, 133],
	"midnightblue": [25, 25, 112],
	"mintcream": [245, 255, 250],
	"mistyrose": [255, 228, 225],
	"moccasin": [255, 228, 181],
	"navajowhite": [255, 222, 173],
	"navy": [0, 0, 128],
	"oldlace": [253, 245, 230],
	"olive": [128, 128, 0],
	"olivedrab": [107, 142, 35],
	"orange": [255, 165, 0],
	"orangered": [255, 69, 0],
	"orchid": [218, 112, 214],
	"palegoldenrod": [238, 232, 170],
	"palegreen": [152, 251, 152],
	"paleturquoise": [175, 238, 238],
	"palevioletred": [219, 112, 147],
	"papayawhip": [255, 239, 213],
	"peachpuff": [255, 218, 185],
	"peru": [205, 133, 63],
	"pink": [255, 192, 203],
	"plum": [221, 160, 221],
	"powderblue": [176, 224, 230],
	"purple": [128, 0, 128],
	"rebeccapurple": [102, 51, 153],
	"red": [255, 0, 0],
	"rosybrown": [188, 143, 143],
	"royalblue": [65, 105, 225],
	"saddlebrown": [139, 69, 19],
	"salmon": [250, 128, 114],
	"sandybrown": [244, 164, 96],
	"seagreen": [46, 139, 87],
	"seashell": [255, 245, 238],
	"sienna": [160, 82, 45],
	"silver": [192, 192, 192],
	"skyblue": [135, 206, 235],
	"slateblue": [106, 90, 205],
	"slategray": [112, 128, 144],
	"slategrey": [112, 128, 144],
	"snow": [255, 250, 250],
	"springgreen": [0, 255, 127],
	"steelblue": [70, 130, 180],
	"tan": [210, 180, 140],
	"teal": [0, 128, 128],
	"thistle": [216, 191, 216],
	"tomato": [255, 99, 71],
	"turquoise": [64, 224, 208],
	"violet": [238, 130, 238],
	"wheat": [245, 222, 179],
	"white": [255, 255, 255],
	"whitesmoke": [245, 245, 245],
	"yellow": [255, 255, 0],
	"yellowgreen": [154, 205, 50]
};
},{}],7:[function(require,module,exports){
/**
 * @namespace Chart
 */
var Chart = require(28)();

require(26)(Chart);
require(40)(Chart);
require(22)(Chart);
require(25)(Chart);
require(30)(Chart);
require(21)(Chart);
require(23)(Chart);
require(24)(Chart);
require(29)(Chart);
require(32)(Chart);
require(33)(Chart);
require(31)(Chart);
require(27)(Chart);
require(34)(Chart);

require(35)(Chart);
require(36)(Chart);
require(37)(Chart);
require(38)(Chart);

require(46)(Chart);
require(44)(Chart);
require(45)(Chart);
require(47)(Chart);
require(48)(Chart);
require(49)(Chart);

// Controllers must be loaded after elements
// See Chart.core.datasetController.dataElementType
require(15)(Chart);
require(16)(Chart);
require(17)(Chart);
require(18)(Chart);
require(19)(Chart);
require(20)(Chart);

require(8)(Chart);
require(9)(Chart);
require(10)(Chart);
require(11)(Chart);
require(12)(Chart);
require(13)(Chart);
require(14)(Chart);

// Loading built-it plugins
var plugins = [];

plugins.push(
    require(41)(Chart),
    require(42)(Chart),
    require(43)(Chart)
);

Chart.plugins.register(plugins);

module.exports = Chart;
if (typeof window !== 'undefined') {
	window.Chart = Chart;
}

},{"10":10,"11":11,"12":12,"13":13,"14":14,"15":15,"16":16,"17":17,"18":18,"19":19,"20":20,"21":21,"22":22,"23":23,"24":24,"25":25,"26":26,"27":27,"28":28,"29":29,"30":30,"31":31,"32":32,"33":33,"34":34,"35":35,"36":36,"37":37,"38":38,"40":40,"41":41,"42":42,"43":43,"44":44,"45":45,"46":46,"47":47,"48":48,"49":49,"8":8,"9":9}],8:[function(require,module,exports){
'use strict';

module.exports = function(Chart) {

	Chart.Bar = function(context, config) {
		config.type = 'bar';

		return new Chart(context, config);
	};

};

},{}],9:[function(require,module,exports){
'use strict';

module.exports = function(Chart) {

	Chart.Bubble = function(context, config) {
		config.type = 'bubble';
		return new Chart(context, config);
	};

};

},{}],10:[function(require,module,exports){
'use strict';

module.exports = function(Chart) {

	Chart.Doughnut = function(context, config) {
		config.type = 'doughnut';

		return new Chart(context, config);
	};

};

},{}],11:[function(require,module,exports){
'use strict';

module.exports = function(Chart) {

	Chart.Line = function(context, config) {
		config.type = 'line';

		return new Chart(context, config);
	};

};

},{}],12:[function(require,module,exports){
'use strict';

module.exports = function(Chart) {

	Chart.PolarArea = function(context, config) {
		config.type = 'polarArea';

		return new Chart(context, config);
	};

};

},{}],13:[function(require,module,exports){
'use strict';

module.exports = function(Chart) {

	Chart.Radar = function(context, config) {
		config.type = 'radar';

		return new Chart(context, config);
	};

};

},{}],14:[function(require,module,exports){
'use strict';

module.exports = function(Chart) {

	var defaultConfig = {
		hover: {
			mode: 'single'
		},

		scales: {
			xAxes: [{
				type: 'linear', // scatter should not use a category axis
				position: 'bottom',
				id: 'x-axis-1' // need an ID so datasets can reference the scale
			}],
			yAxes: [{
				type: 'linear',
				position: 'left',
				id: 'y-axis-1'
			}]
		},

		tooltips: {
			callbacks: {
				title: function() {
					// Title doesn't make sense for scatter since we format the data as a point
					return '';
				},
				label: function(tooltipItem) {
					return '(' + tooltipItem.xLabel + ', ' + tooltipItem.yLabel + ')';
				}
			}
		}
	};

	// Register the default config for this type
	Chart.defaults.scatter = defaultConfig;

	// Scatter charts use line controllers
	Chart.controllers.scatter = Chart.controllers.line;

	Chart.Scatter = function(context, config) {
		config.type = 'scatter';
		return new Chart(context, config);
	};

};

},{}],15:[function(require,module,exports){
'use strict';

module.exports = function(Chart) {

	var helpers = Chart.helpers;

	Chart.defaults.bar = {
		hover: {
			mode: 'label'
		},

		scales: {
			xAxes: [{
				type: 'category',

				// Specific to Bar Controller
				categoryPercentage: 0.8,
				barPercentage: 0.9,

				// grid line settings
				gridLines: {
					offsetGridLines: true
				}
			}],
			yAxes: [{
				type: 'linear'
			}]
		}
	};

	Chart.controllers.bar = Chart.DatasetController.extend({

		dataElementType: Chart.elements.Rectangle,

		initialize: function() {
			var me = this;
			var meta;

			Chart.DatasetController.prototype.initialize.apply(me, arguments);

			meta = me.getMeta();
			meta.stack = me.getDataset().stack;
			meta.bar = true;
		},

		update: function(reset) {
			var me = this;
			var elements = me.getMeta().data;
			var i, ilen;

			me._ruler = me.getRuler();

			for (i = 0, ilen = elements.length; i < ilen; ++i) {
				me.updateElement(elements[i], i, reset);
			}
		},

		updateElement: function(rectangle, index, reset) {
			var me = this;
			var chart = me.chart;
			var meta = me.getMeta();
			var dataset = me.getDataset();
			var custom = rectangle.custom || {};
			var rectangleOptions = chart.options.elements.rectangle;

			rectangle._xScale = me.getScaleForId(meta.xAxisID);
			rectangle._yScale = me.getScaleForId(meta.yAxisID);
			rectangle._datasetIndex = me.index;
			rectangle._index = index;

			rectangle._model = {
				datasetLabel: dataset.label,
				label: chart.data.labels[index],
				borderSkipped: custom.borderSkipped ? custom.borderSkipped : rectangleOptions.borderSkipped,
				backgroundColor: custom.backgroundColor ? custom.backgroundColor : helpers.getValueAtIndexOrDefault(dataset.backgroundColor, index, rectangleOptions.backgroundColor),
				borderColor: custom.borderColor ? custom.borderColor : helpers.getValueAtIndexOrDefault(dataset.borderColor, index, rectangleOptions.borderColor),
				borderWidth: custom.borderWidth ? custom.borderWidth : helpers.getValueAtIndexOrDefault(dataset.borderWidth, index, rectangleOptions.borderWidth)
			};

			me.updateElementGeometry(rectangle, index, reset);

			rectangle.pivot();
		},

		/**
		 * @private
		 */
		updateElementGeometry: function(rectangle, index, reset) {
			var me = this;
			var model = rectangle._model;
			var vscale = me.getValueScale();
			var base = vscale.getBasePixel();
			var horizontal = vscale.isHorizontal();
			var ruler = me._ruler || me.getRuler();
			var vpixels = me.calculateBarValuePixels(me.index, index);
			var ipixels = me.calculateBarIndexPixels(me.index, index, ruler);

			model.horizontal = horizontal;
			model.base = reset? base : vpixels.base;
			model.x = horizontal? reset? base : vpixels.head : ipixels.center;
			model.y = horizontal? ipixels.center : reset? base : vpixels.head;
			model.height = horizontal? ipixels.size : undefined;
			model.width = horizontal? undefined : ipixels.size;
		},

		/**
		 * @private
		 */
		getValueScaleId: function() {
			return this.getMeta().yAxisID;
		},

		/**
		 * @private
		 */
		getIndexScaleId: function() {
			return this.getMeta().xAxisID;
		},

		/**
		 * @private
		 */
		getValueScale: function() {
			return this.getScaleForId(this.getValueScaleId());
		},

		/**
		 * @private
		 */
		getIndexScale: function() {
			return this.getScaleForId(this.getIndexScaleId());
		},

		/**
		 * Returns the effective number of stacks based on groups and bar visibility.
		 * @private
		 */
		getStackCount: function(last) {
			var me = this;
			var chart = me.chart;
			var scale = me.getIndexScale();
			var stacked = scale.options.stacked;
			var ilen = last === undefined? chart.data.datasets.length : last + 1;
			var stacks = [];
			var i, meta;

			for (i = 0; i < ilen; ++i) {
				meta = chart.getDatasetMeta(i);
				if (meta.bar && chart.isDatasetVisible(i) &&
					(stacked === false ||
					(stacked === true && stacks.indexOf(meta.stack) === -1) ||
					(stacked === undefined && (meta.stack === undefined || stacks.indexOf(meta.stack) === -1)))) {
					stacks.push(meta.stack);
				}
			}

			return stacks.length;
		},

		/**
		 * Returns the stack index for the given dataset based on groups and bar visibility.
		 * @private
		 */
		getStackIndex: function(datasetIndex) {
			return this.getStackCount(datasetIndex) - 1;
		},

		/**
		 * @private
		 */
		getRuler: function() {
			var me = this;
			var scale = me.getIndexScale();
			var options = scale.options;
			var stackCount = me.getStackCount();
			var fullSize = scale.isHorizontal()? scale.width : scale.height;
			var tickSize = fullSize / scale.ticks.length;
			var categorySize = tickSize * options.categoryPercentage;
			var fullBarSize = categorySize / stackCount;
			var barSize = fullBarSize * options.barPercentage;

			barSize = Math.min(
				helpers.getValueOrDefault(options.barThickness, barSize),
				helpers.getValueOrDefault(options.maxBarThickness, Infinity));

			return {
				stackCount: stackCount,
				tickSize: tickSize,
				categorySize: categorySize,
				categorySpacing: tickSize - categorySize,
				fullBarSize: fullBarSize,
				barSize: barSize,
				barSpacing: fullBarSize - barSize,
				scale: scale
			};
		},

		/**
		 * Note: pixel values are not clamped to the scale area.
		 * @private
		 */
		calculateBarValuePixels: function(datasetIndex, index) {
			var me = this;
			var chart = me.chart;
			var meta = me.getMeta();
			var scale = me.getValueScale();
			var datasets = chart.data.datasets;
			var value = Number(datasets[datasetIndex].data[index]);
			var stacked = scale.options.stacked;
			var stack = meta.stack;
			var start = 0;
			var i, imeta, ivalue, base, head, size;

			if (stacked || (stacked === undefined && stack !== undefined)) {
				for (i = 0; i < datasetIndex; ++i) {
					imeta = chart.getDatasetMeta(i);

					if (imeta.bar &&
						imeta.stack === stack &&
						imeta.controller.getValueScaleId() === scale.id &&
						chart.isDatasetVisible(i)) {

						ivalue = Number(datasets[i].data[index]);
						if ((value < 0 && ivalue < 0) || (value >= 0 && ivalue > 0)) {
							start += ivalue;
						}
					}
				}
			}

			base = scale.getPixelForValue(start);
			head = scale.getPixelForValue(start + value);
			size = (head - base) / 2;

			return {
				size: size,
				base: base,
				head: head,
				center: head + size / 2
			};
		},

		/**
		 * @private
		 */
		calculateBarIndexPixels: function(datasetIndex, index, ruler) {
			var me = this;
			var scale = ruler.scale;
			var isCombo = me.chart.isCombo;
			var stackIndex = me.getStackIndex(datasetIndex);
			var base = scale.getPixelForValue(null, index, datasetIndex, isCombo);
			var size = ruler.barSize;

			base -= isCombo? ruler.tickSize / 2 : 0;
			base += ruler.fullBarSize * stackIndex;
			base += ruler.categorySpacing / 2;
			base += ruler.barSpacing / 2;

			return {
				size: size,
				base: base,
				head: base + size,
				center: base + size / 2
			};
		},

		draw: function() {
			var me = this;
			var chart = me.chart;
			var elements = me.getMeta().data;
			var dataset = me.getDataset();
			var ilen = elements.length;
			var i = 0;
			var d;

			helpers.canvas.clipArea(chart.ctx, chart.chartArea);

			for (; i<ilen; ++i) {
				d = dataset.data[i];
				if (d !== null && d !== undefined && !isNaN(d)) {
					elements[i].draw();
				}
			}

			helpers.canvas.unclipArea(chart.ctx);
		},

		setHoverStyle: function(rectangle) {
			var dataset = this.chart.data.datasets[rectangle._datasetIndex];
			var index = rectangle._index;
			var custom = rectangle.custom || {};
			var model = rectangle._model;

			model.backgroundColor = custom.hoverBackgroundColor ? custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(dataset.hoverBackgroundColor, index, helpers.getHoverColor(model.backgroundColor));
			model.borderColor = custom.hoverBorderColor ? custom.hoverBorderColor : helpers.getValueAtIndexOrDefault(dataset.hoverBorderColor, index, helpers.getHoverColor(model.borderColor));
			model.borderWidth = custom.hoverBorderWidth ? custom.hoverBorderWidth : helpers.getValueAtIndexOrDefault(dataset.hoverBorderWidth, index, model.borderWidth);
		},

		removeHoverStyle: function(rectangle) {
			var dataset = this.chart.data.datasets[rectangle._datasetIndex];
			var index = rectangle._index;
			var custom = rectangle.custom || {};
			var model = rectangle._model;
			var rectangleElementOptions = this.chart.options.elements.rectangle;

			model.backgroundColor = custom.backgroundColor ? custom.backgroundColor : helpers.getValueAtIndexOrDefault(dataset.backgroundColor, index, rectangleElementOptions.backgroundColor);
			model.borderColor = custom.borderColor ? custom.borderColor : helpers.getValueAtIndexOrDefault(dataset.borderColor, index, rectangleElementOptions.borderColor);
			model.borderWidth = custom.borderWidth ? custom.borderWidth : helpers.getValueAtIndexOrDefault(dataset.borderWidth, index, rectangleElementOptions.borderWidth);
		}
	});


	// including horizontalBar in the bar file, instead of a file of its own
	// it extends bar (like pie extends doughnut)
	Chart.defaults.horizontalBar = {
		hover: {
			mode: 'label'
		},

		scales: {
			xAxes: [{
				type: 'linear',
				position: 'bottom'
			}],
			yAxes: [{
				position: 'left',
				type: 'category',

				// Specific to Horizontal Bar Controller
				categoryPercentage: 0.8,
				barPercentage: 0.9,

				// grid line settings
				gridLines: {
					offsetGridLines: true
				}
			}]
		},
		elements: {
			rectangle: {
				borderSkipped: 'left'
			}
		},
		tooltips: {
			callbacks: {
				title: function(tooltipItems, data) {
					// Pick first xLabel for now
					var title = '';

					if (tooltipItems.length > 0) {
						if (tooltipItems[0].yLabel) {
							title = tooltipItems[0].yLabel;
						} else if (data.labels.length > 0 && tooltipItems[0].index < data.labels.length) {
							title = data.labels[tooltipItems[0].index];
						}
					}

					return title;
				},
				label: function(tooltipItem, data) {
					var datasetLabel = data.datasets[tooltipItem.datasetIndex].label || '';
					return datasetLabel + ': ' + tooltipItem.xLabel;
				}
			}
		}
	};

	Chart.controllers.horizontalBar = Chart.controllers.bar.extend({
		/**
		 * @private
		 */
		getValueScaleId: function() {
			return this.getMeta().xAxisID;
		},

		/**
		 * @private
		 */
		getIndexScaleId: function() {
			return this.getMeta().yAxisID;
		}
	});
};

},{}],16:[function(require,module,exports){
'use strict';

module.exports = function(Chart) {

	var helpers = Chart.helpers;

	Chart.defaults.bubble = {
		hover: {
			mode: 'single'
		},

		scales: {
			xAxes: [{
				type: 'linear', // bubble should probably use a linear scale by default
				position: 'bottom',
				id: 'x-axis-0' // need an ID so datasets can reference the scale
			}],
			yAxes: [{
				type: 'linear',
				position: 'left',
				id: 'y-axis-0'
			}]
		},

		tooltips: {
			callbacks: {
				title: function() {
					// Title doesn't make sense for scatter since we format the data as a point
					return '';
				},
				label: function(tooltipItem, data) {
					var datasetLabel = data.datasets[tooltipItem.datasetIndex].label || '';
					var dataPoint = data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index];
					return datasetLabel + ': (' + tooltipItem.xLabel + ', ' + tooltipItem.yLabel + ', ' + dataPoint.r + ')';
				}
			}
		}
	};

	Chart.controllers.bubble = Chart.DatasetController.extend({

		dataElementType: Chart.elements.Point,

		update: function(reset) {
			var me = this;
			var meta = me.getMeta();
			var points = meta.data;

			// Update Points
			helpers.each(points, function(point, index) {
				me.updateElement(point, index, reset);
			});
		},

		updateElement: function(point, index, reset) {
			var me = this;
			var meta = me.getMeta();
			var xScale = me.getScaleForId(meta.xAxisID);
			var yScale = me.getScaleForId(meta.yAxisID);

			var custom = point.custom || {};
			var dataset = me.getDataset();
			var data = dataset.data[index];
			var pointElementOptions = me.chart.options.elements.point;
			var dsIndex = me.index;

			helpers.extend(point, {
				// Utility
				_xScale: xScale,
				_yScale: yScale,
				_datasetIndex: dsIndex,
				_index: index,

				// Desired view properties
				_model: {
					x: reset ? xScale.getPixelForDecimal(0.5) : xScale.getPixelForValue(typeof data === 'object' ? data : NaN, index, dsIndex, me.chart.isCombo),
					y: reset ? yScale.getBasePixel() : yScale.getPixelForValue(data, index, dsIndex),
					// Appearance
					radius: reset ? 0 : custom.radius ? custom.radius : me.getRadius(data),

					// Tooltip
					hitRadius: custom.hitRadius ? custom.hitRadius : helpers.getValueAtIndexOrDefault(dataset.hitRadius, index, pointElementOptions.hitRadius)
				}
			});

			// Trick to reset the styles of the point
			Chart.DatasetController.prototype.removeHoverStyle.call(me, point, pointElementOptions);

			var model = point._model;
			model.skip = custom.skip ? custom.skip : (isNaN(model.x) || isNaN(model.y));

			point.pivot();
		},

		getRadius: function(value) {
			return value.r || this.chart.options.elements.point.radius;
		},

		setHoverStyle: function(point) {
			var me = this;
			Chart.DatasetController.prototype.setHoverStyle.call(me, point);

			// Radius
			var dataset = me.chart.data.datasets[point._datasetIndex];
			var index = point._index;
			var custom = point.custom || {};
			var model = point._model;
			model.radius = custom.hoverRadius ? custom.hoverRadius : (helpers.getValueAtIndexOrDefault(dataset.hoverRadius, index, me.chart.options.elements.point.hoverRadius)) + me.getRadius(dataset.data[index]);
		},

		removeHoverStyle: function(point) {
			var me = this;
			Chart.DatasetController.prototype.removeHoverStyle.call(me, point, me.chart.options.elements.point);

			var dataVal = me.chart.data.datasets[point._datasetIndex].data[point._index];
			var custom = point.custom || {};
			var model = point._model;

			model.radius = custom.radius ? custom.radius : me.getRadius(dataVal);
		}
	});
};

},{}],17:[function(require,module,exports){
'use strict';

module.exports = function(Chart) {

	var helpers = Chart.helpers,
		defaults = Chart.defaults;

	defaults.doughnut = {
		animation: {
			// Boolean - Whether we animate the rotation of the Doughnut
			animateRotate: true,
			// Boolean - Whether we animate scaling the Doughnut from the centre
			animateScale: false
		},
		aspectRatio: 1,
		hover: {
			mode: 'single'
		},
		legendCallback: function(chart) {
			var text = [];
			text.push('<ul class="' + chart.id + '-legend">');

			var data = chart.data;
			var datasets = data.datasets;
			var labels = data.labels;

			if (datasets.length) {
				for (var i = 0; i < datasets[0].data.length; ++i) {
					text.push('<li><span style="background-color:' + datasets[0].backgroundColor[i] + '"></span>');
					if (labels[i]) {
						text.push(labels[i]);
					}
					text.push('</li>');
				}
			}

			text.push('</ul>');
			return text.join('');
		},
		legend: {
			labels: {
				generateLabels: function(chart) {
					var data = chart.data;
					if (data.labels.length && data.datasets.length) {
						return data.labels.map(function(label, i) {
							var meta = chart.getDatasetMeta(0);
							var ds = data.datasets[0];
							var arc = meta.data[i];
							var custom = arc && arc.custom || {};
							var getValueAtIndexOrDefault = helpers.getValueAtIndexOrDefault;
							var arcOpts = chart.options.elements.arc;
							var fill = custom.backgroundColor ? custom.backgroundColor : getValueAtIndexOrDefault(ds.backgroundColor, i, arcOpts.backgroundColor);
							var stroke = custom.borderColor ? custom.borderColor : getValueAtIndexOrDefault(ds.borderColor, i, arcOpts.borderColor);
							var bw = custom.borderWidth ? custom.borderWidth : getValueAtIndexOrDefault(ds.borderWidth, i, arcOpts.borderWidth);

							return {
								text: label,
								fillStyle: fill,
								strokeStyle: stroke,
								lineWidth: bw,
								hidden: isNaN(ds.data[i]) || meta.data[i].hidden,

								// Extra data used for toggling the correct item
								index: i
							};
						});
					}
					return [];
				}
			},

			onClick: function(e, legendItem) {
				var index = legendItem.index;
				var chart = this.chart;
				var i, ilen, meta;

				for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) {
					meta = chart.getDatasetMeta(i);
					// toggle visibility of index if exists
					if (meta.data[index]) {
						meta.data[index].hidden = !meta.data[index].hidden;
					}
				}

				chart.update();
			}
		},

		// The percentage of the chart that we cut out of the middle.
		cutoutPercentage: 50,

		// The rotation of the chart, where the first data arc begins.
		rotation: Math.PI * -0.5,

		// The total circumference of the chart.
		circumference: Math.PI * 2.0,

		// Need to override these to give a nice default
		tooltips: {
			callbacks: {
				title: function() {
					return '';
				},
				label: function(tooltipItem, data) {
					var dataLabel = data.labels[tooltipItem.index];
					var value = ': ' + data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index];

					if (helpers.isArray(dataLabel)) {
						// show value on first line of multiline label
						// need to clone because we are changing the value
						dataLabel = dataLabel.slice();
						dataLabel[0] += value;
					} else {
						dataLabel += value;
					}

					return dataLabel;
				}
			}
		}
	};

	defaults.pie = helpers.clone(defaults.doughnut);
	helpers.extend(defaults.pie, {
		cutoutPercentage: 0
	});


	Chart.controllers.doughnut = Chart.controllers.pie = Chart.DatasetController.extend({

		dataElementType: Chart.elements.Arc,

		linkScales: helpers.noop,

		// Get index of the dataset in relation to the visible datasets. This allows determining the inner and outer radius correctly
		getRingIndex: function(datasetIndex) {
			var ringIndex = 0;

			for (var j = 0; j < datasetIndex; ++j) {
				if (this.chart.isDatasetVisible(j)) {
					++ringIndex;
				}
			}

			return ringIndex;
		},

		update: function(reset) {
			var me = this;
			var chart = me.chart,
				chartArea = chart.chartArea,
				opts = chart.options,
				arcOpts = opts.elements.arc,
				availableWidth = chartArea.right - chartArea.left - arcOpts.borderWidth,
				availableHeight = chartArea.bottom - chartArea.top - arcOpts.borderWidth,
				minSize = Math.min(availableWidth, availableHeight),
				offset = {
					x: 0,
					y: 0
				},
				meta = me.getMeta(),
				cutoutPercentage = opts.cutoutPercentage,
				circumference = opts.circumference;

			// If the chart's circumference isn't a full circle, calculate minSize as a ratio of the width/height of the arc
			if (circumference < Math.PI * 2.0) {
				var startAngle = opts.rotation % (Math.PI * 2.0);
				startAngle += Math.PI * 2.0 * (startAngle >= Math.PI ? -1 : startAngle < -Math.PI ? 1 : 0);
				var endAngle = startAngle + circumference;
				var start = {x: Math.cos(startAngle), y: Math.sin(startAngle)};
				var end = {x: Math.cos(endAngle), y: Math.sin(endAngle)};
				var contains0 = (startAngle <= 0 && 0 <= endAngle) || (startAngle <= Math.PI * 2.0 && Math.PI * 2.0 <= endAngle);
				var contains90 = (startAngle <= Math.PI * 0.5 && Math.PI * 0.5 <= endAngle) || (startAngle <= Math.PI * 2.5 && Math.PI * 2.5 <= endAngle);
				var contains180 = (startAngle <= -Math.PI && -Math.PI <= endAngle) || (startAngle <= Math.PI && Math.PI <= endAngle);
				var contains270 = (startAngle <= -Math.PI * 0.5 && -Math.PI * 0.5 <= endAngle) || (startAngle <= Math.PI * 1.5 && Math.PI * 1.5 <= endAngle);
				var cutout = cutoutPercentage / 100.0;
				var min = {x: contains180 ? -1 : Math.min(start.x * (start.x < 0 ? 1 : cutout), end.x * (end.x < 0 ? 1 : cutout)), y: contains270 ? -1 : Math.min(start.y * (start.y < 0 ? 1 : cutout), end.y * (end.y < 0 ? 1 : cutout))};
				var max = {x: contains0 ? 1 : Math.max(start.x * (start.x > 0 ? 1 : cutout), end.x * (end.x > 0 ? 1 : cutout)), y: contains90 ? 1 : Math.max(start.y * (start.y > 0 ? 1 : cutout), end.y * (end.y > 0 ? 1 : cutout))};
				var size = {width: (max.x - min.x) * 0.5, height: (max.y - min.y) * 0.5};
				minSize = Math.min(availableWidth / size.width, availableHeight / size.height);
				offset = {x: (max.x + min.x) * -0.5, y: (max.y + min.y) * -0.5};
			}

			chart.borderWidth = me.getMaxBorderWidth(meta.data);
			chart.outerRadius = Math.max((minSize - chart.borderWidth) / 2, 0);
			chart.innerRadius = Math.max(cutoutPercentage ? (chart.outerRadius / 100) * (cutoutPercentage) : 0, 0);
			chart.radiusLength = (chart.outerRadius - chart.innerRadius) / chart.getVisibleDatasetCount();
			chart.offsetX = offset.x * chart.outerRadius;
			chart.offsetY = offset.y * chart.outerRadius;

			meta.total = me.calculateTotal();

			me.outerRadius = chart.outerRadius - (chart.radiusLength * me.getRingIndex(me.index));
			me.innerRadius = Math.max(me.outerRadius - chart.radiusLength, 0);

			helpers.each(meta.data, function(arc, index) {
				me.updateElement(arc, index, reset);
			});
		},

		updateElement: function(arc, index, reset) {
			var me = this;
			var chart = me.chart,
				chartArea = chart.chartArea,
				opts = chart.options,
				animationOpts = opts.animation,
				centerX = (chartArea.left + chartArea.right) / 2,
				centerY = (chartArea.top + chartArea.bottom) / 2,
				startAngle = opts.rotation, // non reset case handled later
				endAngle = opts.rotation, // non reset case handled later
				dataset = me.getDataset(),
				circumference = reset && animationOpts.animateRotate ? 0 : arc.hidden ? 0 : me.calculateCircumference(dataset.data[index]) * (opts.circumference / (2.0 * Math.PI)),
				innerRadius = reset && animationOpts.animateScale ? 0 : me.innerRadius,
				outerRadius = reset && animationOpts.animateScale ? 0 : me.outerRadius,
				valueAtIndexOrDefault = helpers.getValueAtIndexOrDefault;

			helpers.extend(arc, {
				// Utility
				_datasetIndex: me.index,
				_index: index,

				// Desired view properties
				_model: {
					x: centerX + chart.offsetX,
					y: centerY + chart.offsetY,
					startAngle: startAngle,
					endAngle: endAngle,
					circumference: circumference,
					outerRadius: outerRadius,
					innerRadius: innerRadius,
					label: valueAtIndexOrDefault(dataset.label, index, chart.data.labels[index])
				}
			});

			var model = arc._model;
			// Resets the visual styles
			this.removeHoverStyle(arc);

			// Set correct angles if not resetting
			if (!reset || !animationOpts.animateRotate) {
				if (index === 0) {
					model.startAngle = opts.rotation;
				} else {
					model.startAngle = me.getMeta().data[index - 1]._model.endAngle;
				}

				model.endAngle = model.startAngle + model.circumference;
			}

			arc.pivot();
		},

		removeHoverStyle: function(arc) {
			Chart.DatasetController.prototype.removeHoverStyle.call(this, arc, this.chart.options.elements.arc);
		},

		calculateTotal: function() {
			var dataset = this.getDataset();
			var meta = this.getMeta();
			var total = 0;
			var value;

			helpers.each(meta.data, function(element, index) {
				value = dataset.data[index];
				if (!isNaN(value) && !element.hidden) {
					total += Math.abs(value);
				}
			});

			/* if (total === 0) {
				total = NaN;
			}*/

			return total;
		},

		calculateCircumference: function(value) {
			var total = this.getMeta().total;
			if (total > 0 && !isNaN(value)) {
				return (Math.PI * 2.0) * (value / total);
			}
			return 0;
		},

		// gets the max border or hover width to properly scale pie charts
		getMaxBorderWidth: function(elements) {
			var max = 0,
				index = this.index,
				length = elements.length,
				borderWidth,
				hoverWidth;

			for (var i = 0; i < length; i++) {
				borderWidth = elements[i]._model ? elements[i]._model.borderWidth : 0;
				hoverWidth = elements[i]._chart ? elements[i]._chart.config.data.datasets[index].hoverBorderWidth : 0;

				max = borderWidth > max ? borderWidth : max;
				max = hoverWidth > max ? hoverWidth : max;
			}
			return max;
		}
	});
};

},{}],18:[function(require,module,exports){
'use strict';

module.exports = function(Chart) {

	var helpers = Chart.helpers;

	Chart.defaults.line = {
		showLines: true,
		spanGaps: false,

		hover: {
			mode: 'label'
		},

		scales: {
			xAxes: [{
				type: 'category',
				id: 'x-axis-0'
			}],
			yAxes: [{
				type: 'linear',
				id: 'y-axis-0'
			}]
		}
	};

	function lineEnabled(dataset, options) {
		return helpers.getValueOrDefault(dataset.showLine, options.showLines);
	}

	Chart.controllers.line = Chart.DatasetController.extend({

		datasetElementType: Chart.elements.Line,

		dataElementType: Chart.elements.Point,

		update: function(reset) {
			var me = this;
			var meta = me.getMeta();
			var line = meta.dataset;
			var points = meta.data || [];
			var options = me.chart.options;
			var lineElementOptions = options.elements.line;
			var scale = me.getScaleForId(meta.yAxisID);
			var i, ilen, custom;
			var dataset = me.getDataset();
			var showLine = lineEnabled(dataset, options);

			// Update Line
			if (showLine) {
				custom = line.custom || {};

				// Compatibility: If the properties are defined with only the old name, use those values
				if ((dataset.tension !== undefined) && (dataset.lineTension === undefined)) {
					dataset.lineTension = dataset.tension;
				}

				// Utility
				line._scale = scale;
				line._datasetIndex = me.index;
				// Data
				line._children = points;
				// Model
				line._model = {
					// Appearance
					// The default behavior of lines is to break at null values, according
					// to https://github.com/chartjs/Chart.js/issues/2435#issuecomment-216718158
					// This option gives lines the ability to span gaps
					spanGaps: dataset.spanGaps ? dataset.spanGaps : options.spanGaps,
					tension: custom.tension ? custom.tension : helpers.getValueOrDefault(dataset.lineTension, lineElementOptions.tension),
					backgroundColor: custom.backgroundColor ? custom.backgroundColor : (dataset.backgroundColor || lineElementOptions.backgroundColor),
					borderWidth: custom.borderWidth ? custom.borderWidth : (dataset.borderWidth || lineElementOptions.borderWidth),
					borderColor: custom.borderColor ? custom.borderColor : (dataset.borderColor || lineElementOptions.borderColor),
					borderCapStyle: custom.borderCapStyle ? custom.borderCapStyle : (dataset.borderCapStyle || lineElementOptions.borderCapStyle),
					borderDash: custom.borderDash ? custom.borderDash : (dataset.borderDash || lineElementOptions.borderDash),
					borderDashOffset: custom.borderDashOffset ? custom.borderDashOffset : (dataset.borderDashOffset || lineElementOptions.borderDashOffset),
					borderJoinStyle: custom.borderJoinStyle ? custom.borderJoinStyle : (dataset.borderJoinStyle || lineElementOptions.borderJoinStyle),
					fill: custom.fill ? custom.fill : (dataset.fill !== undefined ? dataset.fill : lineElementOptions.fill),
					steppedLine: custom.steppedLine ? custom.steppedLine : helpers.getValueOrDefault(dataset.steppedLine, lineElementOptions.stepped),
					cubicInterpolationMode: custom.cubicInterpolationMode ? custom.cubicInterpolationMode : helpers.getValueOrDefault(dataset.cubicInterpolationMode, lineElementOptions.cubicInterpolationMode),
				};

				line.pivot();
			}

			// Update Points
			for (i=0, ilen=points.length; i<ilen; ++i) {
				me.updateElement(points[i], i, reset);
			}

			if (showLine && line._model.tension !== 0) {
				me.updateBezierControlPoints();
			}

			// Now pivot the point for animation
			for (i=0, ilen=points.length; i<ilen; ++i) {
				points[i].pivot();
			}
		},

		getPointBackgroundColor: function(point, index) {
			var backgroundColor = this.chart.options.elements.point.backgroundColor;
			var dataset = this.getDataset();
			var custom = point.custom || {};

			if (custom.backgroundColor) {
				backgroundColor = custom.backgroundColor;
			} else if (dataset.pointBackgroundColor) {
				backgroundColor = helpers.getValueAtIndexOrDefault(dataset.pointBackgroundColor, index, backgroundColor);
			} else if (dataset.backgroundColor) {
				backgroundColor = dataset.backgroundColor;
			}

			return backgroundColor;
		},

		getPointBorderColor: function(point, index) {
			var borderColor = this.chart.options.elements.point.borderColor;
			var dataset = this.getDataset();
			var custom = point.custom || {};

			if (custom.borderColor) {
				borderColor = custom.borderColor;
			} else if (dataset.pointBorderColor) {
				borderColor = helpers.getValueAtIndexOrDefault(dataset.pointBorderColor, index, borderColor);
			} else if (dataset.borderColor) {
				borderColor = dataset.borderColor;
			}

			return borderColor;
		},

		getPointBorderWidth: function(point, index) {
			var borderWidth = this.chart.options.elements.point.borderWidth;
			var dataset = this.getDataset();
			var custom = point.custom || {};

			if (!isNaN(custom.borderWidth)) {
				borderWidth = custom.borderWidth;
			} else if (!isNaN(dataset.pointBorderWidth)) {
				borderWidth = helpers.getValueAtIndexOrDefault(dataset.pointBorderWidth, index, borderWidth);
			} else if (!isNaN(dataset.borderWidth)) {
				borderWidth = dataset.borderWidth;
			}

			return borderWidth;
		},

		updateElement: function(point, index, reset) {
			var me = this;
			var meta = me.getMeta();
			var custom = point.custom || {};
			var dataset = me.getDataset();
			var datasetIndex = me.index;
			var value = dataset.data[index];
			var yScale = me.getScaleForId(meta.yAxisID);
			var xScale = me.getScaleForId(meta.xAxisID);
			var pointOptions = me.chart.options.elements.point;
			var x, y;
			var labels = me.chart.data.labels || [];
			var includeOffset = (labels.length === 1 || dataset.data.length === 1) || me.chart.isCombo;

			// Compatibility: If the properties are defined with only the old name, use those values
			if ((dataset.radius !== undefined) && (dataset.pointRadius === undefined)) {
				dataset.pointRadius = dataset.radius;
			}
			if ((dataset.hitRadius !== undefined) && (dataset.pointHitRadius === undefined)) {
				dataset.pointHitRadius = dataset.hitRadius;
			}

			x = xScale.getPixelForValue(typeof value === 'object' ? value : NaN, index, datasetIndex, includeOffset);
			y = reset ? yScale.getBasePixel() : me.calculatePointY(value, index, datasetIndex);

			// Utility
			point._xScale = xScale;
			point._yScale = yScale;
			point._datasetIndex = datasetIndex;
			point._index = index;

			// Desired view properties
			point._model = {
				x: x,
				y: y,
				skip: custom.skip || isNaN(x) || isNaN(y),
				// Appearance
				radius: custom.radius || helpers.getValueAtIndexOrDefault(dataset.pointRadius, index, pointOptions.radius),
				pointStyle: custom.pointStyle || helpers.getValueAtIndexOrDefault(dataset.pointStyle, index, pointOptions.pointStyle),
				backgroundColor: me.getPointBackgroundColor(point, index),
				borderColor: me.getPointBorderColor(point, index),
				borderWidth: me.getPointBorderWidth(point, index),
				tension: meta.dataset._model ? meta.dataset._model.tension : 0,
				steppedLine: meta.dataset._model ? meta.dataset._model.steppedLine : false,
				// Tooltip
				hitRadius: custom.hitRadius || helpers.getValueAtIndexOrDefault(dataset.pointHitRadius, index, pointOptions.hitRadius)
			};
		},

		calculatePointY: function(value, index, datasetIndex) {
			var me = this;
			var chart = me.chart;
			var meta = me.getMeta();
			var yScale = me.getScaleForId(meta.yAxisID);
			var sumPos = 0;
			var sumNeg = 0;
			var i, ds, dsMeta;

			if (yScale.options.stacked) {
				for (i = 0; i < datasetIndex; i++) {
					ds = chart.data.datasets[i];
					dsMeta = chart.getDatasetMeta(i);
					if (dsMeta.type === 'line' && dsMeta.yAxisID === yScale.id && chart.isDatasetVisible(i)) {
						var stackedRightValue = Number(yScale.getRightValue(ds.data[index]));
						if (stackedRightValue < 0) {
							sumNeg += stackedRightValue || 0;
						} else {
							sumPos += stackedRightValue || 0;
						}
					}
				}

				var rightValue = Number(yScale.getRightValue(value));
				if (rightValue < 0) {
					return yScale.getPixelForValue(sumNeg + rightValue);
				}
				return yScale.getPixelForValue(sumPos + rightValue);
			}

			return yScale.getPixelForValue(value);
		},

		updateBezierControlPoints: function() {
			var me = this;
			var meta = me.getMeta();
			var area = me.chart.chartArea;
			var points = (meta.data || []);
			var i, ilen, point, model, controlPoints;

			// Only consider points that are drawn in case the spanGaps option is used
			if (meta.dataset._model.spanGaps) {
				points = points.filter(function(pt) {
					return !pt._model.skip;
				});
			}

			function capControlPoint(pt, min, max) {
				return Math.max(Math.min(pt, max), min);
			}

			if (meta.dataset._model.cubicInterpolationMode === 'monotone') {
				helpers.splineCurveMonotone(points);
			} else {
				for (i = 0, ilen = points.length; i < ilen; ++i) {
					point = points[i];
					model = point._model;
					controlPoints = helpers.splineCurve(
						helpers.previousItem(points, i)._model,
						model,
						helpers.nextItem(points, i)._model,
						meta.dataset._model.tension
					);
					model.controlPointPreviousX = controlPoints.previous.x;
					model.controlPointPreviousY = controlPoints.previous.y;
					model.controlPointNextX = controlPoints.next.x;
					model.controlPointNextY = controlPoints.next.y;
				}
			}

			if (me.chart.options.elements.line.capBezierPoints) {
				for (i = 0, ilen = points.length; i < ilen; ++i) {
					model = points[i]._model;
					model.controlPointPreviousX = capControlPoint(model.controlPointPreviousX, area.left, area.right);
					model.controlPointPreviousY = capControlPoint(model.controlPointPreviousY, area.top, area.bottom);
					model.controlPointNextX = capControlPoint(model.controlPointNextX, area.left, area.right);
					model.controlPointNextY = capControlPoint(model.controlPointNextY, area.top, area.bottom);
				}
			}
		},

		draw: function() {
			var me = this;
			var chart = me.chart;
			var meta = me.getMeta();
			var points = meta.data || [];
			var area = chart.chartArea;
			var ilen = points.length;
			var i = 0;

			Chart.canvasHelpers.clipArea(chart.ctx, area);

			if (lineEnabled(me.getDataset(), chart.options)) {
				meta.dataset.draw();
			}

			Chart.canvasHelpers.unclipArea(chart.ctx);

			// Draw the points
			for (; i<ilen; ++i) {
				points[i].draw(area);
			}
		},

		setHoverStyle: function(point) {
			// Point
			var dataset = this.chart.data.datasets[point._datasetIndex];
			var index = point._index;
			var custom = point.custom || {};
			var model = point._model;

			model.radius = custom.hoverRadius || helpers.getValueAtIndexOrDefault(dataset.pointHoverRadius, index, this.chart.options.elements.point.hoverRadius);
			model.backgroundColor = custom.hoverBackgroundColor || helpers.getValueAtIndexOrDefault(dataset.pointHoverBackgroundColor, index, helpers.getHoverColor(model.backgroundColor));
			model.borderColor = custom.hoverBorderColor || helpers.getValueAtIndexOrDefault(dataset.pointHoverBorderColor, index, helpers.getHoverColor(model.borderColor));
			model.borderWidth = custom.hoverBorderWidth || helpers.getValueAtIndexOrDefault(dataset.pointHoverBorderWidth, index, model.borderWidth);
		},

		removeHoverStyle: function(point) {
			var me = this;
			var dataset = me.chart.data.datasets[point._datasetIndex];
			var index = point._index;
			var custom = point.custom || {};
			var model = point._model;

			// Compatibility: If the properties are defined with only the old name, use those values
			if ((dataset.radius !== undefined) && (dataset.pointRadius === undefined)) {
				dataset.pointRadius = dataset.radius;
			}

			model.radius = custom.radius || helpers.getValueAtIndexOrDefault(dataset.pointRadius, index, me.chart.options.elements.point.radius);
			model.backgroundColor = me.getPointBackgroundColor(point, index);
			model.borderColor = me.getPointBorderColor(point, index);
			model.borderWidth = me.getPointBorderWidth(point, index);
		}
	});
};

},{}],19:[function(require,module,exports){
'use strict';

module.exports = function(Chart) {

	var helpers = Chart.helpers;

	Chart.defaults.polarArea = {

		scale: {
			type: 'radialLinear',
			angleLines: {
				display: false
			},
			gridLines: {
				circular: true
			},
			pointLabels: {
				display: false
			},
			ticks: {
				beginAtZero: true
			}
		},

		// Boolean - Whether to animate the rotation of the chart
		animation: {
			animateRotate: true,
			animateScale: true
		},

		startAngle: -0.5 * Math.PI,
		aspectRatio: 1,
		legendCallback: function(chart) {
			var text = [];
			text.push('<ul class="' + chart.id + '-legend">');

			var data = chart.data;
			var datasets = data.datasets;
			var labels = data.labels;

			if (datasets.length) {
				for (var i = 0; i < datasets[0].data.length; ++i) {
					text.push('<li><span style="background-color:' + datasets[0].backgroundColor[i] + '"></span>');
					if (labels[i]) {
						text.push(labels[i]);
					}
					text.push('</li>');
				}
			}

			text.push('</ul>');
			return text.join('');
		},
		legend: {
			labels: {
				generateLabels: function(chart) {
					var data = chart.data;
					if (data.labels.length && data.datasets.length) {
						return data.labels.map(function(label, i) {
							var meta = chart.getDatasetMeta(0);
							var ds = data.datasets[0];
							var arc = meta.data[i];
							var custom = arc.custom || {};
							var getValueAtIndexOrDefault = helpers.getValueAtIndexOrDefault;
							var arcOpts = chart.options.elements.arc;
							var fill = custom.backgroundColor ? custom.backgroundColor : getValueAtIndexOrDefault(ds.backgroundColor, i, arcOpts.backgroundColor);
							var stroke = custom.borderColor ? custom.borderColor : getValueAtIndexOrDefault(ds.borderColor, i, arcOpts.borderColor);
							var bw = custom.borderWidth ? custom.borderWidth : getValueAtIndexOrDefault(ds.borderWidth, i, arcOpts.borderWidth);

							return {
								text: label,
								fillStyle: fill,
								strokeStyle: stroke,
								lineWidth: bw,
								hidden: isNaN(ds.data[i]) || meta.data[i].hidden,

								// Extra data used for toggling the correct item
								index: i
							};
						});
					}
					return [];
				}
			},

			onClick: function(e, legendItem) {
				var index = legendItem.index;
				var chart = this.chart;
				var i, ilen, meta;

				for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) {
					meta = chart.getDatasetMeta(i);
					meta.data[index].hidden = !meta.data[index].hidden;
				}

				chart.update();
			}
		},

		// Need to override these to give a nice default
		tooltips: {
			callbacks: {
				title: function() {
					return '';
				},
				label: function(tooltipItem, data) {
					return data.labels[tooltipItem.index] + ': ' + tooltipItem.yLabel;
				}
			}
		}
	};

	Chart.controllers.polarArea = Chart.DatasetController.extend({

		dataElementType: Chart.elements.Arc,

		linkScales: helpers.noop,

		update: function(reset) {
			var me = this;
			var chart = me.chart;
			var chartArea = chart.chartArea;
			var meta = me.getMeta();
			var opts = chart.options;
			var arcOpts = opts.elements.arc;
			var minSize = Math.min(chartArea.right - chartArea.left, chartArea.bottom - chartArea.top);
			chart.outerRadius = Math.max((minSize - arcOpts.borderWidth / 2) / 2, 0);
			chart.innerRadius = Math.max(opts.cutoutPercentage ? (chart.outerRadius / 100) * (opts.cutoutPercentage) : 1, 0);
			chart.radiusLength = (chart.outerRadius - chart.innerRadius) / chart.getVisibleDatasetCount();

			me.outerRadius = chart.outerRadius - (chart.radiusLength * me.index);
			me.innerRadius = me.outerRadius - chart.radiusLength;

			meta.count = me.countVisibleElements();

			helpers.each(meta.data, function(arc, index) {
				me.updateElement(arc, index, reset);
			});
		},

		updateElement: function(arc, index, reset) {
			var me = this;
			var chart = me.chart;
			var dataset = me.getDataset();
			var opts = chart.options;
			var animationOpts = opts.animation;
			var scale = chart.scale;
			var getValueAtIndexOrDefault = helpers.getValueAtIndexOrDefault;
			var labels = chart.data.labels;

			var circumference = me.calculateCircumference(dataset.data[index]);
			var centerX = scale.xCenter;
			var centerY = scale.yCenter;

			// If there is NaN data before us, we need to calculate the starting angle correctly.
			// We could be way more efficient here, but its unlikely that the polar area chart will have a lot of data
			var visibleCount = 0;
			var meta = me.getMeta();
			for (var i = 0; i < index; ++i) {
				if (!isNaN(dataset.data[i]) && !meta.data[i].hidden) {
					++visibleCount;
				}
			}

			// var negHalfPI = -0.5 * Math.PI;
			var datasetStartAngle = opts.startAngle;
			var distance = arc.hidden ? 0 : scale.getDistanceFromCenterForValue(dataset.data[index]);
			var startAngle = datasetStartAngle + (circumference * visibleCount);
			var endAngle = startAngle + (arc.hidden ? 0 : circumference);

			var resetRadius = animationOpts.animateScale ? 0 : scale.getDistanceFromCenterForValue(dataset.data[index]);

			helpers.extend(arc, {
				// Utility
				_datasetIndex: me.index,
				_index: index,
				_scale: scale,

				// Desired view properties
				_model: {
					x: centerX,
					y: centerY,
					innerRadius: 0,
					outerRadius: reset ? resetRadius : distance,
					startAngle: reset && animationOpts.animateRotate ? datasetStartAngle : startAngle,
					endAngle: reset && animationOpts.animateRotate ? datasetStartAngle : endAngle,
					label: getValueAtIndexOrDefault(labels, index, labels[index])
				}
			});

			// Apply border and fill style
			me.removeHoverStyle(arc);

			arc.pivot();
		},

		removeHoverStyle: function(arc) {
			Chart.DatasetController.prototype.removeHoverStyle.call(this, arc, this.chart.options.elements.arc);
		},

		countVisibleElements: function() {
			var dataset = this.getDataset();
			var meta = this.getMeta();
			var count = 0;

			helpers.each(meta.data, function(element, index) {
				if (!isNaN(dataset.data[index]) && !element.hidden) {
					count++;
				}
			});

			return count;
		},

		calculateCircumference: function(value) {
			var count = this.getMeta().count;
			if (count > 0 && !isNaN(value)) {
				return (2 * Math.PI) / count;
			}
			return 0;
		}
	});
};

},{}],20:[function(require,module,exports){
'use strict';

module.exports = function(Chart) {

	var helpers = Chart.helpers;

	Chart.defaults.radar = {
		aspectRatio: 1,
		scale: {
			type: 'radialLinear'
		},
		elements: {
			line: {
				tension: 0 // no bezier in radar
			}
		}
	};

	Chart.controllers.radar = Chart.DatasetController.extend({

		datasetElementType: Chart.elements.Line,

		dataElementType: Chart.elements.Point,

		linkScales: helpers.noop,

		update: function(reset) {
			var me = this;
			var meta = me.getMeta();
			var line = meta.dataset;
			var points = meta.data;
			var custom = line.custom || {};
			var dataset = me.getDataset();
			var lineElementOptions = me.chart.options.elements.line;
			var scale = me.chart.scale;

			// Compatibility: If the properties are defined with only the old name, use those values
			if ((dataset.tension !== undefined) && (dataset.lineTension === undefined)) {
				dataset.lineTension = dataset.tension;
			}

			helpers.extend(meta.dataset, {
				// Utility
				_datasetIndex: me.index,
				_scale: scale,
				// Data
				_children: points,
				_loop: true,
				// Model
				_model: {
					// Appearance
					tension: custom.tension ? custom.tension : helpers.getValueOrDefault(dataset.lineTension, lineElementOptions.tension),
					backgroundColor: custom.backgroundColor ? custom.backgroundColor : (dataset.backgroundColor || lineElementOptions.backgroundColor),
					borderWidth: custom.borderWidth ? custom.borderWidth : (dataset.borderWidth || lineElementOptions.borderWidth),
					borderColor: custom.borderColor ? custom.borderColor : (dataset.borderColor || lineElementOptions.borderColor),
					fill: custom.fill ? custom.fill : (dataset.fill !== undefined ? dataset.fill : lineElementOptions.fill),
					borderCapStyle: custom.borderCapStyle ? custom.borderCapStyle : (dataset.borderCapStyle || lineElementOptions.borderCapStyle),
					borderDash: custom.borderDash ? custom.borderDash : (dataset.borderDash || lineElementOptions.borderDash),
					borderDashOffset: custom.borderDashOffset ? custom.borderDashOffset : (dataset.borderDashOffset || lineElementOptions.borderDashOffset),
					borderJoinStyle: custom.borderJoinStyle ? custom.borderJoinStyle : (dataset.borderJoinStyle || lineElementOptions.borderJoinStyle),
				}
			});

			meta.dataset.pivot();

			// Update Points
			helpers.each(points, function(point, index) {
				me.updateElement(point, index, reset);
			}, me);

			// Update bezier control points
			me.updateBezierControlPoints();
		},
		updateElement: function(point, index, reset) {
			var me = this;
			var custom = point.custom || {};
			var dataset = me.getDataset();
			var scale = me.chart.scale;
			var pointElementOptions = me.chart.options.elements.point;
			var pointPosition = scale.getPointPositionForValue(index, dataset.data[index]);

			// Compatibility: If the properties are defined with only the old name, use those values
			if ((dataset.radius !== undefined) && (dataset.pointRadius === undefined)) {
				dataset.pointRadius = dataset.radius;
			}
			if ((dataset.hitRadius !== undefined) && (dataset.pointHitRadius === undefined)) {
				dataset.pointHitRadius = dataset.hitRadius;
			}

			helpers.extend(point, {
				// Utility
				_datasetIndex: me.index,
				_index: index,
				_scale: scale,

				// Desired view properties
				_model: {
					x: reset ? scale.xCenter : pointPosition.x, // value not used in dataset scale, but we want a consistent API between scales
					y: reset ? scale.yCenter : pointPosition.y,

					// Appearance
					tension: custom.tension ? custom.tension : helpers.getValueOrDefault(dataset.lineTension, me.chart.options.elements.line.tension),
					radius: custom.radius ? custom.radius : helpers.getValueAtIndexOrDefault(dataset.pointRadius, index, pointElementOptions.radius),
					backgroundColor: custom.backgroundColor ? custom.backgroundColor : helpers.getValueAtIndexOrDefault(dataset.pointBackgroundColor, index, pointElementOptions.backgroundColor),
					borderColor: custom.borderColor ? custom.borderColor : helpers.getValueAtIndexOrDefault(dataset.pointBorderColor, index, pointElementOptions.borderColor),
					borderWidth: custom.borderWidth ? custom.borderWidth : helpers.getValueAtIndexOrDefault(dataset.pointBorderWidth, index, pointElementOptions.borderWidth),
					pointStyle: custom.pointStyle ? custom.pointStyle : helpers.getValueAtIndexOrDefault(dataset.pointStyle, index, pointElementOptions.pointStyle),

					// Tooltip
					hitRadius: custom.hitRadius ? custom.hitRadius : helpers.getValueAtIndexOrDefault(dataset.pointHitRadius, index, pointElementOptions.hitRadius)
				}
			});

			point._model.skip = custom.skip ? custom.skip : (isNaN(point._model.x) || isNaN(point._model.y));
		},
		updateBezierControlPoints: function() {
			var chartArea = this.chart.chartArea;
			var meta = this.getMeta();

			helpers.each(meta.data, function(point, index) {
				var model = point._model;
				var controlPoints = helpers.splineCurve(
					helpers.previousItem(meta.data, index, true)._model,
					model,
					helpers.nextItem(meta.data, index, true)._model,
					model.tension
				);

				// Prevent the bezier going outside of the bounds of the graph
				model.controlPointPreviousX = Math.max(Math.min(controlPoints.previous.x, chartArea.right), chartArea.left);
				model.controlPointPreviousY = Math.max(Math.min(controlPoints.previous.y, chartArea.bottom), chartArea.top);

				model.controlPointNextX = Math.max(Math.min(controlPoints.next.x, chartArea.right), chartArea.left);
				model.controlPointNextY = Math.max(Math.min(controlPoints.next.y, chartArea.bottom), chartArea.top);

				// Now pivot the point for animation
				point.pivot();
			});
		},

		setHoverStyle: function(point) {
			// Point
			var dataset = this.chart.data.datasets[point._datasetIndex];
			var custom = point.custom || {};
			var index = point._index;
			var model = point._model;

			model.radius = custom.hoverRadius ? custom.hoverRadius : helpers.getValueAtIndexOrDefault(dataset.pointHoverRadius, index, this.chart.options.elements.point.hoverRadius);
			model.backgroundColor = custom.hoverBackgroundColor ? custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(dataset.pointHoverBackgroundColor, index, helpers.getHoverColor(model.backgroundColor));
			model.borderColor = custom.hoverBorderColor ? custom.hoverBorderColor : helpers.getValueAtIndexOrDefault(dataset.pointHoverBorderColor, index, helpers.getHoverColor(model.borderColor));
			model.borderWidth = custom.hoverBorderWidth ? custom.hoverBorderWidth : helpers.getValueAtIndexOrDefault(dataset.pointHoverBorderWidth, index, model.borderWidth);
		},

		removeHoverStyle: function(point) {
			var dataset = this.chart.data.datasets[point._datasetIndex];
			var custom = point.custom || {};
			var index = point._index;
			var model = point._model;
			var pointElementOptions = this.chart.options.elements.point;

			model.radius = custom.radius ? custom.radius : helpers.getValueAtIndexOrDefault(dataset.pointRadius, index, pointElementOptions.radius);
			model.backgroundColor = custom.backgroundColor ? custom.backgroundColor : helpers.getValueAtIndexOrDefault(dataset.pointBackgroundColor, index, pointElementOptions.backgroundColor);
			model.borderColor = custom.borderColor ? custom.borderColor : helpers.getValueAtIndexOrDefault(dataset.pointBorderColor, index, pointElementOptions.borderColor);
			model.borderWidth = custom.borderWidth ? custom.borderWidth : helpers.getValueAtIndexOrDefault(dataset.pointBorderWidth, index, pointElementOptions.borderWidth);
		}
	});
};

},{}],21:[function(require,module,exports){
/* global window: false */
'use strict';

module.exports = function(Chart) {

	var helpers = Chart.helpers;

	Chart.defaults.global.animation = {
		duration: 1000,
		easing: 'easeOutQuart',
		onProgress: helpers.noop,
		onComplete: helpers.noop
	};

	Chart.Animation = Chart.Element.extend({
		chart: null, // the animation associated chart instance
		currentStep: 0, // the current animation step
		numSteps: 60, // default number of steps
		easing: '', // the easing to use for this animation
		render: null, // render function used by the animation service

		onAnimationProgress: null, // user specified callback to fire on each step of the animation
		onAnimationComplete: null, // user specified callback to fire when the animation finishes
	});

	Chart.animationService = {
		frameDuration: 17,
		animations: [],
		dropFrames: 0,
		request: null,

		/**
		 * @param {Chart} chart - The chart to animate.
		 * @param {Chart.Animation} animation - The animation that we will animate.
		 * @param {Number} duration - The animation duration in ms.
		 * @param {Boolean} lazy - if true, the chart is not marked as animating to enable more responsive interactions
		 */
		addAnimation: function(chart, animation, duration, lazy) {
			var animations = this.animations;
			var i, ilen;

			animation.chart = chart;

			if (!lazy) {
				chart.animating = true;
			}

			for (i=0, ilen=animations.length; i < ilen; ++i) {
				if (animations[i].chart === chart) {
					animations[i] = animation;
					return;
				}
			}

			animations.push(animation);

			// If there are no animations queued, manually kickstart a digest, for lack of a better word
			if (animations.length === 1) {
				this.requestAnimationFrame();
			}
		},

		cancelAnimation: function(chart) {
			var index = helpers.findIndex(this.animations, function(animation) {
				return animation.chart === chart;
			});

			if (index !== -1) {
				this.animations.splice(index, 1);
				chart.animating = false;
			}
		},

		requestAnimationFrame: function() {
			var me = this;
			if (me.request === null) {
				// Skip animation frame requests until the active one is executed.
				// This can happen when processing mouse events, e.g. 'mousemove'
				// and 'mouseout' events will trigger multiple renders.
				me.request = helpers.requestAnimFrame.call(window, function() {
					me.request = null;
					me.startDigest();
				});
			}
		},

		/**
		 * @private
		 */
		startDigest: function() {
			var me = this;
			var startTime = Date.now();
			var framesToDrop = 0;

			if (me.dropFrames > 1) {
				framesToDrop = Math.floor(me.dropFrames);
				me.dropFrames = me.dropFrames % 1;
			}

			me.advance(1 + framesToDrop);

			var endTime = Date.now();

			me.dropFrames += (endTime - startTime) / me.frameDuration;

			// Do we have more stuff to animate?
			if (me.animations.length > 0) {
				me.requestAnimationFrame();
			}
		},

		/**
		 * @private
		 */
		advance: function(count) {
			var animations = this.animations;
			var animation, chart;
			var i = 0;

			while (i < animations.length) {
				animation = animations[i];
				chart = animation.chart;

				animation.currentStep = (animation.currentStep || 0) + count;
				animation.currentStep = Math.min(animation.currentStep, animation.numSteps);

				helpers.callback(animation.render, [chart, animation], chart);
				helpers.callback(animation.onAnimationProgress, [animation], chart);

				if (animation.currentStep >= animation.numSteps) {
					helpers.callback(animation.onAnimationComplete, [animation], chart);
					chart.animating = false;
					animations.splice(i, 1);
				} else {
					++i;
				}
			}
		}
	};

	/**
	 * Provided for backward compatibility, use Chart.Animation instead
	 * @prop Chart.Animation#animationObject
	 * @deprecated since version 2.6.0
	 * @todo remove at version 3
	 */
	Object.defineProperty(Chart.Animation.prototype, 'animationObject', {
		get: function() {
			return this;
		}
	});

	/**
	 * Provided for backward compatibility, use Chart.Animation#chart instead
	 * @prop Chart.Animation#chartInstance
	 * @deprecated since version 2.6.0
	 * @todo remove at version 3
	 */
	Object.defineProperty(Chart.Animation.prototype, 'chartInstance', {
		get: function() {
			return this.chart;
		},
		set: function(value) {
			this.chart = value;
		}
	});

};

},{}],22:[function(require,module,exports){
'use strict';

module.exports = function(Chart) {
	// Global Chart canvas helpers object for drawing items to canvas
	var helpers = Chart.canvasHelpers = {};

	helpers.drawPoint = function(ctx, pointStyle, radius, x, y) {
		var type, edgeLength, xOffset, yOffset, height, size;

		if (typeof pointStyle === 'object') {
			type = pointStyle.toString();
			if (type === '[object HTMLImageElement]' || type === '[object HTMLCanvasElement]') {
				ctx.drawImage(pointStyle, x - pointStyle.width / 2, y - pointStyle.height / 2, pointStyle.width, pointStyle.height);
				return;
			}
		}

		if (isNaN(radius) || radius <= 0) {
			return;
		}

		switch (pointStyle) {
		// Default includes circle
		default:
			ctx.beginPath();
			ctx.arc(x, y, radius, 0, Math.PI * 2);
			ctx.closePath();
			ctx.fill();
			break;
		case 'triangle':
			ctx.beginPath();
			edgeLength = 3 * radius / Math.sqrt(3);
			height = edgeLength * Math.sqrt(3) / 2;
			ctx.moveTo(x - edgeLength / 2, y + height / 3);
			ctx.lineTo(x + edgeLength / 2, y + height / 3);
			ctx.lineTo(x, y - 2 * height / 3);
			ctx.closePath();
			ctx.fill();
			break;
		case 'rect':
			size = 1 / Math.SQRT2 * radius;
			ctx.beginPath();
			ctx.fillRect(x - size, y - size, 2 * size, 2 * size);
			ctx.strokeRect(x - size, y - size, 2 * size, 2 * size);
			break;
		case 'rectRounded':
			var offset = radius / Math.SQRT2;
			var leftX = x - offset;
			var topY = y - offset;
			var sideSize = Math.SQRT2 * radius;
			Chart.helpers.drawRoundedRectangle(ctx, leftX, topY, sideSize, sideSize, radius / 2);
			ctx.fill();
			break;
		case 'rectRot':
			size = 1 / Math.SQRT2 * radius;
			ctx.beginPath();
			ctx.moveTo(x - size, y);
			ctx.lineTo(x, y + size);
			ctx.lineTo(x + size, y);
			ctx.lineTo(x, y - size);
			ctx.closePath();
			ctx.fill();
			break;
		case 'cross':
			ctx.beginPath();
			ctx.moveTo(x, y + radius);
			ctx.lineTo(x, y - radius);
			ctx.moveTo(x - radius, y);
			ctx.lineTo(x + radius, y);
			ctx.closePath();
			break;
		case 'crossRot':
			ctx.beginPath();
			xOffset = Math.cos(Math.PI / 4) * radius;
			yOffset = Math.sin(Math.PI / 4) * radius;
			ctx.moveTo(x - xOffset, y - yOffset);
			ctx.lineTo(x + xOffset, y + yOffset);
			ctx.moveTo(x - xOffset, y + yOffset);
			ctx.lineTo(x + xOffset, y - yOffset);
			ctx.closePath();
			break;
		case 'star':
			ctx.beginPath();
			ctx.moveTo(x, y + radius);
			ctx.lineTo(x, y - radius);
			ctx.moveTo(x - radius, y);
			ctx.lineTo(x + radius, y);
			xOffset = Math.cos(Math.PI / 4) * radius;
			yOffset = Math.sin(Math.PI / 4) * radius;
			ctx.moveTo(x - xOffset, y - yOffset);
			ctx.lineTo(x + xOffset, y + yOffset);
			ctx.moveTo(x - xOffset, y + yOffset);
			ctx.lineTo(x + xOffset, y - yOffset);
			ctx.closePath();
			break;
		case 'line':
			ctx.beginPath();
			ctx.moveTo(x - radius, y);
			ctx.lineTo(x + radius, y);
			ctx.closePath();
			break;
		case 'dash':
			ctx.beginPath();
			ctx.moveTo(x, y);
			ctx.lineTo(x + radius, y);
			ctx.closePath();
			break;
		}

		ctx.stroke();
	};

	helpers.clipArea = function(ctx, clipArea) {
		ctx.save();
		ctx.beginPath();
		ctx.rect(clipArea.left, clipArea.top, clipArea.right - clipArea.left, clipArea.bottom - clipArea.top);
		ctx.clip();
	};

	helpers.unclipArea = function(ctx) {
		ctx.restore();
	};

	helpers.lineTo = function(ctx, previous, target, flip) {
		if (target.steppedLine) {
			if (target.steppedLine === 'after') {
				ctx.lineTo(previous.x, target.y);
			} else {
				ctx.lineTo(target.x, previous.y);
			}
			ctx.lineTo(target.x, target.y);
			return;
		}

		if (!target.tension) {
			ctx.lineTo(target.x, target.y);
			return;
		}

		ctx.bezierCurveTo(
			flip? previous.controlPointPreviousX : previous.controlPointNextX,
			flip? previous.controlPointPreviousY : previous.controlPointNextY,
			flip? target.controlPointNextX : target.controlPointPreviousX,
			flip? target.controlPointNextY : target.controlPointPreviousY,
			target.x,
			target.y);
	};

	Chart.helpers.canvas = helpers;
};

},{}],23:[function(require,module,exports){
'use strict';

module.exports = function(Chart) {

	var helpers = Chart.helpers;
	var plugins = Chart.plugins;
	var platform = Chart.platform;

	// Create a dictionary of chart types, to allow for extension of existing types
	Chart.types = {};

	// Store a reference to each instance - allowing us to globally resize chart instances on window resize.
	// Destroy method on the chart will remove the instance of the chart from this reference.
	Chart.instances = {};

	// Controllers available for dataset visualization eg. bar, line, slice, etc.
	Chart.controllers = {};

	/**
	 * Initializes the given config with global and chart default values.
	 */
	function initConfig(config) {
		config = config || {};

		// Do NOT use configMerge() for the data object because this method merges arrays
		// and so would change references to labels and datasets, preventing data updates.
		var data = config.data = config.data || {};
		data.datasets = data.datasets || [];
		data.labels = data.labels || [];

		config.options = helpers.configMerge(
			Chart.defaults.global,
			Chart.defaults[config.type],
			config.options || {});

		return config;
	}

	/**
	 * Updates the config of the chart
	 * @param chart {Chart} chart to update the options for
	 */
	function updateConfig(chart) {
		var newOptions = chart.options;

		// Update Scale(s) with options
		if (newOptions.scale) {
			chart.scale.options = newOptions.scale;
		} else if (newOptions.scales) {
			newOptions.scales.xAxes.concat(newOptions.scales.yAxes).forEach(function(scaleOptions) {
				chart.scales[scaleOptions.id].options = scaleOptions;
			});
		}

		// Tooltip
		chart.tooltip._options = newOptions.tooltips;
	}

	function positionIsHorizontal(position) {
		return position === 'top' || position === 'bottom';
	}

	helpers.extend(Chart.prototype, /** @lends Chart */ {
		/**
		 * @private
		 */
		construct: function(item, config) {
			var me = this;

			config = initConfig(config);

			var context = platform.acquireContext(item, config);
			var canvas = context && context.canvas;
			var height = canvas && canvas.height;
			var width = canvas && canvas.width;

			me.id = helpers.uid();
			me.ctx = context;
			me.canvas = canvas;
			me.config = config;
			me.width = width;
			me.height = height;
			me.aspectRatio = height? width / height : null;
			me.options = config.options;
			me._bufferedRender = false;

			/**
			 * Provided for backward compatibility, Chart and Chart.Controller have been merged,
			 * the "instance" still need to be defined since it might be called from plugins.
			 * @prop Chart#chart
			 * @deprecated since version 2.6.0
			 * @todo remove at version 3
			 * @private
			 */
			me.chart = me;
			me.controller = me;  // chart.chart.controller #inception

			// Add the chart instance to the global namespace
			Chart.instances[me.id] = me;

			// Define alias to the config data: `chart.data === chart.config.data`
			Object.defineProperty(me, 'data', {
				get: function() {
					return me.config.data;
				},
				set: function(value) {
					me.config.data = value;
				}
			});

			if (!context || !canvas) {
				// The given item is not a compatible context2d element, let's return before finalizing
				// the chart initialization but after setting basic chart / controller properties that
				// can help to figure out that the chart is not valid (e.g chart.canvas !== null);
				// https://github.com/chartjs/Chart.js/issues/2807
				console.error("Failed to create chart: can't acquire context from the given item");
				return;
			}

			me.initialize();
			me.update();
		},

		/**
		 * @private
		 */
		initialize: function() {
			var me = this;

			// Before init plugin notification
			plugins.notify(me, 'beforeInit');

			helpers.retinaScale(me);

			me.bindEvents();

			if (me.options.responsive) {
				// Initial resize before chart draws (must be silent to preserve initial animations).
				me.resize(true);
			}

			// Make sure scales have IDs and are built before we build any controllers.
			me.ensureScalesHaveIDs();
			me.buildScales();
			me.initToolTip();

			// After init plugin notification
			plugins.notify(me, 'afterInit');

			return me;
		},

		clear: function() {
			helpers.clear(this);
			return this;
		},

		stop: function() {
			// Stops any current animation loop occurring
			Chart.animationService.cancelAnimation(this);
			return this;
		},

		resize: function(silent) {
			var me = this;
			var options = me.options;
			var canvas = me.canvas;
			var aspectRatio = (options.maintainAspectRatio && me.aspectRatio) || null;

			// the canvas render width and height will be casted to integers so make sure that
			// the canvas display style uses the same integer values to avoid blurring effect.
			var newWidth = Math.floor(helpers.getMaximumWidth(canvas));
			var newHeight = Math.floor(aspectRatio? newWidth / aspectRatio : helpers.getMaximumHeight(canvas));

			if (me.width === newWidth && me.height === newHeight) {
				return;
			}

			canvas.width = me.width = newWidth;
			canvas.height = me.height = newHeight;
			canvas.style.width = newWidth + 'px';
			canvas.style.height = newHeight + 'px';

			helpers.retinaScale(me);

			if (!silent) {
				// Notify any plugins about the resize
				var newSize = {width: newWidth, height: newHeight};
				plugins.notify(me, 'resize', [newSize]);

				// Notify of resize
				if (me.options.onResize) {
					me.options.onResize(me, newSize);
				}

				me.stop();
				me.update(me.options.responsiveAnimationDuration);
			}
		},

		ensureScalesHaveIDs: function() {
			var options = this.options;
			var scalesOptions = options.scales || {};
			var scaleOptions = options.scale;

			helpers.each(scalesOptions.xAxes, function(xAxisOptions, index) {
				xAxisOptions.id = xAxisOptions.id || ('x-axis-' + index);
			});

			helpers.each(scalesOptions.yAxes, function(yAxisOptions, index) {
				yAxisOptions.id = yAxisOptions.id || ('y-axis-' + index);
			});

			if (scaleOptions) {
				scaleOptions.id = scaleOptions.id || 'scale';
			}
		},

		/**
		 * Builds a map of scale ID to scale object for future lookup.
		 */
		buildScales: function() {
			var me = this;
			var options = me.options;
			var scales = me.scales = {};
			var items = [];

			if (options.scales) {
				items = items.concat(
					(options.scales.xAxes || []).map(function(xAxisOptions) {
						return {options: xAxisOptions, dtype: 'category', dposition: 'bottom'};
					}),
					(options.scales.yAxes || []).map(function(yAxisOptions) {
						return {options: yAxisOptions, dtype: 'linear', dposition: 'left'};
					})
				);
			}

			if (options.scale) {
				items.push({
					options: options.scale,
					dtype: 'radialLinear',
					isDefault: true,
					dposition: 'chartArea'
				});
			}

			helpers.each(items, function(item) {
				var scaleOptions = item.options;
				var scaleType = helpers.getValueOrDefault(scaleOptions.type, item.dtype);
				var scaleClass = Chart.scaleService.getScaleConstructor(scaleType);
				if (!scaleClass) {
					return;
				}

				if (positionIsHorizontal(scaleOptions.position) !== positionIsHorizontal(item.dposition)) {
					scaleOptions.position = item.dposition;
				}

				var scale = new scaleClass({
					id: scaleOptions.id,
					options: scaleOptions,
					ctx: me.ctx,
					chart: me
				});

				scales[scale.id] = scale;

				// TODO(SB): I think we should be able to remove this custom case (options.scale)
				// and consider it as a regular scale part of the "scales"" map only! This would
				// make the logic easier and remove some useless? custom code.
				if (item.isDefault) {
					me.scale = scale;
				}
			});

			Chart.scaleService.addScalesToLayout(this);
		},

		buildOrUpdateControllers: function() {
			var me = this;
			var types = [];
			var newControllers = [];

			helpers.each(me.data.datasets, function(dataset, datasetIndex) {
				var meta = me.getDatasetMeta(datasetIndex);
				if (!meta.type) {
					meta.type = dataset.type || me.config.type;
				}

				types.push(meta.type);

				if (meta.controller) {
					meta.controller.updateIndex(datasetIndex);
				} else {
					var ControllerClass = Chart.controllers[meta.type];
					if (ControllerClass === undefined) {
						throw new Error('"' + meta.type + '" is not a chart type.');
					}

					meta.controller = new ControllerClass(me, datasetIndex);
					newControllers.push(meta.controller);
				}
			}, me);

			if (types.length > 1) {
				for (var i = 1; i < types.length; i++) {
					if (types[i] !== types[i - 1]) {
						me.isCombo = true;
						break;
					}
				}
			}

			return newControllers;
		},

		/**
		 * Reset the elements of all datasets
		 * @private
		 */
		resetElements: function() {
			var me = this;
			helpers.each(me.data.datasets, function(dataset, datasetIndex) {
				me.getDatasetMeta(datasetIndex).controller.reset();
			}, me);
		},

		/**
		* Resets the chart back to it's state before the initial animation
		*/
		reset: function() {
			this.resetElements();
			this.tooltip.initialize();
		},

		update: function(animationDuration, lazy) {
			var me = this;

			updateConfig(me);

			if (plugins.notify(me, 'beforeUpdate') === false) {
				return;
			}

			// In case the entire data object changed
			me.tooltip._data = me.data;

			// Make sure dataset controllers are updated and new controllers are reset
			var newControllers = me.buildOrUpdateControllers();

			// Make sure all dataset controllers have correct meta data counts
			helpers.each(me.data.datasets, function(dataset, datasetIndex) {
				me.getDatasetMeta(datasetIndex).controller.buildOrUpdateElements();
			}, me);

			me.updateLayout();

			// Can only reset the new controllers after the scales have been updated
			helpers.each(newControllers, function(controller) {
				controller.reset();
			});

			me.updateDatasets();

			// Do this before render so that any plugins that need final scale updates can use it
			plugins.notify(me, 'afterUpdate');

			if (me._bufferedRender) {
				me._bufferedRequest = {
					lazy: lazy,
					duration: animationDuration
				};
			} else {
				me.render(animationDuration, lazy);
			}
		},

		/**
		 * Updates the chart layout unless a plugin returns `false` to the `beforeLayout`
		 * hook, in which case, plugins will not be called on `afterLayout`.
		 * @private
		 */
		updateLayout: function() {
			var me = this;

			if (plugins.notify(me, 'beforeLayout') === false) {
				return;
			}

			Chart.layoutService.update(this, this.width, this.height);

			/**
			 * Provided for backward compatibility, use `afterLayout` instead.
			 * @method IPlugin#afterScaleUpdate
			 * @deprecated since version 2.5.0
			 * @todo remove at version 3
			 * @private
			 */
			plugins.notify(me, 'afterScaleUpdate');
			plugins.notify(me, 'afterLayout');
		},

		/**
		 * Updates all datasets unless a plugin returns `false` to the `beforeDatasetsUpdate`
		 * hook, in which case, plugins will not be called on `afterDatasetsUpdate`.
		 * @private
		 */
		updateDatasets: function() {
			var me = this;

			if (plugins.notify(me, 'beforeDatasetsUpdate') === false) {
				return;
			}

			for (var i = 0, ilen = me.data.datasets.length; i < ilen; ++i) {
				me.updateDataset(i);
			}

			plugins.notify(me, 'afterDatasetsUpdate');
		},

		/**
		 * Updates dataset at index unless a plugin returns `false` to the `beforeDatasetUpdate`
		 * hook, in which case, plugins will not be called on `afterDatasetUpdate`.
		 * @private
		 */
		updateDataset: function(index) {
			var me = this;
			var meta = me.getDatasetMeta(index);
			var args = {
				meta: meta,
				index: index
			};

			if (plugins.notify(me, 'beforeDatasetUpdate', [args]) === false) {
				return;
			}

			meta.controller.update();

			plugins.notify(me, 'afterDatasetUpdate', [args]);
		},

		render: function(duration, lazy) {
			var me = this;

			if (plugins.notify(me, 'beforeRender') === false) {
				return;
			}

			var animationOptions = me.options.animation;
			var onComplete = function(animation) {
				plugins.notify(me, 'afterRender');
				helpers.callback(animationOptions && animationOptions.onComplete, [animation], me);
			};

			if (animationOptions && ((typeof duration !== 'undefined' && duration !== 0) || (typeof duration === 'undefined' && animationOptions.duration !== 0))) {
				var animation = new Chart.Animation({
					numSteps: (duration || animationOptions.duration) / 16.66, // 60 fps
					easing: animationOptions.easing,

					render: function(chart, animationObject) {
						var easingFunction = helpers.easingEffects[animationObject.easing];
						var currentStep = animationObject.currentStep;
						var stepDecimal = currentStep / animationObject.numSteps;

						chart.draw(easingFunction(stepDecimal), stepDecimal, currentStep);
					},

					onAnimationProgress: animationOptions.onProgress,
					onAnimationComplete: onComplete
				});

				Chart.animationService.addAnimation(me, animation, duration, lazy);
			} else {
				me.draw();

				// See https://github.com/chartjs/Chart.js/issues/3781
				onComplete(new Chart.Animation({numSteps: 0, chart: me}));
			}

			return me;
		},

		draw: function(easingValue) {
			var me = this;

			me.clear();

			if (easingValue === undefined || easingValue === null) {
				easingValue = 1;
			}

			me.transition(easingValue);

			if (plugins.notify(me, 'beforeDraw', [easingValue]) === false) {
				return;
			}

			// Draw all the scales
			helpers.each(me.boxes, function(box) {
				box.draw(me.chartArea);
			}, me);

			if (me.scale) {
				me.scale.draw();
			}

			me.drawDatasets(easingValue);

			// Finally draw the tooltip
			me.tooltip.draw();

			plugins.notify(me, 'afterDraw', [easingValue]);
		},

		/**
		 * @private
		 */
		transition: function(easingValue) {
			var me = this;

			for (var i=0, ilen=(me.data.datasets || []).length; i<ilen; ++i) {
				if (me.isDatasetVisible(i)) {
					me.getDatasetMeta(i).controller.transition(easingValue);
				}
			}

			me.tooltip.transition(easingValue);
		},

		/**
		 * Draws all datasets unless a plugin returns `false` to the `beforeDatasetsDraw`
		 * hook, in which case, plugins will not be called on `afterDatasetsDraw`.
		 * @private
		 */
		drawDatasets: function(easingValue) {
			var me = this;

			if (plugins.notify(me, 'beforeDatasetsDraw', [easingValue]) === false) {
				return;
			}

			// Draw datasets reversed to support proper line stacking
			for (var i=(me.data.datasets || []).length - 1; i >= 0; --i) {
				if (me.isDatasetVisible(i)) {
					me.drawDataset(i, easingValue);
				}
			}

			plugins.notify(me, 'afterDatasetsDraw', [easingValue]);
		},

		/**
		 * Draws dataset at index unless a plugin returns `false` to the `beforeDatasetDraw`
		 * hook, in which case, plugins will not be called on `afterDatasetDraw`.
		 * @private
		 */
		drawDataset: function(index, easingValue) {
			var me = this;
			var meta = me.getDatasetMeta(index);
			var args = {
				meta: meta,
				index: index,
				easingValue: easingValue
			};

			if (plugins.notify(me, 'beforeDatasetDraw', [args]) === false) {
				return;
			}

			meta.controller.draw(easingValue);

			plugins.notify(me, 'afterDatasetDraw', [args]);
		},

		// Get the single element that was clicked on
		// @return : An object containing the dataset index and element index of the matching element. Also contains the rectangle that was draw
		getElementAtEvent: function(e) {
			return Chart.Interaction.modes.single(this, e);
		},

		getElementsAtEvent: function(e) {
			return Chart.Interaction.modes.label(this, e, {intersect: true});
		},

		getElementsAtXAxis: function(e) {
			return Chart.Interaction.modes['x-axis'](this, e, {intersect: true});
		},

		getElementsAtEventForMode: function(e, mode, options) {
			var method = Chart.Interaction.modes[mode];
			if (typeof method === 'function') {
				return method(this, e, options);
			}

			return [];
		},

		getDatasetAtEvent: function(e) {
			return Chart.Interaction.modes.dataset(this, e, {intersect: true});
		},

		getDatasetMeta: function(datasetIndex) {
			var me = this;
			var dataset = me.data.datasets[datasetIndex];
			if (!dataset._meta) {
				dataset._meta = {};
			}

			var meta = dataset._meta[me.id];
			if (!meta) {
				meta = dataset._meta[me.id] = {
					type: null,
					data: [],
					dataset: null,
					controller: null,
					hidden: null,			// See isDatasetVisible() comment
					xAxisID: null,
					yAxisID: null
				};
			}

			return meta;
		},

		getVisibleDatasetCount: function() {
			var count = 0;
			for (var i = 0, ilen = this.data.datasets.length; i<ilen; ++i) {
				if (this.isDatasetVisible(i)) {
					count++;
				}
			}
			return count;
		},

		isDatasetVisible: function(datasetIndex) {
			var meta = this.getDatasetMeta(datasetIndex);

			// meta.hidden is a per chart dataset hidden flag override with 3 states: if true or false,
			// the dataset.hidden value is ignored, else if null, the dataset hidden state is returned.
			return typeof meta.hidden === 'boolean'? !meta.hidden : !this.data.datasets[datasetIndex].hidden;
		},

		generateLegend: function() {
			return this.options.legendCallback(this);
		},

		destroy: function() {
			var me = this;
			var canvas = me.canvas;
			var meta, i, ilen;

			me.stop();

			// dataset controllers need to cleanup associated data
			for (i = 0, ilen = me.data.datasets.length; i < ilen; ++i) {
				meta = me.getDatasetMeta(i);
				if (meta.controller) {
					meta.controller.destroy();
					meta.controller = null;
				}
			}

			if (canvas) {
				me.unbindEvents();
				helpers.clear(me);
				platform.releaseContext(me.ctx);
				me.canvas = null;
				me.ctx = null;
			}

			plugins.notify(me, 'destroy');

			delete Chart.instances[me.id];
		},

		toBase64Image: function() {
			return this.canvas.toDataURL.apply(this.canvas, arguments);
		},

		initToolTip: function() {
			var me = this;
			me.tooltip = new Chart.Tooltip({
				_chart: me,
				_chartInstance: me,            // deprecated, backward compatibility
				_data: me.data,
				_options: me.options.tooltips
			}, me);
			me.tooltip.initialize();
		},

		/**
		 * @private
		 */
		bindEvents: function() {
			var me = this;
			var listeners = me._listeners = {};
			var listener = function() {
				me.eventHandler.apply(me, arguments);
			};

			helpers.each(me.options.events, function(type) {
				platform.addEventListener(me, type, listener);
				listeners[type] = listener;
			});

			// Responsiveness is currently based on the use of an iframe, however this method causes
			// performance issues and could be troublesome when used with ad blockers. So make sure
			// that the user is still able to create a chart without iframe when responsive is false.
			// See https://github.com/chartjs/Chart.js/issues/2210
			if (me.options.responsive) {
				listener = function() {
					me.resize();
				};

				platform.addEventListener(me, 'resize', listener);
				listeners.resize = listener;
			}
		},

		/**
		 * @private
		 */
		unbindEvents: function() {
			var me = this;
			var listeners = me._listeners;
			if (!listeners) {
				return;
			}

			delete me._listeners;
			helpers.each(listeners, function(listener, type) {
				platform.removeEventListener(me, type, listener);
			});
		},

		updateHoverStyle: function(elements, mode, enabled) {
			var method = enabled? 'setHoverStyle' : 'removeHoverStyle';
			var element, i, ilen;

			for (i=0, ilen=elements.length; i<ilen; ++i) {
				element = elements[i];
				if (element) {
					this.getDatasetMeta(element._datasetIndex).controller[method](element);
				}
			}
		},

		/**
		 * @private
		 */
		eventHandler: function(e) {
			var me = this;
			var tooltip = me.tooltip;

			if (plugins.notify(me, 'beforeEvent', [e]) === false) {
				return;
			}

			// Buffer any update calls so that renders do not occur
			me._bufferedRender = true;
			me._bufferedRequest = null;

			var changed = me.handleEvent(e);
			changed |= tooltip && tooltip.handleEvent(e);

			plugins.notify(me, 'afterEvent', [e]);

			var bufferedRequest = me._bufferedRequest;
			if (bufferedRequest) {
				// If we have an update that was triggered, we need to do a normal render
				me.render(bufferedRequest.duration, bufferedRequest.lazy);
			} else if (changed && !me.animating) {
				// If entering, leaving, or changing elements, animate the change via pivot
				me.stop();

				// We only need to render at this point. Updating will cause scales to be
				// recomputed generating flicker & using more memory than necessary.
				me.render(me.options.hover.animationDuration, true);
			}

			me._bufferedRender = false;
			me._bufferedRequest = null;

			return me;
		},

		/**
		 * Handle an event
		 * @private
		 * @param {IEvent} event the event to handle
		 * @return {Boolean} true if the chart needs to re-render
		 */
		handleEvent: function(e) {
			var me = this;
			var options = me.options || {};
			var hoverOptions = options.hover;
			var changed = false;

			me.lastActive = me.lastActive || [];

			// Find Active Elements for hover and tooltips
			if (e.type === 'mouseout') {
				me.active = [];
			} else {
				me.active = me.getElementsAtEventForMode(e, hoverOptions.mode, hoverOptions);
			}

			// On Hover hook
			if (hoverOptions.onHover) {
				// Need to call with native event here to not break backwards compatibility
				hoverOptions.onHover.call(me, e.native, me.active);
			}

			if (e.type === 'mouseup' || e.type === 'click') {
				if (options.onClick) {
					// Use e.native here for backwards compatibility
					options.onClick.call(me, e.native, me.active);
				}
			}

			// Remove styling for last active (even if it may still be active)
			if (me.lastActive.length) {
				me.updateHoverStyle(me.lastActive, hoverOptions.mode, false);
			}

			// Built in hover styling
			if (me.active.length && hoverOptions.mode) {
				me.updateHoverStyle(me.active, hoverOptions.mode, true);
			}

			changed = !helpers.arrayEquals(me.active, me.lastActive);

			// Remember Last Actives
			me.lastActive = me.active;

			return changed;
		}
	});

	/**
	 * Provided for backward compatibility, use Chart instead.
	 * @class Chart.Controller
	 * @deprecated since version 2.6.0
	 * @todo remove at version 3
	 * @private
	 */
	Chart.Controller = Chart;
};

},{}],24:[function(require,module,exports){
'use strict';

module.exports = function(Chart) {

	var helpers = Chart.helpers;

	var arrayEvents = ['push', 'pop', 'shift', 'splice', 'unshift'];

	/**
	 * Hooks the array methods that add or remove values ('push', pop', 'shift', 'splice',
	 * 'unshift') and notify the listener AFTER the array has been altered. Listeners are
	 * called on the 'onData*' callbacks (e.g. onDataPush, etc.) with same arguments.
	 */
	function listenArrayEvents(array, listener) {
		if (array._chartjs) {
			array._chartjs.listeners.push(listener);
			return;
		}

		Object.defineProperty(array, '_chartjs', {
			configurable: true,
			enumerable: false,
			value: {
				listeners: [listener]
			}
		});

		arrayEvents.forEach(function(key) {
			var method = 'onData' + key.charAt(0).toUpperCase() + key.slice(1);
			var base = array[key];

			Object.defineProperty(array, key, {
				configurable: true,
				enumerable: false,
				value: function() {
					var args = Array.prototype.slice.call(arguments);
					var res = base.apply(this, args);

					helpers.each(array._chartjs.listeners, function(object) {
						if (typeof object[method] === 'function') {
							object[method].apply(object, args);
						}
					});

					return res;
				}
			});
		});
	}

	/**
	 * Removes the given array event listener and cleanup extra attached properties (such as
	 * the _chartjs stub and overridden methods) if array doesn't have any more listeners.
	 */
	function unlistenArrayEvents(array, listener) {
		var stub = array._chartjs;
		if (!stub) {
			return;
		}

		var listeners = stub.listeners;
		var index = listeners.indexOf(listener);
		if (index !== -1) {
			listeners.splice(index, 1);
		}

		if (listeners.length > 0) {
			return;
		}

		arrayEvents.forEach(function(key) {
			delete array[key];
		});

		delete array._chartjs;
	}

	// Base class for all dataset controllers (line, bar, etc)
	Chart.DatasetController = function(chart, datasetIndex) {
		this.initialize(chart, datasetIndex);
	};

	helpers.extend(Chart.DatasetController.prototype, {

		/**
		 * Element type used to generate a meta dataset (e.g. Chart.element.Line).
		 * @type {Chart.core.element}
		 */
		datasetElementType: null,

		/**
		 * Element type used to generate a meta data (e.g. Chart.element.Point).
		 * @type {Chart.core.element}
		 */
		dataElementType: null,

		initialize: function(chart, datasetIndex) {
			var me = this;
			me.chart = chart;
			me.index = datasetIndex;
			me.linkScales();
			me.addElements();
		},

		updateIndex: function(datasetIndex) {
			this.index = datasetIndex;
		},

		linkScales: function() {
			var me = this;
			var meta = me.getMeta();
			var dataset = me.getDataset();

			if (meta.xAxisID === null) {
				meta.xAxisID = dataset.xAxisID || me.chart.options.scales.xAxes[0].id;
			}
			if (meta.yAxisID === null) {
				meta.yAxisID = dataset.yAxisID || me.chart.options.scales.yAxes[0].id;
			}
		},

		getDataset: function() {
			return this.chart.data.datasets[this.index];
		},

		getMeta: function() {
			return this.chart.getDatasetMeta(this.index);
		},

		getScaleForId: function(scaleID) {
			return this.chart.scales[scaleID];
		},

		reset: function() {
			this.update(true);
		},

		/**
		 * @private
		 */
		destroy: function() {
			if (this._data) {
				unlistenArrayEvents(this._data, this);
			}
		},

		createMetaDataset: function() {
			var me = this;
			var type = me.datasetElementType;
			return type && new type({
				_chart: me.chart,
				_datasetIndex: me.index
			});
		},

		createMetaData: function(index) {
			var me = this;
			var type = me.dataElementType;
			return type && new type({
				_chart: me.chart,
				_datasetIndex: me.index,
				_index: index
			});
		},

		addElements: function() {
			var me = this;
			var meta = me.getMeta();
			var data = me.getDataset().data || [];
			var metaData = meta.data;
			var i, ilen;

			for (i=0, ilen=data.length; i<ilen; ++i) {
				metaData[i] = metaData[i] || me.createMetaData(i);
			}

			meta.dataset = meta.dataset || me.createMetaDataset();
		},

		addElementAndReset: function(index) {
			var element = this.createMetaData(index);
			this.getMeta().data.splice(index, 0, element);
			this.updateElement(element, index, true);
		},

		buildOrUpdateElements: function() {
			var me = this;
			var dataset = me.getDataset();
			var data = dataset.data || (dataset.data = []);

			// In order to correctly handle data addition/deletion animation (an thus simulate
			// real-time charts), we need to monitor these data modifications and synchronize
			// the internal meta data accordingly.
			if (me._data !== data) {
				if (me._data) {
					// This case happens when the user replaced the data array instance.
					unlistenArrayEvents(me._data, me);
				}

				listenArrayEvents(data, me);
				me._data = data;
			}

			// Re-sync meta data in case the user replaced the data array or if we missed
			// any updates and so make sure that we handle number of datapoints changing.
			me.resyncElements();
		},

		update: helpers.noop,

		transition: function(easingValue) {
			var meta = this.getMeta();
			var elements = meta.data || [];
			var ilen = elements.length;
			var i = 0;

			for (; i<ilen; ++i) {
				elements[i].transition(easingValue);
			}

			if (meta.dataset) {
				meta.dataset.transition(easingValue);
			}
		},

		draw: function() {
			var meta = this.getMeta();
			var elements = meta.data || [];
			var ilen = elements.length;
			var i = 0;

			if (meta.dataset) {
				meta.dataset.draw();
			}

			for (; i<ilen; ++i) {
				elements[i].draw();
			}
		},

		removeHoverStyle: function(element, elementOpts) {
			var dataset = this.chart.data.datasets[element._datasetIndex],
				index = element._index,
				custom = element.custom || {},
				valueOrDefault = helpers.getValueAtIndexOrDefault,
				model = element._model;

			model.backgroundColor = custom.backgroundColor ? custom.backgroundColor : valueOrDefault(dataset.backgroundColor, index, elementOpts.backgroundColor);
			model.borderColor = custom.borderColor ? custom.borderColor : valueOrDefault(dataset.borderColor, index, elementOpts.borderColor);
			model.borderWidth = custom.borderWidth ? custom.borderWidth : valueOrDefault(dataset.borderWidth, index, elementOpts.borderWidth);
		},

		setHoverStyle: function(element) {
			var dataset = this.chart.data.datasets[element._datasetIndex],
				index = element._index,
				custom = element.custom || {},
				valueOrDefault = helpers.getValueAtIndexOrDefault,
				getHoverColor = helpers.getHoverColor,
				model = element._model;

			model.backgroundColor = custom.hoverBackgroundColor ? custom.hoverBackgroundColor : valueOrDefault(dataset.hoverBackgroundColor, index, getHoverColor(model.backgroundColor));
			model.borderColor = custom.hoverBorderColor ? custom.hoverBorderColor : valueOrDefault(dataset.hoverBorderColor, index, getHoverColor(model.borderColor));
			model.borderWidth = custom.hoverBorderWidth ? custom.hoverBorderWidth : valueOrDefault(dataset.hoverBorderWidth, index, model.borderWidth);
		},

		/**
		 * @private
		 */
		resyncElements: function() {
			var me = this;
			var meta = me.getMeta();
			var data = me.getDataset().data;
			var numMeta = meta.data.length;
			var numData = data.length;

			if (numData < numMeta) {
				meta.data.splice(numData, numMeta - numData);
			} else if (numData > numMeta) {
				me.insertElements(numMeta, numData - numMeta);
			}
		},

		/**
		 * @private
		 */
		insertElements: function(start, count) {
			for (var i=0; i<count; ++i) {
				this.addElementAndReset(start + i);
			}
		},

		/**
		 * @private
		 */
		onDataPush: function() {
			this.insertElements(this.getDataset().data.length-1, arguments.length);
		},

		/**
		 * @private
		 */
		onDataPop: function() {
			this.getMeta().data.pop();
		},

		/**
		 * @private
		 */
		onDataShift: function() {
			this.getMeta().data.shift();
		},

		/**
		 * @private
		 */
		onDataSplice: function(start, count) {
			this.getMeta().data.splice(start, count);
			this.insertElements(start, arguments.length - 2);
		},

		/**
		 * @private
		 */
		onDataUnshift: function() {
			this.insertElements(0, arguments.length);
		}
	});

	Chart.DatasetController.extend = helpers.inherits;
};

},{}],25:[function(require,module,exports){
'use strict';

var color = require(3);

module.exports = function(Chart) {

	var helpers = Chart.helpers;

	function interpolate(start, view, model, ease) {
		var keys = Object.keys(model);
		var i, ilen, key, actual, origin, target, type, c0, c1;

		for (i=0, ilen=keys.length; i<ilen; ++i) {
			key = keys[i];

			target = model[key];

			// if a value is added to the model after pivot() has been called, the view
			// doesn't contain it, so let's initialize the view to the target value.
			if (!view.hasOwnProperty(key)) {
				view[key] = target;
			}

			actual = view[key];

			if (actual === target || key[0] === '_') {
				continue;
			}

			if (!start.hasOwnProperty(key)) {
				start[key] = actual;
			}

			origin = start[key];

			type = typeof(target);

			if (type === typeof(origin)) {
				if (type === 'string') {
					c0 = color(origin);
					if (c0.valid) {
						c1 = color(target);
						if (c1.valid) {
							view[key] = c1.mix(c0, ease).rgbString();
							continue;
						}
					}
				} else if (type === 'number' && isFinite(origin) && isFinite(target)) {
					view[key] = origin + (target - origin) * ease;
					continue;
				}
			}

			view[key] = target;
		}
	}

	Chart.elements = {};

	Chart.Element = function(configuration) {
		helpers.extend(this, configuration);
		this.initialize.apply(this, arguments);
	};

	helpers.extend(Chart.Element.prototype, {

		initialize: function() {
			this.hidden = false;
		},

		pivot: function() {
			var me = this;
			if (!me._view) {
				me._view = helpers.clone(me._model);
			}
			me._start = {};
			return me;
		},

		transition: function(ease) {
			var me = this;
			var model = me._model;
			var start = me._start;
			var view = me._view;

			// No animation -> No Transition
			if (!model || ease === 1) {
				me._view = model;
				me._start = null;
				return me;
			}

			if (!view) {
				view = me._view = {};
			}

			if (!start) {
				start = me._start = {};
			}

			interpolate(start, view, model, ease);

			return me;
		},

		tooltipPosition: function() {
			return {
				x: this._model.x,
				y: this._model.y
			};
		},

		hasValue: function() {
			return helpers.isNumber(this._model.x) && helpers.isNumber(this._model.y);
		}
	});

	Chart.Element.extend = helpers.inherits;
};

},{"3":3}],26:[function(require,module,exports){
/* global window: false */
/* global document: false */
'use strict';

var color = require(3);

module.exports = function(Chart) {
	// Global Chart helpers object for utility methods and classes
	var helpers = Chart.helpers = {};

	// -- Basic js utility methods
	helpers.each = function(loopable, callback, self, reverse) {
		// Check to see if null or undefined firstly.
		var i, len;
		if (helpers.isArray(loopable)) {
			len = loopable.length;
			if (reverse) {
				for (i = len - 1; i >= 0; i--) {
					callback.call(self, loopable[i], i);
				}
			} else {
				for (i = 0; i < len; i++) {
					callback.call(self, loopable[i], i);
				}
			}
		} else if (typeof loopable === 'object') {
			var keys = Object.keys(loopable);
			len = keys.length;
			for (i = 0; i < len; i++) {
				callback.call(self, loopable[keys[i]], keys[i]);
			}
		}
	};
	helpers.clone = function(obj) {
		var objClone = {};
		helpers.each(obj, function(value, key) {
			if (helpers.isArray(value)) {
				objClone[key] = value.slice(0);
			} else if (typeof value === 'object' && value !== null) {
				objClone[key] = helpers.clone(value);
			} else {
				objClone[key] = value;
			}
		});
		return objClone;
	};
	helpers.extend = function(base) {
		var setFn = function(value, key) {
			base[key] = value;
		};
		for (var i = 1, ilen = arguments.length; i < ilen; i++) {
			helpers.each(arguments[i], setFn);
		}
		return base;
	};
	// Need a special merge function to chart configs since they are now grouped
	helpers.configMerge = function(_base) {
		var base = helpers.clone(_base);
		helpers.each(Array.prototype.slice.call(arguments, 1), function(extension) {
			helpers.each(extension, function(value, key) {
				var baseHasProperty = base.hasOwnProperty(key);
				var baseVal = baseHasProperty ? base[key] : {};

				if (key === 'scales') {
					// Scale config merging is complex. Add our own function here for that
					base[key] = helpers.scaleMerge(baseVal, value);
				} else if (key === 'scale') {
					// Used in polar area & radar charts since there is only one scale
					base[key] = helpers.configMerge(baseVal, Chart.scaleService.getScaleDefaults(value.type), value);
				} else if (baseHasProperty
						&& typeof baseVal === 'object'
						&& !helpers.isArray(baseVal)
						&& baseVal !== null
						&& typeof value === 'object'
						&& !helpers.isArray(value)) {
					// If we are overwriting an object with an object, do a merge of the properties.
					base[key] = helpers.configMerge(baseVal, value);
				} else {
					// can just overwrite the value in this case
					base[key] = value;
				}
			});
		});

		return base;
	};
	helpers.scaleMerge = function(_base, extension) {
		var base = helpers.clone(_base);

		helpers.each(extension, function(value, key) {
			if (key === 'xAxes' || key === 'yAxes') {
				// These properties are arrays of items
				if (base.hasOwnProperty(key)) {
					helpers.each(value, function(valueObj, index) {
						var axisType = helpers.getValueOrDefault(valueObj.type, key === 'xAxes' ? 'category' : 'linear');
						var axisDefaults = Chart.scaleService.getScaleDefaults(axisType);
						if (index >= base[key].length || !base[key][index].type) {
							base[key].push(helpers.configMerge(axisDefaults, valueObj));
						} else if (valueObj.type && valueObj.type !== base[key][index].type) {
							// Type changed. Bring in the new defaults before we bring in valueObj so that valueObj can override the correct scale defaults
							base[key][index] = helpers.configMerge(base[key][index], axisDefaults, valueObj);
						} else {
							// Type is the same
							base[key][index] = helpers.configMerge(base[key][index], valueObj);
						}
					});
				} else {
					base[key] = [];
					helpers.each(value, function(valueObj) {
						var axisType = helpers.getValueOrDefault(valueObj.type, key === 'xAxes' ? 'category' : 'linear');
						base[key].push(helpers.configMerge(Chart.scaleService.getScaleDefaults(axisType), valueObj));
					});
				}
			} else if (base.hasOwnProperty(key) && typeof base[key] === 'object' && base[key] !== null && typeof value === 'object') {
				// If we are overwriting an object with an object, do a merge of the properties.
				base[key] = helpers.configMerge(base[key], value);

			} else {
				// can just overwrite the value in this case
				base[key] = value;
			}
		});

		return base;
	};
	helpers.getValueAtIndexOrDefault = function(value, index, defaultValue) {
		if (value === undefined || value === null) {
			return defaultValue;
		}

		if (helpers.isArray(value)) {
			return index < value.length ? value[index] : defaultValue;
		}

		return value;
	};
	helpers.getValueOrDefault = function(value, defaultValue) {
		return value === undefined ? defaultValue : value;
	};
	helpers.indexOf = Array.prototype.indexOf?
		function(array, item) {
			return array.indexOf(item);
		}:
		function(array, item) {
			for (var i = 0, ilen = array.length; i < ilen; ++i) {
				if (array[i] === item) {
					return i;
				}
			}
			return -1;
		};
	helpers.where = function(collection, filterCallback) {
		if (helpers.isArray(collection) && Array.prototype.filter) {
			return collection.filter(filterCallback);
		}
		var filtered = [];

		helpers.each(collection, function(item) {
			if (filterCallback(item)) {
				filtered.push(item);
			}
		});

		return filtered;
	};
	helpers.findIndex = Array.prototype.findIndex?
		function(array, callback, scope) {
			return array.findIndex(callback, scope);
		} :
		function(array, callback, scope) {
			scope = scope === undefined? array : scope;
			for (var i = 0, ilen = array.length; i < ilen; ++i) {
				if (callback.call(scope, array[i], i, array)) {
					return i;
				}
			}
			return -1;
		};
	helpers.findNextWhere = function(arrayToSearch, filterCallback, startIndex) {
		// Default to start of the array
		if (startIndex === undefined || startIndex === null) {
			startIndex = -1;
		}
		for (var i = startIndex + 1; i < arrayToSearch.length; i++) {
			var currentItem = arrayToSearch[i];
			if (filterCallback(currentItem)) {
				return currentItem;
			}
		}
	};
	helpers.findPreviousWhere = function(arrayToSearch, filterCallback, startIndex) {
		// Default to end of the array
		if (startIndex === undefined || startIndex === null) {
			startIndex = arrayToSearch.length;
		}
		for (var i = startIndex - 1; i >= 0; i--) {
			var currentItem = arrayToSearch[i];
			if (filterCallback(currentItem)) {
				return currentItem;
			}
		}
	};
	helpers.inherits = function(extensions) {
		// Basic javascript inheritance based on the model created in Backbone.js
		var me = this;
		var ChartElement = (extensions && extensions.hasOwnProperty('constructor')) ? extensions.constructor : function() {
			return me.apply(this, arguments);
		};

		var Surrogate = function() {
			this.constructor = ChartElement;
		};
		Surrogate.prototype = me.prototype;
		ChartElement.prototype = new Surrogate();

		ChartElement.extend = helpers.inherits;

		if (extensions) {
			helpers.extend(ChartElement.prototype, extensions);
		}

		ChartElement.__super__ = me.prototype;

		return ChartElement;
	};
	helpers.noop = function() {};
	helpers.uid = (function() {
		var id = 0;
		return function() {
			return id++;
		};
	}());
	// -- Math methods
	helpers.isNumber = function(n) {
		return !isNaN(parseFloat(n)) && isFinite(n);
	};
	helpers.almostEquals = function(x, y, epsilon) {
		return Math.abs(x - y) < epsilon;
	};
	helpers.almostWhole = function(x, epsilon) {
		var rounded = Math.round(x);
		return (((rounded - epsilon) < x) && ((rounded + epsilon) > x));
	};
	helpers.max = function(array) {
		return array.reduce(function(max, value) {
			if (!isNaN(value)) {
				return Math.max(max, value);
			}
			return max;
		}, Number.NEGATIVE_INFINITY);
	};
	helpers.min = function(array) {
		return array.reduce(function(min, value) {
			if (!isNaN(value)) {
				return Math.min(min, value);
			}
			return min;
		}, Number.POSITIVE_INFINITY);
	};
	helpers.sign = Math.sign?
		function(x) {
			return Math.sign(x);
		} :
		function(x) {
			x = +x; // convert to a number
			if (x === 0 || isNaN(x)) {
				return x;
			}
			return x > 0 ? 1 : -1;
		};
	helpers.log10 = Math.log10?
		function(x) {
			return Math.log10(x);
		} :
		function(x) {
			return Math.log(x) / Math.LN10;
		};
	helpers.toRadians = function(degrees) {
		return degrees * (Math.PI / 180);
	};
	helpers.toDegrees = function(radians) {
		return radians * (180 / Math.PI);
	};
	// Gets the angle from vertical upright to the point about a centre.
	helpers.getAngleFromPoint = function(centrePoint, anglePoint) {
		var distanceFromXCenter = anglePoint.x - centrePoint.x,
			distanceFromYCenter = anglePoint.y - centrePoint.y,
			radialDistanceFromCenter = Math.sqrt(distanceFromXCenter * distanceFromXCenter + distanceFromYCenter * distanceFromYCenter);

		var angle = Math.atan2(distanceFromYCenter, distanceFromXCenter);

		if (angle < (-0.5 * Math.PI)) {
			angle += 2.0 * Math.PI; // make sure the returned angle is in the range of (-PI/2, 3PI/2]
		}

		return {
			angle: angle,
			distance: radialDistanceFromCenter
		};
	};
	helpers.distanceBetweenPoints = function(pt1, pt2) {
		return Math.sqrt(Math.pow(pt2.x - pt1.x, 2) + Math.pow(pt2.y - pt1.y, 2));
	};
	helpers.aliasPixel = function(pixelWidth) {
		return (pixelWidth % 2 === 0) ? 0 : 0.5;
	};
	helpers.splineCurve = function(firstPoint, middlePoint, afterPoint, t) {
		// Props to Rob Spencer at scaled innovation for his post on splining between points
		// http://scaledinnovation.com/analytics/splines/aboutSplines.html

		// This function must also respect "skipped" points

		var previous = firstPoint.skip ? middlePoint : firstPoint,
			current = middlePoint,
			next = afterPoint.skip ? middlePoint : afterPoint;

		var d01 = Math.sqrt(Math.pow(current.x - previous.x, 2) + Math.pow(current.y - previous.y, 2));
		var d12 = Math.sqrt(Math.pow(next.x - current.x, 2) + Math.pow(next.y - current.y, 2));

		var s01 = d01 / (d01 + d12);
		var s12 = d12 / (d01 + d12);

		// If all points are the same, s01 & s02 will be inf
		s01 = isNaN(s01) ? 0 : s01;
		s12 = isNaN(s12) ? 0 : s12;

		var fa = t * s01; // scaling factor for triangle Ta
		var fb = t * s12;

		return {
			previous: {
				x: current.x - fa * (next.x - previous.x),
				y: current.y - fa * (next.y - previous.y)
			},
			next: {
				x: current.x + fb * (next.x - previous.x),
				y: current.y + fb * (next.y - previous.y)
			}
		};
	};
	helpers.EPSILON = Number.EPSILON || 1e-14;
	helpers.splineCurveMonotone = function(points) {
		// This function calculates Bézier control points in a similar way than |splineCurve|,
		// but preserves monotonicity of the provided data and ensures no local extremums are added
		// between the dataset discrete points due to the interpolation.
		// See : https://en.wikipedia.org/wiki/Monotone_cubic_interpolation

		var pointsWithTangents = (points || []).map(function(point) {
			return {
				model: point._model,
				deltaK: 0,
				mK: 0
			};
		});

		// Calculate slopes (deltaK) and initialize tangents (mK)
		var pointsLen = pointsWithTangents.length;
		var i, pointBefore, pointCurrent, pointAfter;
		for (i = 0; i < pointsLen; ++i) {
			pointCurrent = pointsWithTangents[i];
			if (pointCurrent.model.skip) {
				continue;
			}

			pointBefore = i > 0 ? pointsWithTangents[i - 1] : null;
			pointAfter = i < pointsLen - 1 ? pointsWithTangents[i + 1] : null;
			if (pointAfter && !pointAfter.model.skip) {
				var slopeDeltaX = (pointAfter.model.x - pointCurrent.model.x);

				// In the case of two points that appear at the same x pixel, slopeDeltaX is 0
				pointCurrent.deltaK = slopeDeltaX !== 0 ? (pointAfter.model.y - pointCurrent.model.y) / slopeDeltaX : 0;
			}

			if (!pointBefore || pointBefore.model.skip) {
				pointCurrent.mK = pointCurrent.deltaK;
			} else if (!pointAfter || pointAfter.model.skip) {
				pointCurrent.mK = pointBefore.deltaK;
			} else if (this.sign(pointBefore.deltaK) !== this.sign(pointCurrent.deltaK)) {
				pointCurrent.mK = 0;
			} else {
				pointCurrent.mK = (pointBefore.deltaK + pointCurrent.deltaK) / 2;
			}
		}

		// Adjust tangents to ensure monotonic properties
		var alphaK, betaK, tauK, squaredMagnitude;
		for (i = 0; i < pointsLen - 1; ++i) {
			pointCurrent = pointsWithTangents[i];
			pointAfter = pointsWithTangents[i + 1];
			if (pointCurrent.model.skip || pointAfter.model.skip) {
				continue;
			}

			if (helpers.almostEquals(pointCurrent.deltaK, 0, this.EPSILON)) {
				pointCurrent.mK = pointAfter.mK = 0;
				continue;
			}

			alphaK = pointCurrent.mK / pointCurrent.deltaK;
			betaK = pointAfter.mK / pointCurrent.deltaK;
			squaredMagnitude = Math.pow(alphaK, 2) + Math.pow(betaK, 2);
			if (squaredMagnitude <= 9) {
				continue;
			}

			tauK = 3 / Math.sqrt(squaredMagnitude);
			pointCurrent.mK = alphaK * tauK * pointCurrent.deltaK;
			pointAfter.mK = betaK * tauK * pointCurrent.deltaK;
		}

		// Compute control points
		var deltaX;
		for (i = 0; i < pointsLen; ++i) {
			pointCurrent = pointsWithTangents[i];
			if (pointCurrent.model.skip) {
				continue;
			}

			pointBefore = i > 0 ? pointsWithTangents[i - 1] : null;
			pointAfter = i < pointsLen - 1 ? pointsWithTangents[i + 1] : null;
			if (pointBefore && !pointBefore.model.skip) {
				deltaX = (pointCurrent.model.x - pointBefore.model.x) / 3;
				pointCurrent.model.controlPointPreviousX = pointCurrent.model.x - deltaX;
				pointCurrent.model.controlPointPreviousY = pointCurrent.model.y - deltaX * pointCurrent.mK;
			}
			if (pointAfter && !pointAfter.model.skip) {
				deltaX = (pointAfter.model.x - pointCurrent.model.x) / 3;
				pointCurrent.model.controlPointNextX = pointCurrent.model.x + deltaX;
				pointCurrent.model.controlPointNextY = pointCurrent.model.y + deltaX * pointCurrent.mK;
			}
		}
	};
	helpers.nextItem = function(collection, index, loop) {
		if (loop) {
			return index >= collection.length - 1 ? collection[0] : collection[index + 1];
		}
		return index >= collection.length - 1 ? collection[collection.length - 1] : collection[index + 1];
	};
	helpers.previousItem = function(collection, index, loop) {
		if (loop) {
			return index <= 0 ? collection[collection.length - 1] : collection[index - 1];
		}
		return index <= 0 ? collection[0] : collection[index - 1];
	};
	// Implementation of the nice number algorithm used in determining where axis labels will go
	helpers.niceNum = function(range, round) {
		var exponent = Math.floor(helpers.log10(range));
		var fraction = range / Math.pow(10, exponent);
		var niceFraction;

		if (round) {
			if (fraction < 1.5) {
				niceFraction = 1;
			} else if (fraction < 3) {
				niceFraction = 2;
			} else if (fraction < 7) {
				niceFraction = 5;
			} else {
				niceFraction = 10;
			}
		} else if (fraction <= 1.0) {
			niceFraction = 1;
		} else if (fraction <= 2) {
			niceFraction = 2;
		} else if (fraction <= 5) {
			niceFraction = 5;
		} else {
			niceFraction = 10;
		}

		return niceFraction * Math.pow(10, exponent);
	};
	// Easing functions adapted from Robert Penner's easing equations
	// http://www.robertpenner.com/easing/
	var easingEffects = helpers.easingEffects = {
		linear: function(t) {
			return t;
		},
		easeInQuad: function(t) {
			return t * t;
		},
		easeOutQuad: function(t) {
			return -1 * t * (t - 2);
		},
		easeInOutQuad: function(t) {
			if ((t /= 1 / 2) < 1) {
				return 1 / 2 * t * t;
			}
			return -1 / 2 * ((--t) * (t - 2) - 1);
		},
		easeInCubic: function(t) {
			return t * t * t;
		},
		easeOutCubic: function(t) {
			return 1 * ((t = t / 1 - 1) * t * t + 1);
		},
		easeInOutCubic: function(t) {
			if ((t /= 1 / 2) < 1) {
				return 1 / 2 * t * t * t;
			}
			return 1 / 2 * ((t -= 2) * t * t + 2);
		},
		easeInQuart: function(t) {
			return t * t * t * t;
		},
		easeOutQuart: function(t) {
			return -1 * ((t = t / 1 - 1) * t * t * t - 1);
		},
		easeInOutQuart: function(t) {
			if ((t /= 1 / 2) < 1) {
				return 1 / 2 * t * t * t * t;
			}
			return -1 / 2 * ((t -= 2) * t * t * t - 2);
		},
		easeInQuint: function(t) {
			return 1 * (t /= 1) * t * t * t * t;
		},
		easeOutQuint: function(t) {
			return 1 * ((t = t / 1 - 1) * t * t * t * t + 1);
		},
		easeInOutQuint: function(t) {
			if ((t /= 1 / 2) < 1) {
				return 1 / 2 * t * t * t * t * t;
			}
			return 1 / 2 * ((t -= 2) * t * t * t * t + 2);
		},
		easeInSine: function(t) {
			return -1 * Math.cos(t / 1 * (Math.PI / 2)) + 1;
		},
		easeOutSine: function(t) {
			return 1 * Math.sin(t / 1 * (Math.PI / 2));
		},
		easeInOutSine: function(t) {
			return -1 / 2 * (Math.cos(Math.PI * t / 1) - 1);
		},
		easeInExpo: function(t) {
			return (t === 0) ? 1 : 1 * Math.pow(2, 10 * (t / 1 - 1));
		},
		easeOutExpo: function(t) {
			return (t === 1) ? 1 : 1 * (-Math.pow(2, -10 * t / 1) + 1);
		},
		easeInOutExpo: function(t) {
			if (t === 0) {
				return 0;
			}
			if (t === 1) {
				return 1;
			}
			if ((t /= 1 / 2) < 1) {
				return 1 / 2 * Math.pow(2, 10 * (t - 1));
			}
			return 1 / 2 * (-Math.pow(2, -10 * --t) + 2);
		},
		easeInCirc: function(t) {
			if (t >= 1) {
				return t;
			}
			return -1 * (Math.sqrt(1 - (t /= 1) * t) - 1);
		},
		easeOutCirc: function(t) {
			return 1 * Math.sqrt(1 - (t = t / 1 - 1) * t);
		},
		easeInOutCirc: function(t) {
			if ((t /= 1 / 2) < 1) {
				return -1 / 2 * (Math.sqrt(1 - t * t) - 1);
			}
			return 1 / 2 * (Math.sqrt(1 - (t -= 2) * t) + 1);
		},
		easeInElastic: function(t) {
			var s = 1.70158;
			var p = 0;
			var a = 1;
			if (t === 0) {
				return 0;
			}
			if ((t /= 1) === 1) {
				return 1;
			}
			if (!p) {
				p = 1 * 0.3;
			}
			if (a < Math.abs(1)) {
				a = 1;
				s = p / 4;
			} else {
				s = p / (2 * Math.PI) * Math.asin(1 / a);
			}
			return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * 1 - s) * (2 * Math.PI) / p));
		},
		easeOutElastic: function(t) {
			var s = 1.70158;
			var p = 0;
			var a = 1;
			if (t === 0) {
				return 0;
			}
			if ((t /= 1) === 1) {
				return 1;
			}
			if (!p) {
				p = 1 * 0.3;
			}
			if (a < Math.abs(1)) {
				a = 1;
				s = p / 4;
			} else {
				s = p / (2 * Math.PI) * Math.asin(1 / a);
			}
			return a * Math.pow(2, -10 * t) * Math.sin((t * 1 - s) * (2 * Math.PI) / p) + 1;
		},
		easeInOutElastic: function(t) {
			var s = 1.70158;
			var p = 0;
			var a = 1;
			if (t === 0) {
				return 0;
			}
			if ((t /= 1 / 2) === 2) {
				return 1;
			}
			if (!p) {
				p = 1 * (0.3 * 1.5);
			}
			if (a < Math.abs(1)) {
				a = 1;
				s = p / 4;
			} else {
				s = p / (2 * Math.PI) * Math.asin(1 / a);
			}
			if (t < 1) {
				return -0.5 * (a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * 1 - s) * (2 * Math.PI) / p));
			}
			return a * Math.pow(2, -10 * (t -= 1)) * Math.sin((t * 1 - s) * (2 * Math.PI) / p) * 0.5 + 1;
		},
		easeInBack: function(t) {
			var s = 1.70158;
			return 1 * (t /= 1) * t * ((s + 1) * t - s);
		},
		easeOutBack: function(t) {
			var s = 1.70158;
			return 1 * ((t = t / 1 - 1) * t * ((s + 1) * t + s) + 1);
		},
		easeInOutBack: function(t) {
			var s = 1.70158;
			if ((t /= 1 / 2) < 1) {
				return 1 / 2 * (t * t * (((s *= (1.525)) + 1) * t - s));
			}
			return 1 / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2);
		},
		easeInBounce: function(t) {
			return 1 - easingEffects.easeOutBounce(1 - t);
		},
		easeOutBounce: function(t) {
			if ((t /= 1) < (1 / 2.75)) {
				return 1 * (7.5625 * t * t);
			} else if (t < (2 / 2.75)) {
				return 1 * (7.5625 * (t -= (1.5 / 2.75)) * t + 0.75);
			} else if (t < (2.5 / 2.75)) {
				return 1 * (7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375);
			}
			return 1 * (7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375);
		},
		easeInOutBounce: function(t) {
			if (t < 1 / 2) {
				return easingEffects.easeInBounce(t * 2) * 0.5;
			}
			return easingEffects.easeOutBounce(t * 2 - 1) * 0.5 + 1 * 0.5;
		}
	};
	// Request animation polyfill - http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/
	helpers.requestAnimFrame = (function() {
		if (typeof window === 'undefined') {
			return function(callback) {
				callback();
			};
		}
		return window.requestAnimationFrame ||
			window.webkitRequestAnimationFrame ||
			window.mozRequestAnimationFrame ||
			window.oRequestAnimationFrame ||
			window.msRequestAnimationFrame ||
			function(callback) {
				return window.setTimeout(callback, 1000 / 60);
			};
	}());
	// -- DOM methods
	helpers.getRelativePosition = function(evt, chart) {
		var mouseX, mouseY;
		var e = evt.originalEvent || evt,
			canvas = evt.currentTarget || evt.srcElement,
			boundingRect = canvas.getBoundingClientRect();

		var touches = e.touches;
		if (touches && touches.length > 0) {
			mouseX = touches[0].clientX;
			mouseY = touches[0].clientY;

		} else {
			mouseX = e.clientX;
			mouseY = e.clientY;
		}

		// Scale mouse coordinates into canvas coordinates
		// by following the pattern laid out by 'jerryj' in the comments of
		// http://www.html5canvastutorials.com/advanced/html5-canvas-mouse-coordinates/
		var paddingLeft = parseFloat(helpers.getStyle(canvas, 'padding-left'));
		var paddingTop = parseFloat(helpers.getStyle(canvas, 'padding-top'));
		var paddingRight = parseFloat(helpers.getStyle(canvas, 'padding-right'));
		var paddingBottom = parseFloat(helpers.getStyle(canvas, 'padding-bottom'));
		var width = boundingRect.right - boundingRect.left - paddingLeft - paddingRight;
		var height = boundingRect.bottom - boundingRect.top - paddingTop - paddingBottom;

		// We divide by the current device pixel ratio, because the canvas is scaled up by that amount in each direction. However
		// the backend model is in unscaled coordinates. Since we are going to deal with our model coordinates, we go back here
		mouseX = Math.round((mouseX - boundingRect.left - paddingLeft) / (width) * canvas.width / chart.currentDevicePixelRatio);
		mouseY = Math.round((mouseY - boundingRect.top - paddingTop) / (height) * canvas.height / chart.currentDevicePixelRatio);

		return {
			x: mouseX,
			y: mouseY
		};

	};
	helpers.addEvent = function(node, eventType, method) {
		if (node.addEventListener) {
			node.addEventListener(eventType, method);
		} else if (node.attachEvent) {
			node.attachEvent('on' + eventType, method);
		} else {
			node['on' + eventType] = method;
		}
	};
	helpers.removeEvent = function(node, eventType, handler) {
		if (node.removeEventListener) {
			node.removeEventListener(eventType, handler, false);
		} else if (node.detachEvent) {
			node.detachEvent('on' + eventType, handler);
		} else {
			node['on' + eventType] = helpers.noop;
		}
	};

	// Private helper function to convert max-width/max-height values that may be percentages into a number
	function parseMaxStyle(styleValue, node, parentProperty) {
		var valueInPixels;
		if (typeof(styleValue) === 'string') {
			valueInPixels = parseInt(styleValue, 10);

			if (styleValue.indexOf('%') !== -1) {
				// percentage * size in dimension
				valueInPixels = valueInPixels / 100 * node.parentNode[parentProperty];
			}
		} else {
			valueInPixels = styleValue;
		}

		return valueInPixels;
	}

	/**
	 * Returns if the given value contains an effective constraint.
	 * @private
	 */
	function isConstrainedValue(value) {
		return value !== undefined && value !== null && value !== 'none';
	}

	// Private helper to get a constraint dimension
	// @param domNode : the node to check the constraint on
	// @param maxStyle : the style that defines the maximum for the direction we are using (maxWidth / maxHeight)
	// @param percentageProperty : property of parent to use when calculating width as a percentage
	// @see http://www.nathanaeljones.com/blog/2013/reading-max-width-cross-browser
	function getConstraintDimension(domNode, maxStyle, percentageProperty) {
		var view = document.defaultView;
		var parentNode = domNode.parentNode;
		var constrainedNode = view.getComputedStyle(domNode)[maxStyle];
		var constrainedContainer = view.getComputedStyle(parentNode)[maxStyle];
		var hasCNode = isConstrainedValue(constrainedNode);
		var hasCContainer = isConstrainedValue(constrainedContainer);
		var infinity = Number.POSITIVE_INFINITY;

		if (hasCNode || hasCContainer) {
			return Math.min(
				hasCNode? parseMaxStyle(constrainedNode, domNode, percentageProperty) : infinity,
				hasCContainer? parseMaxStyle(constrainedContainer, parentNode, percentageProperty) : infinity);
		}

		return 'none';
	}
	// returns Number or undefined if no constraint
	helpers.getConstraintWidth = function(domNode) {
		return getConstraintDimension(domNode, 'max-width', 'clientWidth');
	};
	// returns Number or undefined if no constraint
	helpers.getConstraintHeight = function(domNode) {
		return getConstraintDimension(domNode, 'max-height', 'clientHeight');
	};
	helpers.getMaximumWidth = function(domNode) {
		var container = domNode.parentNode;
		var paddingLeft = parseInt(helpers.getStyle(container, 'padding-left'), 10);
		var paddingRight = parseInt(helpers.getStyle(container, 'padding-right'), 10);
		var w = container.clientWidth - paddingLeft - paddingRight;
		var cw = helpers.getConstraintWidth(domNode);
		return isNaN(cw)? w : Math.min(w, cw);
	};
	helpers.getMaximumHeight = function(domNode) {
		var container = domNode.parentNode;
		var paddingTop = parseInt(helpers.getStyle(container, 'padding-top'), 10);
		var paddingBottom = parseInt(helpers.getStyle(container, 'padding-bottom'), 10);
		var h = container.clientHeight - paddingTop - paddingBottom;
		var ch = helpers.getConstraintHeight(domNode);
		return isNaN(ch)? h : Math.min(h, ch);
	};
	helpers.getStyle = function(el, property) {
		return el.currentStyle ?
			el.currentStyle[property] :
			document.defaultView.getComputedStyle(el, null).getPropertyValue(property);
	};
	helpers.retinaScale = function(chart) {
		var pixelRatio = chart.currentDevicePixelRatio = window.devicePixelRatio || 1;
		if (pixelRatio === 1) {
			return;
		}

		var canvas = chart.canvas;
		var height = chart.height;
		var width = chart.width;

		canvas.height = height * pixelRatio;
		canvas.width = width * pixelRatio;
		chart.ctx.scale(pixelRatio, pixelRatio);

		// If no style has been set on the canvas, the render size is used as display size,
		// making the chart visually bigger, so let's enforce it to the "correct" values.
		// See https://github.com/chartjs/Chart.js/issues/3575
		canvas.style.height = height + 'px';
		canvas.style.width = width + 'px';
	};
	// -- Canvas methods
	helpers.clear = function(chart) {
		chart.ctx.clearRect(0, 0, chart.width, chart.height);
	};
	helpers.fontString = function(pixelSize, fontStyle, fontFamily) {
		return fontStyle + ' ' + pixelSize + 'px ' + fontFamily;
	};
	helpers.longestText = function(ctx, font, arrayOfThings, cache) {
		cache = cache || {};
		var data = cache.data = cache.data || {};
		var gc = cache.garbageCollect = cache.garbageCollect || [];

		if (cache.font !== font) {
			data = cache.data = {};
			gc = cache.garbageCollect = [];
			cache.font = font;
		}

		ctx.font = font;
		var longest = 0;
		helpers.each(arrayOfThings, function(thing) {
			// Undefined strings and arrays should not be measured
			if (thing !== undefined && thing !== null && helpers.isArray(thing) !== true) {
				longest = helpers.measureText(ctx, data, gc, longest, thing);
			} else if (helpers.isArray(thing)) {
				// if it is an array lets measure each element
				// to do maybe simplify this function a bit so we can do this more recursively?
				helpers.each(thing, function(nestedThing) {
					// Undefined strings and arrays should not be measured
					if (nestedThing !== undefined && nestedThing !== null && !helpers.isArray(nestedThing)) {
						longest = helpers.measureText(ctx, data, gc, longest, nestedThing);
					}
				});
			}
		});

		var gcLen = gc.length / 2;
		if (gcLen > arrayOfThings.length) {
			for (var i = 0; i < gcLen; i++) {
				delete data[gc[i]];
			}
			gc.splice(0, gcLen);
		}
		return longest;
	};
	helpers.measureText = function(ctx, data, gc, longest, string) {
		var textWidth = data[string];
		if (!textWidth) {
			textWidth = data[string] = ctx.measureText(string).width;
			gc.push(string);
		}
		if (textWidth > longest) {
			longest = textWidth;
		}
		return longest;
	};
	helpers.numberOfLabelLines = function(arrayOfThings) {
		var numberOfLines = 1;
		helpers.each(arrayOfThings, function(thing) {
			if (helpers.isArray(thing)) {
				if (thing.length > numberOfLines) {
					numberOfLines = thing.length;
				}
			}
		});
		return numberOfLines;
	};
	helpers.drawRoundedRectangle = function(ctx, x, y, width, height, radius) {
		ctx.beginPath();
		ctx.moveTo(x + radius, y);
		ctx.lineTo(x + width - radius, y);
		ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
		ctx.lineTo(x + width, y + height - radius);
		ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
		ctx.lineTo(x + radius, y + height);
		ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
		ctx.lineTo(x, y + radius);
		ctx.quadraticCurveTo(x, y, x + radius, y);
		ctx.closePath();
	};

	helpers.color = !color?
		function(value) {
			console.error('Color.js not found!');
			return value;
		} :
		function(value) {
			/* global CanvasGradient */
			if (value instanceof CanvasGradient) {
				value = Chart.defaults.global.defaultColor;
			}

			return color(value);
		};

	helpers.isArray = Array.isArray?
		function(obj) {
			return Array.isArray(obj);
		} :
		function(obj) {
			return Object.prototype.toString.call(obj) === '[object Array]';
		};
	// ! @see http://stackoverflow.com/a/14853974
	helpers.arrayEquals = function(a0, a1) {
		var i, ilen, v0, v1;

		if (!a0 || !a1 || a0.length !== a1.length) {
			return false;
		}

		for (i = 0, ilen=a0.length; i < ilen; ++i) {
			v0 = a0[i];
			v1 = a1[i];

			if (v0 instanceof Array && v1 instanceof Array) {
				if (!helpers.arrayEquals(v0, v1)) {
					return false;
				}
			} else if (v0 !== v1) {
				// NOTE: two different object instances will never be equal: {x:20} != {x:20}
				return false;
			}
		}

		return true;
	};
	helpers.callback = function(fn, args, thisArg) {
		if (fn && typeof fn.call === 'function') {
			fn.apply(thisArg, args);
		}
	};
	helpers.getHoverColor = function(colorValue) {
		/* global CanvasPattern */
		return (colorValue instanceof CanvasPattern) ?
			colorValue :
			helpers.color(colorValue).saturate(0.5).darken(0.1).rgbString();
	};

	/**
	 * Provided for backward compatibility, use Chart.helpers#callback instead.
	 * @function Chart.helpers#callCallback
	 * @deprecated since version 2.6.0
	 * @todo remove at version 3
	 */
	helpers.callCallback = helpers.callback;
};

},{"3":3}],27:[function(require,module,exports){
'use strict';

module.exports = function(Chart) {
	var helpers = Chart.helpers;

	/**
	 * Helper function to get relative position for an event
	 * @param {Event|IEvent} event - The event to get the position for
	 * @param {Chart} chart - The chart
	 * @returns {Point} the event position
	 */
	function getRelativePosition(e, chart) {
		if (e.native) {
			return {
				x: e.x,
				y: e.y
			};
		}

		return helpers.getRelativePosition(e, chart);
	}

	/**
	 * Helper function to traverse all of the visible elements in the chart
	 * @param chart {chart} the chart
	 * @param handler {Function} the callback to execute for each visible item
	 */
	function parseVisibleItems(chart, handler) {
		var datasets = chart.data.datasets;
		var meta, i, j, ilen, jlen;

		for (i = 0, ilen = datasets.length; i < ilen; ++i) {
			if (!chart.isDatasetVisible(i)) {
				continue;
			}

			meta = chart.getDatasetMeta(i);
			for (j = 0, jlen = meta.data.length; j < jlen; ++j) {
				var element = meta.data[j];
				if (!element._view.skip) {
					handler(element);
				}
			}
		}
	}

	/**
	 * Helper function to get the items that intersect the event position
	 * @param items {ChartElement[]} elements to filter
	 * @param position {Point} the point to be nearest to
	 * @return {ChartElement[]} the nearest items
	 */
	function getIntersectItems(chart, position) {
		var elements = [];

		parseVisibleItems(chart, function(element) {
			if (element.inRange(position.x, position.y)) {
				elements.push(element);
			}
		});

		return elements;
	}

	/**
	 * Helper function to get the items nearest to the event position considering all visible items in teh chart
	 * @param chart {Chart} the chart to look at elements from
	 * @param position {Point} the point to be nearest to
	 * @param intersect {Boolean} if true, only consider items that intersect the position
	 * @param distanceMetric {Function} Optional function to provide the distance between
	 * @return {ChartElement[]} the nearest items
	 */
	function getNearestItems(chart, position, intersect, distanceMetric) {
		var minDistance = Number.POSITIVE_INFINITY;
		var nearestItems = [];

		if (!distanceMetric) {
			distanceMetric = helpers.distanceBetweenPoints;
		}

		parseVisibleItems(chart, function(element) {
			if (intersect && !element.inRange(position.x, position.y)) {
				return;
			}

			var center = element.getCenterPoint();
			var distance = distanceMetric(position, center);

			if (distance < minDistance) {
				nearestItems = [element];
				minDistance = distance;
			} else if (distance === minDistance) {
				// Can have multiple items at the same distance in which case we sort by size
				nearestItems.push(element);
			}
		});

		return nearestItems;
	}

	function indexMode(chart, e, options) {
		var position = getRelativePosition(e, chart);
		var distanceMetric = function(pt1, pt2) {
			return Math.abs(pt1.x - pt2.x);
		};
		var items = options.intersect ? getIntersectItems(chart, position) : getNearestItems(chart, position, false, distanceMetric);
		var elements = [];

		if (!items.length) {
			return [];
		}

		chart.data.datasets.forEach(function(dataset, datasetIndex) {
			if (chart.isDatasetVisible(datasetIndex)) {
				var meta = chart.getDatasetMeta(datasetIndex),
					element = meta.data[items[0]._index];

				// don't count items that are skipped (null data)
				if (element && !element._view.skip) {
					elements.push(element);
				}
			}
		});

		return elements;
	}

	/**
	 * @interface IInteractionOptions
	 */
	/**
	 * If true, only consider items that intersect the point
	 * @name IInterfaceOptions#boolean
	 * @type Boolean
	 */

	/**
	 * Contains interaction related functions
	 * @namespace Chart.Interaction
	 */
	Chart.Interaction = {
		// Helper function for different modes
		modes: {
			single: function(chart, e) {
				var position = getRelativePosition(e, chart);
				var elements = [];

				parseVisibleItems(chart, function(element) {
					if (element.inRange(position.x, position.y)) {
						elements.push(element);
						return elements;
					}
				});

				return elements.slice(0, 1);
			},

			/**
			 * @function Chart.Interaction.modes.label
			 * @deprecated since version 2.4.0
	 		 * @todo remove at version 3
			 * @private
			 */
			label: indexMode,

			/**
			 * Returns items at the same index. If the options.intersect parameter is true, we only return items if we intersect something
			 * If the options.intersect mode is false, we find the nearest item and return the items at the same index as that item
			 * @function Chart.Interaction.modes.index
			 * @since v2.4.0
			 * @param chart {chart} the chart we are returning items from
			 * @param e {Event} the event we are find things at
			 * @param options {IInteractionOptions} options to use during interaction
			 * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
			 */
			index: indexMode,

			/**
			 * Returns items in the same dataset. If the options.intersect parameter is true, we only return items if we intersect something
			 * If the options.intersect is false, we find the nearest item and return the items in that dataset
			 * @function Chart.Interaction.modes.dataset
			 * @param chart {chart} the chart we are returning items from
			 * @param e {Event} the event we are find things at
			 * @param options {IInteractionOptions} options to use during interaction
			 * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
			 */
			dataset: function(chart, e, options) {
				var position = getRelativePosition(e, chart);
				var items = options.intersect ? getIntersectItems(chart, position) : getNearestItems(chart, position, false);

				if (items.length > 0) {
					items = chart.getDatasetMeta(items[0]._datasetIndex).data;
				}

				return items;
			},

			/**
			 * @function Chart.Interaction.modes.x-axis
			 * @deprecated since version 2.4.0. Use index mode and intersect == true
			 * @todo remove at version 3
			 * @private
			 */
			'x-axis': function(chart, e) {
				return indexMode(chart, e, true);
			},

			/**
			 * Point mode returns all elements that hit test based on the event position
			 * of the event
			 * @function Chart.Interaction.modes.intersect
			 * @param chart {chart} the chart we are returning items from
			 * @param e {Event} the event we are find things at
			 * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
			 */
			point: function(chart, e) {
				var position = getRelativePosition(e, chart);
				return getIntersectItems(chart, position);
			},

			/**
			 * nearest mode returns the element closest to the point
			 * @function Chart.Interaction.modes.intersect
			 * @param chart {chart} the chart we are returning items from
			 * @param e {Event} the event we are find things at
			 * @param options {IInteractionOptions} options to use
			 * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
			 */
			nearest: function(chart, e, options) {
				var position = getRelativePosition(e, chart);
				var nearestItems = getNearestItems(chart, position, options.intersect);

				// We have multiple items at the same distance from the event. Now sort by smallest
				if (nearestItems.length > 1) {
					nearestItems.sort(function(a, b) {
						var sizeA = a.getArea();
						var sizeB = b.getArea();
						var ret = sizeA - sizeB;

						if (ret === 0) {
							// if equal sort by dataset index
							ret = a._datasetIndex - b._datasetIndex;
						}

						return ret;
					});
				}

				// Return only 1 item
				return nearestItems.slice(0, 1);
			},

			/**
			 * x mode returns the elements that hit-test at the current x coordinate
			 * @function Chart.Interaction.modes.x
			 * @param chart {chart} the chart we are returning items from
			 * @param e {Event} the event we are find things at
			 * @param options {IInteractionOptions} options to use
			 * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
			 */
			x: function(chart, e, options) {
				var position = getRelativePosition(e, chart);
				var items = [];
				var intersectsItem = false;

				parseVisibleItems(chart, function(element) {
					if (element.inXRange(position.x)) {
						items.push(element);
					}

					if (element.inRange(position.x, position.y)) {
						intersectsItem = true;
					}
				});

				// If we want to trigger on an intersect and we don't have any items
				// that intersect the position, return nothing
				if (options.intersect && !intersectsItem) {
					items = [];
				}
				return items;
			},

			/**
			 * y mode returns the elements that hit-test at the current y coordinate
			 * @function Chart.Interaction.modes.y
			 * @param chart {chart} the chart we are returning items from
			 * @param e {Event} the event we are find things at
			 * @param options {IInteractionOptions} options to use
			 * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
			 */
			y: function(chart, e, options) {
				var position = getRelativePosition(e, chart);
				var items = [];
				var intersectsItem = false;

				parseVisibleItems(chart, function(element) {
					if (element.inYRange(position.y)) {
						items.push(element);
					}

					if (element.inRange(position.x, position.y)) {
						intersectsItem = true;
					}
				});

				// If we want to trigger on an intersect and we don't have any items
				// that intersect the position, return nothing
				if (options.intersect && !intersectsItem) {
					items = [];
				}
				return items;
			}
		}
	};
};

},{}],28:[function(require,module,exports){
'use strict';

module.exports = function() {

	// Occupy the global variable of Chart, and create a simple base class
	var Chart = function(item, config) {
		this.construct(item, config);
		return this;
	};

	// Globally expose the defaults to allow for user updating/changing
	Chart.defaults = {
		global: {
			responsive: true,
			responsiveAnimationDuration: 0,
			maintainAspectRatio: true,
			events: ['mousemove', 'mouseout', 'click', 'touchstart', 'touchmove'],
			hover: {
				onHover: null,
				mode: 'nearest',
				intersect: true,
				animationDuration: 400
			},
			onClick: null,
			defaultColor: 'rgba(0,0,0,0.1)',
			defaultFontColor: '#666',
			defaultFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",
			defaultFontSize: 12,
			defaultFontStyle: 'normal',
			showLines: true,

			// Element defaults defined in element extensions
			elements: {},

			// Legend callback string
			legendCallback: function(chart) {
				var text = [];
				text.push('<ul class="' + chart.id + '-legend">');
				for (var i = 0; i < chart.data.datasets.length; i++) {
					text.push('<li><span style="background-color:' + chart.data.datasets[i].backgroundColor + '"></span>');
					if (chart.data.datasets[i].label) {
						text.push(chart.data.datasets[i].label);
					}
					text.push('</li>');
				}
				text.push('</ul>');

				return text.join('');
			}
		}
	};

	Chart.Chart = Chart;

	return Chart;
};

},{}],29:[function(require,module,exports){
'use strict';

module.exports = function(Chart) {

	var helpers = Chart.helpers;

	function filterByPosition(array, position) {
		return helpers.where(array, function(v) {
			return v.position === position;
		});
	}

	function sortByWeight(array, reverse) {
		array.forEach(function(v, i) {
			v._tmpIndex_ = i;
			return v;
		});
		array.sort(function(a, b) {
			var v0 = reverse ? b : a;
			var v1 = reverse ? a : b;
			return v0.weight === v1.weight ?
				v0._tmpIndex_ - v1._tmpIndex_ :
				v0.weight - v1.weight;
		});
		array.forEach(function(v) {
			delete v._tmpIndex_;
		});
	}

	/**
	 * @interface ILayoutItem
	 * @prop {String} position - The position of the item in the chart layout. Possible values are
	 * 'left', 'top', 'right', 'bottom', and 'chartArea'
	 * @prop {Number} weight - The weight used to sort the item. Higher weights are further away from the chart area
	 * @prop {Boolean} fullWidth - if true, and the item is horizontal, then push vertical boxes down
	 * @prop {Function} isHorizontal - returns true if the layout item is horizontal (ie. top or bottom)
	 * @prop {Function} update - Takes two parameters: width and height. Returns size of item
	 * @prop {Function} getPadding -  Returns an object with padding on the edges
	 * @prop {Number} width - Width of item. Must be valid after update()
	 * @prop {Number} height - Height of item. Must be valid after update()
	 * @prop {Number} left - Left edge of the item. Set by layout system and cannot be used in update
	 * @prop {Number} top - Top edge of the item. Set by layout system and cannot be used in update
	 * @prop {Number} right - Right edge of the item. Set by layout system and cannot be used in update
	 * @prop {Number} bottom - Bottom edge of the item. Set by layout system and cannot be used in update
	 */

	// The layout service is very self explanatory.  It's responsible for the layout within a chart.
	// Scales, Legends and Plugins all rely on the layout service and can easily register to be placed anywhere they need
	// It is this service's responsibility of carrying out that layout.
	Chart.layoutService = {
		defaults: {},

		/**
		 * Register a box to a chart.
		 * A box is simply a reference to an object that requires layout. eg. Scales, Legend, Title.
		 * @param {Chart} chart - the chart to use
		 * @param {ILayoutItem} item - the item to add to be layed out
		 */
		addBox: function(chart, item) {
			if (!chart.boxes) {
				chart.boxes = [];
			}

			// initialize item with default values
			item.fullWidth = item.fullWidth || false;
			item.position = item.position || 'top';
			item.weight = item.weight || 0;

			chart.boxes.push(item);
		},

		/**
		 * Remove a layoutItem from a chart
		 * @param {Chart} chart - the chart to remove the box from
		 * @param {Object} layoutItem - the item to remove from the layout
		 */
		removeBox: function(chart, layoutItem) {
			var index = chart.boxes? chart.boxes.indexOf(layoutItem) : -1;
			if (index !== -1) {
				chart.boxes.splice(index, 1);
			}
		},

		/**
		 * Sets (or updates) options on the given `item`.
		 * @param {Chart} chart - the chart in which the item lives (or will be added to)
		 * @param {Object} item - the item to configure with the given options
		 * @param {Object} options - the new item options.
		 */
		configure: function(chart, item, options) {
			var props = ['fullWidth', 'position', 'weight'];
			var ilen = props.length;
			var i = 0;
			var prop;

			for (; i<ilen; ++i) {
				prop = props[i];
				if (options.hasOwnProperty(prop)) {
					item[prop] = options[prop];
				}
			}
		},

		/**
		 * Fits boxes of the given chart into the given size by having each box measure itself
		 * then running a fitting algorithm
		 * @param {Chart} chart - the chart
		 * @param {Number} width - the width to fit into
		 * @param {Number} height - the height to fit into
		 */
		update: function(chart, width, height) {
			if (!chart) {
				return;
			}

			var layoutOptions = chart.options.layout;
			var padding = layoutOptions ? layoutOptions.padding : null;

			var leftPadding = 0;
			var rightPadding = 0;
			var topPadding = 0;
			var bottomPadding = 0;

			if (!isNaN(padding)) {
				// options.layout.padding is a number. assign to all
				leftPadding = padding;
				rightPadding = padding;
				topPadding = padding;
				bottomPadding = padding;
			} else {
				leftPadding = padding.left || 0;
				rightPadding = padding.right || 0;
				topPadding = padding.top || 0;
				bottomPadding = padding.bottom || 0;
			}

			var leftBoxes = filterByPosition(chart.boxes, 'left');
			var rightBoxes = filterByPosition(chart.boxes, 'right');
			var topBoxes = filterByPosition(chart.boxes, 'top');
			var bottomBoxes = filterByPosition(chart.boxes, 'bottom');
			var chartAreaBoxes = filterByPosition(chart.boxes, 'chartArea');

			// Sort boxes by weight. A higher weight is further away from the chart area
			sortByWeight(leftBoxes, true);
			sortByWeight(rightBoxes, false);
			sortByWeight(topBoxes, true);
			sortByWeight(bottomBoxes, false);

			// Essentially we now have any number of boxes on each of the 4 sides.
			// Our canvas looks like the following.
			// The areas L1 and L2 are the left axes. R1 is the right axis, T1 is the top axis and
			// B1 is the bottom axis
			// There are also 4 quadrant-like locations (left to right instead of clockwise) reserved for chart overlays
			// These locations are single-box locations only, when trying to register a chartArea location that is already taken,
			// an error will be thrown.
			//
			// |----------------------------------------------------|
			// |                  T1 (Full Width)                   |
			// |----------------------------------------------------|
			// |    |    |                 T2                  |    |
			// |    |----|-------------------------------------|----|
			// |    |    | C1 |                           | C2 |    |
			// |    |    |----|                           |----|    |
			// |    |    |                                     |    |
			// | L1 | L2 |           ChartArea (C0)            | R1 |
			// |    |    |                                     |    |
			// |    |    |----|                           |----|    |
			// |    |    | C3 |                           | C4 |    |
			// |    |----|-------------------------------------|----|
			// |    |    |                 B1                  |    |
			// |----------------------------------------------------|
			// |                  B2 (Full Width)                   |
			// |----------------------------------------------------|
			//
			// What we do to find the best sizing, we do the following
			// 1. Determine the minimum size of the chart area.
			// 2. Split the remaining width equally between each vertical axis
			// 3. Split the remaining height equally between each horizontal axis
			// 4. Give each layout the maximum size it can be. The layout will return it's minimum size
			// 5. Adjust the sizes of each axis based on it's minimum reported size.
			// 6. Refit each axis
			// 7. Position each axis in the final location
			// 8. Tell the chart the final location of the chart area
			// 9. Tell any axes that overlay the chart area the positions of the chart area

			// Step 1
			var chartWidth = width - leftPadding - rightPadding;
			var chartHeight = height - topPadding - bottomPadding;
			var chartAreaWidth = chartWidth / 2; // min 50%
			var chartAreaHeight = chartHeight / 2; // min 50%

			// Step 2
			var verticalBoxWidth = (width - chartAreaWidth) / (leftBoxes.length + rightBoxes.length);

			// Step 3
			var horizontalBoxHeight = (height - chartAreaHeight) / (topBoxes.length + bottomBoxes.length);

			// Step 4
			var maxChartAreaWidth = chartWidth;
			var maxChartAreaHeight = chartHeight;
			var minBoxSizes = [];

			function getMinimumBoxSize(box) {
				var minSize;
				var isHorizontal = box.isHorizontal();

				if (isHorizontal) {
					minSize = box.update(box.fullWidth ? chartWidth : maxChartAreaWidth, horizontalBoxHeight);
					maxChartAreaHeight -= minSize.height;
				} else {
					minSize = box.update(verticalBoxWidth, chartAreaHeight);
					maxChartAreaWidth -= minSize.width;
				}

				minBoxSizes.push({
					horizontal: isHorizontal,
					minSize: minSize,
					box: box,
				});
			}

			helpers.each(leftBoxes.concat(rightBoxes, topBoxes, bottomBoxes), getMinimumBoxSize);

			// If a horizontal box has padding, we move the left boxes over to avoid ugly charts (see issue #2478)
			var maxHorizontalLeftPadding = 0;
			var maxHorizontalRightPadding = 0;
			var maxVerticalTopPadding = 0;
			var maxVerticalBottomPadding = 0;

			helpers.each(topBoxes.concat(bottomBoxes), function(horizontalBox) {
				if (horizontalBox.getPadding) {
					var boxPadding = horizontalBox.getPadding();
					maxHorizontalLeftPadding = Math.max(maxHorizontalLeftPadding, boxPadding.left);
					maxHorizontalRightPadding = Math.max(maxHorizontalRightPadding, boxPadding.right);
				}
			});

			helpers.each(leftBoxes.concat(rightBoxes), function(verticalBox) {
				if (verticalBox.getPadding) {
					var boxPadding = verticalBox.getPadding();
					maxVerticalTopPadding = Math.max(maxVerticalTopPadding, boxPadding.top);
					maxVerticalBottomPadding = Math.max(maxVerticalBottomPadding, boxPadding.bottom);
				}
			});

			// At this point, maxChartAreaHeight and maxChartAreaWidth are the size the chart area could
			// be if the axes are drawn at their minimum sizes.
			// Steps 5 & 6
			var totalLeftBoxesWidth = leftPadding;
			var totalRightBoxesWidth = rightPadding;
			var totalTopBoxesHeight = topPadding;
			var totalBottomBoxesHeight = bottomPadding;

			// Function to fit a box
			function fitBox(box) {
				var minBoxSize = helpers.findNextWhere(minBoxSizes, function(minBox) {
					return minBox.box === box;
				});

				if (minBoxSize) {
					if (box.isHorizontal()) {
						var scaleMargin = {
							left: Math.max(totalLeftBoxesWidth, maxHorizontalLeftPadding),
							right: Math.max(totalRightBoxesWidth, maxHorizontalRightPadding),
							top: 0,
							bottom: 0
						};

						// Don't use min size here because of label rotation. When the labels are rotated, their rotation highly depends
						// on the margin. Sometimes they need to increase in size slightly
						box.update(box.fullWidth ? chartWidth : maxChartAreaWidth, chartHeight / 2, scaleMargin);
					} else {
						box.update(minBoxSize.minSize.width, maxChartAreaHeight);
					}
				}
			}

			// Update, and calculate the left and right margins for the horizontal boxes
			helpers.each(leftBoxes.concat(rightBoxes), fitBox);

			helpers.each(leftBoxes, function(box) {
				totalLeftBoxesWidth += box.width;
			});

			helpers.each(rightBoxes, function(box) {
				totalRightBoxesWidth += box.width;
			});

			// Set the Left and Right margins for the horizontal boxes
			helpers.each(topBoxes.concat(bottomBoxes), fitBox);

			// Figure out how much margin is on the top and bottom of the vertical boxes
			helpers.each(topBoxes, function(box) {
				totalTopBoxesHeight += box.height;
			});

			helpers.each(bottomBoxes, function(box) {
				totalBottomBoxesHeight += box.height;
			});

			function finalFitVerticalBox(box) {
				var minBoxSize = helpers.findNextWhere(minBoxSizes, function(minSize) {
					return minSize.box === box;
				});

				var scaleMargin = {
					left: 0,
					right: 0,
					top: totalTopBoxesHeight,
					bottom: totalBottomBoxesHeight
				};

				if (minBoxSize) {
					box.update(minBoxSize.minSize.width, maxChartAreaHeight, scaleMargin);
				}
			}

			// Let the left layout know the final margin
			helpers.each(leftBoxes.concat(rightBoxes), finalFitVerticalBox);

			// Recalculate because the size of each layout might have changed slightly due to the margins (label rotation for instance)
			totalLeftBoxesWidth = leftPadding;
			totalRightBoxesWidth = rightPadding;
			totalTopBoxesHeight = topPadding;
			totalBottomBoxesHeight = bottomPadding;

			helpers.each(leftBoxes, function(box) {
				totalLeftBoxesWidth += box.width;
			});

			helpers.each(rightBoxes, function(box) {
				totalRightBoxesWidth += box.width;
			});

			helpers.each(topBoxes, function(box) {
				totalTopBoxesHeight += box.height;
			});
			helpers.each(bottomBoxes, function(box) {
				totalBottomBoxesHeight += box.height;
			});

			// We may be adding some padding to account for rotated x axis labels
			var leftPaddingAddition = Math.max(maxHorizontalLeftPadding - totalLeftBoxesWidth, 0);
			totalLeftBoxesWidth += leftPaddingAddition;
			totalRightBoxesWidth += Math.max(maxHorizontalRightPadding - totalRightBoxesWidth, 0);

			var topPaddingAddition = Math.max(maxVerticalTopPadding - totalTopBoxesHeight, 0);
			totalTopBoxesHeight += topPaddingAddition;
			totalBottomBoxesHeight += Math.max(maxVerticalBottomPadding - totalBottomBoxesHeight, 0);

			// Figure out if our chart area changed. This would occur if the dataset layout label rotation
			// changed due to the application of the margins in step 6. Since we can only get bigger, this is safe to do
			// without calling `fit` again
			var newMaxChartAreaHeight = height - totalTopBoxesHeight - totalBottomBoxesHeight;
			var newMaxChartAreaWidth = width - totalLeftBoxesWidth - totalRightBoxesWidth;

			if (newMaxChartAreaWidth !== maxChartAreaWidth || newMaxChartAreaHeight !== maxChartAreaHeight) {
				helpers.each(leftBoxes, function(box) {
					box.height = newMaxChartAreaHeight;
				});

				helpers.each(rightBoxes, function(box) {
					box.height = newMaxChartAreaHeight;
				});

				helpers.each(topBoxes, function(box) {
					if (!box.fullWidth) {
						box.width = newMaxChartAreaWidth;
					}
				});

				helpers.each(bottomBoxes, function(box) {
					if (!box.fullWidth) {
						box.width = newMaxChartAreaWidth;
					}
				});

				maxChartAreaHeight = newMaxChartAreaHeight;
				maxChartAreaWidth = newMaxChartAreaWidth;
			}

			// Step 7 - Position the boxes
			var left = leftPadding + leftPaddingAddition;
			var top = topPadding + topPaddingAddition;

			function placeBox(box) {
				if (box.isHorizontal()) {
					box.left = box.fullWidth ? leftPadding : totalLeftBoxesWidth;
					box.right = box.fullWidth ? width - rightPadding : totalLeftBoxesWidth + maxChartAreaWidth;
					box.top = top;
					box.bottom = top + box.height;

					// Move to next point
					top = box.bottom;

				} else {

					box.left = left;
					box.right = left + box.width;
					box.top = totalTopBoxesHeight;
					box.bottom = totalTopBoxesHeight + maxChartAreaHeight;

					// Move to next point
					left = box.right;
				}
			}

			helpers.each(leftBoxes.concat(topBoxes), placeBox);

			// Account for chart width and height
			left += maxChartAreaWidth;
			top += maxChartAreaHeight;

			helpers.each(rightBoxes, placeBox);
			helpers.each(bottomBoxes, placeBox);

			// Step 8
			chart.chartArea = {
				left: totalLeftBoxesWidth,
				top: totalTopBoxesHeight,
				right: totalLeftBoxesWidth + maxChartAreaWidth,
				bottom: totalTopBoxesHeight + maxChartAreaHeight
			};

			// Step 9
			helpers.each(chartAreaBoxes, function(box) {
				box.left = chart.chartArea.left;
				box.top = chart.chartArea.top;
				box.right = chart.chartArea.right;
				box.bottom = chart.chartArea.bottom;

				box.update(maxChartAreaWidth, maxChartAreaHeight);
			});
		}
	};
};

},{}],30:[function(require,module,exports){
'use strict';

module.exports = function(Chart) {

	var helpers = Chart.helpers;

	Chart.defaults.global.plugins = {};

	/**
	 * The plugin service singleton
	 * @namespace Chart.plugins
	 * @since 2.1.0
	 */
	Chart.plugins = {
		/**
		 * Globally registered plugins.
		 * @private
		 */
		_plugins: [],

		/**
		 * This identifier is used to invalidate the descriptors cache attached to each chart
		 * when a global plugin is registered or unregistered. In this case, the cache ID is
		 * incremented and descriptors are regenerated during following API calls.
		 * @private
		 */
		_cacheId: 0,

		/**
		 * Registers the given plugin(s) if not already registered.
		 * @param {Array|Object} plugins plugin instance(s).
		 */
		register: function(plugins) {
			var p = this._plugins;
			([]).concat(plugins).forEach(function(plugin) {
				if (p.indexOf(plugin) === -1) {
					p.push(plugin);
				}
			});

			this._cacheId++;
		},

		/**
		 * Unregisters the given plugin(s) only if registered.
		 * @param {Array|Object} plugins plugin instance(s).
		 */
		unregister: function(plugins) {
			var p = this._plugins;
			([]).concat(plugins).forEach(function(plugin) {
				var idx = p.indexOf(plugin);
				if (idx !== -1) {
					p.splice(idx, 1);
				}
			});

			this._cacheId++;
		},

		/**
		 * Remove all registered plugins.
		 * @since 2.1.5
		 */
		clear: function() {
			this._plugins = [];
			this._cacheId++;
		},

		/**
		 * Returns the number of registered plugins?
		 * @returns {Number}
		 * @since 2.1.5
		 */
		count: function() {
			return this._plugins.length;
		},

		/**
		 * Returns all registered plugin instances.
		 * @returns {Array} array of plugin objects.
		 * @since 2.1.5
		 */
		getAll: function() {
			return this._plugins;
		},

		/**
		 * Calls enabled plugins for `chart` on the specified hook and with the given args.
		 * This method immediately returns as soon as a plugin explicitly returns false. The
		 * returned value can be used, for instance, to interrupt the current action.
		 * @param {Object} chart - The chart instance for which plugins should be called.
		 * @param {String} hook - The name of the plugin method to call (e.g. 'beforeUpdate').
		 * @param {Array} [args] - Extra arguments to apply to the hook call.
		 * @returns {Boolean} false if any of the plugins return false, else returns true.
		 */
		notify: function(chart, hook, args) {
			var descriptors = this.descriptors(chart);
			var ilen = descriptors.length;
			var i, descriptor, plugin, params, method;

			for (i=0; i<ilen; ++i) {
				descriptor = descriptors[i];
				plugin = descriptor.plugin;
				method = plugin[hook];
				if (typeof method === 'function') {
					params = [chart].concat(args || []);
					params.push(descriptor.options);
					if (method.apply(plugin, params) === false) {
						return false;
					}
				}
			}

			return true;
		},

		/**
		 * Returns descriptors of enabled plugins for the given chart.
		 * @returns {Array} [{ plugin, options }]
		 * @private
		 */
		descriptors: function(chart) {
			var cache = chart._plugins || (chart._plugins = {});
			if (cache.id === this._cacheId) {
				return cache.descriptors;
			}

			var plugins = [];
			var descriptors = [];
			var config = (chart && chart.config) || {};
			var defaults = Chart.defaults.global.plugins;
			var options = (config.options && config.options.plugins) || {};

			this._plugins.concat(config.plugins || []).forEach(function(plugin) {
				var idx = plugins.indexOf(plugin);
				if (idx !== -1) {
					return;
				}

				var id = plugin.id;
				var opts = options[id];
				if (opts === false) {
					return;
				}

				if (opts === true) {
					opts = helpers.clone(defaults[id]);
				}

				plugins.push(plugin);
				descriptors.push({
					plugin: plugin,
					options: opts || {}
				});
			});

			cache.descriptors = descriptors;
			cache.id = this._cacheId;
			return descriptors;
		}
	};

	/**
	 * Plugin extension hooks.
	 * @interface IPlugin
	 * @since 2.1.0
	 */
	/**
	 * @method IPlugin#beforeInit
	 * @desc Called before initializing `chart`.
	 * @param {Chart.Controller} chart - The chart instance.
	 * @param {Object} options - The plugin options.
	 */
	/**
	 * @method IPlugin#afterInit
	 * @desc Called after `chart` has been initialized and before the first update.
	 * @param {Chart.Controller} chart - The chart instance.
	 * @param {Object} options - The plugin options.
	 */
	/**
	 * @method IPlugin#beforeUpdate
	 * @desc Called before updating `chart`. If any plugin returns `false`, the update
	 * is cancelled (and thus subsequent render(s)) until another `update` is triggered.
	 * @param {Chart.Controller} chart - The chart instance.
	 * @param {Object} options - The plugin options.
	 * @returns {Boolean} `false` to cancel the chart update.
	 */
	/**
	 * @method IPlugin#afterUpdate
	 * @desc Called after `chart` has been updated and before rendering. Note that this
	 * hook will not be called if the chart update has been previously cancelled.
	 * @param {Chart.Controller} chart - The chart instance.
	 * @param {Object} options - The plugin options.
	 */
	/**
	 * @method IPlugin#beforeDatasetsUpdate
 	 * @desc Called before updating the `chart` datasets. If any plugin returns `false`,
	 * the datasets update is cancelled until another `update` is triggered.
	 * @param {Chart.Controller} chart - The chart instance.
	 * @param {Object} options - The plugin options.
	 * @returns {Boolean} false to cancel the datasets update.
	 * @since version 2.1.5
	 */
	/**
	 * @method IPlugin#afterDatasetsUpdate
	 * @desc Called after the `chart` datasets have been updated. Note that this hook
	 * will not be called if the datasets update has been previously cancelled.
	 * @param {Chart.Controller} chart - The chart instance.
	 * @param {Object} options - The plugin options.
	 * @since version 2.1.5
	 */
	/**
	 * @method IPlugin#beforeDatasetUpdate
 	 * @desc Called before updating the `chart` dataset at the given `args.index`. If any plugin
	 * returns `false`, the datasets update is cancelled until another `update` is triggered.
	 * @param {Chart} chart - The chart instance.
	 * @param {Object} args - The call arguments.
	 * @param {Object} args.index - The dataset index.
	 * @param {Number} args.meta - The dataset metadata.
	 * @param {Object} options - The plugin options.
	 * @returns {Boolean} `false` to cancel the chart datasets drawing.
	 */
	/**
	 * @method IPlugin#afterDatasetUpdate
 	 * @desc Called after the `chart` datasets at the given `args.index` has been updated. Note
	 * that this hook will not be called if the datasets update has been previously cancelled.
	 * @param {Chart} chart - The chart instance.
	 * @param {Object} args - The call arguments.
	 * @param {Object} args.index - The dataset index.
	 * @param {Number} args.meta - The dataset metadata.
	 * @param {Object} options - The plugin options.
	 */
	/**
	 * @method IPlugin#beforeLayout
	 * @desc Called before laying out `chart`. If any plugin returns `false`,
	 * the layout update is cancelled until another `update` is triggered.
	 * @param {Chart.Controller} chart - The chart instance.
	 * @param {Object} options - The plugin options.
	 * @returns {Boolean} `false` to cancel the chart layout.
	 */
	/**
	 * @method IPlugin#afterLayout
	 * @desc Called after the `chart` has been layed out. Note that this hook will not
	 * be called if the layout update has been previously cancelled.
	 * @param {Chart.Controller} chart - The chart instance.
	 * @param {Object} options - The plugin options.
	 */
	/**
	 * @method IPlugin#beforeRender
	 * @desc Called before rendering `chart`. If any plugin returns `false`,
	 * the rendering is cancelled until another `render` is triggered.
	 * @param {Chart.Controller} chart - The chart instance.
	 * @param {Object} options - The plugin options.
	 * @returns {Boolean} `false` to cancel the chart rendering.
	 */
	/**
	 * @method IPlugin#afterRender
	 * @desc Called after the `chart` has been fully rendered (and animation completed). Note
	 * that this hook will not be called if the rendering has been previously cancelled.
	 * @param {Chart.Controller} chart - The chart instance.
	 * @param {Object} options - The plugin options.
	 */
	/**
	 * @method IPlugin#beforeDraw
	 * @desc Called before drawing `chart` at every animation frame specified by the given
	 * easing value. If any plugin returns `false`, the frame drawing is cancelled until
	 * another `render` is triggered.
	 * @param {Chart.Controller} chart - The chart instance.
	 * @param {Number} easingValue - The current animation value, between 0.0 and 1.0.
	 * @param {Object} options - The plugin options.
	 * @returns {Boolean} `false` to cancel the chart drawing.
	 */
	/**
	 * @method IPlugin#afterDraw
	 * @desc Called after the `chart` has been drawn for the specific easing value. Note
	 * that this hook will not be called if the drawing has been previously cancelled.
	 * @param {Chart.Controller} chart - The chart instance.
	 * @param {Number} easingValue - The current animation value, between 0.0 and 1.0.
	 * @param {Object} options - The plugin options.
	 */
	/**
	 * @method IPlugin#beforeDatasetsDraw
 	 * @desc Called before drawing the `chart` datasets. If any plugin returns `false`,
	 * the datasets drawing is cancelled until another `render` is triggered.
	 * @param {Chart.Controller} chart - The chart instance.
	 * @param {Number} easingValue - The current animation value, between 0.0 and 1.0.
	 * @param {Object} options - The plugin options.
	 * @returns {Boolean} `false` to cancel the chart datasets drawing.
	 */
	/**
	 * @method IPlugin#afterDatasetsDraw
	 * @desc Called after the `chart` datasets have been drawn. Note that this hook
	 * will not be called if the datasets drawing has been previously cancelled.
	 * @param {Chart.Controller} chart - The chart instance.
	 * @param {Number} easingValue - The current animation value, between 0.0 and 1.0.
	 * @param {Object} options - The plugin options.
	 */
	/**
	 * @method IPlugin#beforeDatasetDraw
 	 * @desc Called before drawing the `chart` dataset at the given `args.index` (datasets
	 * are drawn in the reverse order). If any plugin returns `false`, the datasets drawing
	 * is cancelled until another `render` is triggered.
	 * @param {Chart} chart - The chart instance.
	 * @param {Object} args - The call arguments.
	 * @param {Object} args.index - The dataset index.
	 * @param {Number} args.meta - The dataset metadata.
	 * @param {Number} args.easingValue - The current animation value, between 0.0 and 1.0.
	 * @param {Object} options - The plugin options.
	 * @returns {Boolean} `false` to cancel the chart datasets drawing.
	 */
	/**
	 * @method IPlugin#afterDatasetDraw
 	 * @desc Called after the `chart` datasets at the given `args.index` have been drawn
	 * (datasets are drawn in the reverse order). Note that this hook will not be called
	 * if the datasets drawing has been previously cancelled.
	 * @param {Chart} chart - The chart instance.
	 * @param {Object} args - The call arguments.
	 * @param {Object} args.index - The dataset index.
	 * @param {Number} args.meta - The dataset metadata.
	 * @param {Number} args.easingValue - The current animation value, between 0.0 and 1.0.
	 * @param {Object} options - The plugin options.
	 */
	/**
	 * @method IPlugin#beforeEvent
 	 * @desc Called before processing the specified `event`. If any plugin returns `false`,
	 * the event will be discarded.
	 * @param {Chart.Controller} chart - The chart instance.
	 * @param {IEvent} event - The event object.
	 * @param {Object} options - The plugin options.
	 */
	/**
	 * @method IPlugin#afterEvent
	 * @desc Called after the `event` has been consumed. Note that this hook
	 * will not be called if the `event` has been previously discarded.
	 * @param {Chart.Controller} chart - The chart instance.
	 * @param {IEvent} event - The event object.
	 * @param {Object} options - The plugin options.
	 */
	/**
	 * @method IPlugin#resize
	 * @desc Called after the chart as been resized.
	 * @param {Chart.Controller} chart - The chart instance.
	 * @param {Number} size - The new canvas display size (eq. canvas.style width & height).
	 * @param {Object} options - The plugin options.
	 */
	/**
	 * @method IPlugin#destroy
	 * @desc Called after the chart as been destroyed.
	 * @param {Chart.Controller} chart - The chart instance.
	 * @param {Object} options - The plugin options.
	 */

	/**
	 * Provided for backward compatibility, use Chart.plugins instead
	 * @namespace Chart.pluginService
	 * @deprecated since version 2.1.5
	 * @todo remove at version 3
	 * @private
	 */
	Chart.pluginService = Chart.plugins;

	/**
	 * Provided for backward compatibility, inheriting from Chart.PlugingBase has no
	 * effect, instead simply create/register plugins via plain JavaScript objects.
	 * @interface Chart.PluginBase
	 * @deprecated since version 2.5.0
	 * @todo remove at version 3
	 * @private
	 */
	Chart.PluginBase = Chart.Element.extend({});
};

},{}],31:[function(require,module,exports){
'use strict';

module.exports = function(Chart) {

	var helpers = Chart.helpers;

	Chart.defaults.scale = {
		display: true,
		position: 'left',

		// grid line settings
		gridLines: {
			display: true,
			color: 'rgba(0, 0, 0, 0.1)',
			lineWidth: 1,
			drawBorder: true,
			drawOnChartArea: true,
			drawTicks: true,
			tickMarkLength: 10,
			zeroLineWidth: 1,
			zeroLineColor: 'rgba(0,0,0,0.25)',
			zeroLineBorderDash: [],
			zeroLineBorderDashOffset: 0.0,
			offsetGridLines: false,
			borderDash: [],
			borderDashOffset: 0.0
		},

		// scale label
		scaleLabel: {
			// actual label
			labelString: '',

			// display property
			display: false
		},

		// label settings
		ticks: {
			beginAtZero: false,
			minRotation: 0,
			maxRotation: 50,
			mirror: false,
			padding: 0,
			reverse: false,
			display: true,
			autoSkip: true,
			autoSkipPadding: 0,
			labelOffset: 0,
			// We pass through arrays to be rendered as multiline labels, we convert Others to strings here.
			callback: Chart.Ticks.formatters.values
		}
	};

	function computeTextSize(context, tick, font) {
		return helpers.isArray(tick) ?
			helpers.longestText(context, font, tick) :
			context.measureText(tick).width;
	}

	function parseFontOptions(options) {
		var getValueOrDefault = helpers.getValueOrDefault;
		var globalDefaults = Chart.defaults.global;
		var size = getValueOrDefault(options.fontSize, globalDefaults.defaultFontSize);
		var style = getValueOrDefault(options.fontStyle, globalDefaults.defaultFontStyle);
		var family = getValueOrDefault(options.fontFamily, globalDefaults.defaultFontFamily);

		return {
			size: size,
			style: style,
			family: family,
			font: helpers.fontString(size, style, family)
		};
	}

	Chart.Scale = Chart.Element.extend({
		/**
		 * Get the padding needed for the scale
		 * @method getPadding
		 * @private
		 * @returns {Padding} the necessary padding
		 */
		getPadding: function() {
			var me = this;
			return {
				left: me.paddingLeft || 0,
				top: me.paddingTop || 0,
				right: me.paddingRight || 0,
				bottom: me.paddingBottom || 0
			};
		},

		// These methods are ordered by lifecyle. Utilities then follow.
		// Any function defined here is inherited by all scale types.
		// Any function can be extended by the scale type

		beforeUpdate: function() {
			helpers.callback(this.options.beforeUpdate, [this]);
		},
		update: function(maxWidth, maxHeight, margins) {
			var me = this;

			// Update Lifecycle - Probably don't want to ever extend or overwrite this function ;)
			me.beforeUpdate();

			// Absorb the master measurements
			me.maxWidth = maxWidth;
			me.maxHeight = maxHeight;
			me.margins = helpers.extend({
				left: 0,
				right: 0,
				top: 0,
				bottom: 0
			}, margins);
			me.longestTextCache = me.longestTextCache || {};

			// Dimensions
			me.beforeSetDimensions();
			me.setDimensions();
			me.afterSetDimensions();

			// Data min/max
			me.beforeDataLimits();
			me.determineDataLimits();
			me.afterDataLimits();

			// Ticks
			me.beforeBuildTicks();
			me.buildTicks();
			me.afterBuildTicks();

			me.beforeTickToLabelConversion();
			me.convertTicksToLabels();
			me.afterTickToLabelConversion();

			// Tick Rotation
			me.beforeCalculateTickRotation();
			me.calculateTickRotation();
			me.afterCalculateTickRotation();
			// Fit
			me.beforeFit();
			me.fit();
			me.afterFit();
			//
			me.afterUpdate();

			return me.minSize;

		},
		afterUpdate: function() {
			helpers.callback(this.options.afterUpdate, [this]);
		},

		//

		beforeSetDimensions: function() {
			helpers.callback(this.options.beforeSetDimensions, [this]);
		},
		setDimensions: function() {
			var me = this;
			// Set the unconstrained dimension before label rotation
			if (me.isHorizontal()) {
				// Reset position before calculating rotation
				me.width = me.maxWidth;
				me.left = 0;
				me.right = me.width;
			} else {
				me.height = me.maxHeight;

				// Reset position before calculating rotation
				me.top = 0;
				me.bottom = me.height;
			}

			// Reset padding
			me.paddingLeft = 0;
			me.paddingTop = 0;
			me.paddingRight = 0;
			me.paddingBottom = 0;
		},
		afterSetDimensions: function() {
			helpers.callback(this.options.afterSetDimensions, [this]);
		},

		// Data limits
		beforeDataLimits: function() {
			helpers.callback(this.options.beforeDataLimits, [this]);
		},
		determineDataLimits: helpers.noop,
		afterDataLimits: function() {
			helpers.callback(this.options.afterDataLimits, [this]);
		},

		//
		beforeBuildTicks: function() {
			helpers.callback(this.options.beforeBuildTicks, [this]);
		},
		buildTicks: helpers.noop,
		afterBuildTicks: function() {
			helpers.callback(this.options.afterBuildTicks, [this]);
		},

		beforeTickToLabelConversion: function() {
			helpers.callback(this.options.beforeTickToLabelConversion, [this]);
		},
		convertTicksToLabels: function() {
			var me = this;
			// Convert ticks to strings
			var tickOpts = me.options.ticks;
			me.ticks = me.ticks.map(tickOpts.userCallback || tickOpts.callback);
		},
		afterTickToLabelConversion: function() {
			helpers.callback(this.options.afterTickToLabelConversion, [this]);
		},

		//

		beforeCalculateTickRotation: function() {
			helpers.callback(this.options.beforeCalculateTickRotation, [this]);
		},
		calculateTickRotation: function() {
			var me = this;
			var context = me.ctx;
			var tickOpts = me.options.ticks;

			// Get the width of each grid by calculating the difference
			// between x offsets between 0 and 1.
			var tickFont = parseFontOptions(tickOpts);
			context.font = tickFont.font;

			var labelRotation = tickOpts.minRotation || 0;

			if (me.options.display && me.isHorizontal()) {
				var originalLabelWidth = helpers.longestText(context, tickFont.font, me.ticks, me.longestTextCache);
				var labelWidth = originalLabelWidth;
				var cosRotation;
				var sinRotation;

				// Allow 3 pixels x2 padding either side for label readability
				var tickWidth = me.getPixelForTick(1) - me.getPixelForTick(0) - 6;

				// Max label rotation can be set or default to 90 - also act as a loop counter
				while (labelWidth > tickWidth && labelRotation < tickOpts.maxRotation) {
					var angleRadians = helpers.toRadians(labelRotation);
					cosRotation = Math.cos(angleRadians);
					sinRotation = Math.sin(angleRadians);

					if (sinRotation * originalLabelWidth > me.maxHeight) {
						// go back one step
						labelRotation--;
						break;
					}

					labelRotation++;
					labelWidth = cosRotation * originalLabelWidth;
				}
			}

			me.labelRotation = labelRotation;
		},
		afterCalculateTickRotation: function() {
			helpers.callback(this.options.afterCalculateTickRotation, [this]);
		},

		//

		beforeFit: function() {
			helpers.callback(this.options.beforeFit, [this]);
		},
		fit: function() {
			var me = this;
			// Reset
			var minSize = me.minSize = {
				width: 0,
				height: 0
			};

			var opts = me.options;
			var tickOpts = opts.ticks;
			var scaleLabelOpts = opts.scaleLabel;
			var gridLineOpts = opts.gridLines;
			var display = opts.display;
			var isHorizontal = me.isHorizontal();

			var tickFont = parseFontOptions(tickOpts);
			var scaleLabelFontSize = parseFontOptions(scaleLabelOpts).size * 1.5;
			var tickMarkLength = opts.gridLines.tickMarkLength;

			// Width
			if (isHorizontal) {
				// subtract the margins to line up with the chartArea if we are a full width scale
				minSize.width = me.isFullWidth() ? me.maxWidth - me.margins.left - me.margins.right : me.maxWidth;
			} else {
				minSize.width = display && gridLineOpts.drawTicks ? tickMarkLength : 0;
			}

			// height
			if (isHorizontal) {
				minSize.height = display && gridLineOpts.drawTicks ? tickMarkLength : 0;
			} else {
				minSize.height = me.maxHeight; // fill all the height
			}

			// Are we showing a title for the scale?
			if (scaleLabelOpts.display && display) {
				if (isHorizontal) {
					minSize.height += scaleLabelFontSize;
				} else {
					minSize.width += scaleLabelFontSize;
				}
			}

			// Don't bother fitting the ticks if we are not showing them
			if (tickOpts.display && display) {
				var largestTextWidth = helpers.longestText(me.ctx, tickFont.font, me.ticks, me.longestTextCache);
				var tallestLabelHeightInLines = helpers.numberOfLabelLines(me.ticks);
				var lineSpace = tickFont.size * 0.5;

				if (isHorizontal) {
					// A horizontal axis is more constrained by the height.
					me.longestLabelWidth = largestTextWidth;

					var angleRadians = helpers.toRadians(me.labelRotation);
					var cosRotation = Math.cos(angleRadians);
					var sinRotation = Math.sin(angleRadians);

					// TODO - improve this calculation
					var labelHeight = (sinRotation * largestTextWidth)
						+ (tickFont.size * tallestLabelHeightInLines)
						+ (lineSpace * tallestLabelHeightInLines);

					minSize.height = Math.min(me.maxHeight, minSize.height + labelHeight);
					me.ctx.font = tickFont.font;

					var firstTick = me.ticks[0];
					var firstLabelWidth = computeTextSize(me.ctx, firstTick, tickFont.font);

					var lastTick = me.ticks[me.ticks.length - 1];
					var lastLabelWidth = computeTextSize(me.ctx, lastTick, tickFont.font);

					// Ensure that our ticks are always inside the canvas. When rotated, ticks are right aligned which means that the right padding is dominated
					// by the font height
					if (me.labelRotation !== 0) {
						me.paddingLeft = opts.position === 'bottom'? (cosRotation * firstLabelWidth) + 3: (cosRotation * lineSpace) + 3; // add 3 px to move away from canvas edges
						me.paddingRight = opts.position === 'bottom'? (cosRotation * lineSpace) + 3: (cosRotation * lastLabelWidth) + 3;
					} else {
						me.paddingLeft = firstLabelWidth / 2 + 3; // add 3 px to move away from canvas edges
						me.paddingRight = lastLabelWidth / 2 + 3;
					}
				} else {
					// A vertical axis is more constrained by the width. Labels are the dominant factor here, so get that length first
					// Account for padding

					if (tickOpts.mirror) {
						largestTextWidth = 0;
					} else {
						largestTextWidth += me.options.ticks.padding;
					}
					minSize.width = Math.min(me.maxWidth, minSize.width + largestTextWidth);
					me.paddingTop = tickFont.size / 2;
					me.paddingBottom = tickFont.size / 2;
				}
			}

			me.handleMargins();

			me.width = minSize.width;
			me.height = minSize.height;
		},

		/**
		 * Handle margins and padding interactions
		 * @private
		 */
		handleMargins: function() {
			var me = this;
			if (me.margins) {
				me.paddingLeft = Math.max(me.paddingLeft - me.margins.left, 0);
				me.paddingTop = Math.max(me.paddingTop - me.margins.top, 0);
				me.paddingRight = Math.max(me.paddingRight - me.margins.right, 0);
				me.paddingBottom = Math.max(me.paddingBottom - me.margins.bottom, 0);
			}
		},

		afterFit: function() {
			helpers.callback(this.options.afterFit, [this]);
		},

		// Shared Methods
		isHorizontal: function() {
			return this.options.position === 'top' || this.options.position === 'bottom';
		},
		isFullWidth: function() {
			return (this.options.fullWidth);
		},

		// Get the correct value. NaN bad inputs, If the value type is object get the x or y based on whether we are horizontal or not
		getRightValue: function(rawValue) {
			// Null and undefined values first
			if (rawValue === null || typeof(rawValue) === 'undefined') {
				return NaN;
			}
			// isNaN(object) returns true, so make sure NaN is checking for a number; Discard Infinite values
			if (typeof(rawValue) === 'number' && !isFinite(rawValue)) {
				return NaN;
			}
			// If it is in fact an object, dive in one more level
			if (typeof(rawValue) === 'object') {
				if ((rawValue instanceof Date) || (rawValue.isValid)) {
					return rawValue;
				}
				return this.getRightValue(this.isHorizontal() ? rawValue.x : rawValue.y);
			}

			// Value is good, return it
			return rawValue;
		},

		// Used to get the value to display in the tooltip for the data at the given index
		// function getLabelForIndex(index, datasetIndex)
		getLabelForIndex: helpers.noop,

		// Used to get data value locations.  Value can either be an index or a numerical value
		getPixelForValue: helpers.noop,

		// Used to get the data value from a given pixel. This is the inverse of getPixelForValue
		getValueForPixel: helpers.noop,

		// Used for tick location, should
		getPixelForTick: function(index, includeOffset) {
			var me = this;
			if (me.isHorizontal()) {
				var innerWidth = me.width - (me.paddingLeft + me.paddingRight);
				var tickWidth = innerWidth / Math.max((me.ticks.length - ((me.options.gridLines.offsetGridLines) ? 0 : 1)), 1);
				var pixel = (tickWidth * index) + me.paddingLeft;

				if (includeOffset) {
					pixel += tickWidth / 2;
				}

				var finalVal = me.left + Math.round(pixel);
				finalVal += me.isFullWidth() ? me.margins.left : 0;
				return finalVal;
			}
			var innerHeight = me.height - (me.paddingTop + me.paddingBottom);
			return me.top + (index * (innerHeight / (me.ticks.length - 1)));
		},

		// Utility for getting the pixel location of a percentage of scale
		getPixelForDecimal: function(decimal /* , includeOffset*/) {
			var me = this;
			if (me.isHorizontal()) {
				var innerWidth = me.width - (me.paddingLeft + me.paddingRight);
				var valueOffset = (innerWidth * decimal) + me.paddingLeft;

				var finalVal = me.left + Math.round(valueOffset);
				finalVal += me.isFullWidth() ? me.margins.left : 0;
				return finalVal;
			}
			return me.top + (decimal * me.height);
		},

		getBasePixel: function() {
			return this.getPixelForValue(this.getBaseValue());
		},

		getBaseValue: function() {
			var me = this;
			var min = me.min;
			var max = me.max;

			return me.beginAtZero ? 0:
				min < 0 && max < 0? max :
				min > 0 && max > 0? min :
				0;
		},

		// Actually draw the scale on the canvas
		// @param {rectangle} chartArea : the area of the chart to draw full grid lines on
		draw: function(chartArea) {
			var me = this;
			var options = me.options;
			if (!options.display) {
				return;
			}

			var context = me.ctx;
			var globalDefaults = Chart.defaults.global;
			var optionTicks = options.ticks;
			var gridLines = options.gridLines;
			var scaleLabel = options.scaleLabel;

			var isRotated = me.labelRotation !== 0;
			var skipRatio;
			var useAutoskipper = optionTicks.autoSkip;
			var isHorizontal = me.isHorizontal();

			// figure out the maximum number of gridlines to show
			var maxTicks;
			if (optionTicks.maxTicksLimit) {
				maxTicks = optionTicks.maxTicksLimit;
			}

			var tickFontColor = helpers.getValueOrDefault(optionTicks.fontColor, globalDefaults.defaultFontColor);
			var tickFont = parseFontOptions(optionTicks);

			var tl = gridLines.drawTicks ? gridLines.tickMarkLength : 0;

			var scaleLabelFontColor = helpers.getValueOrDefault(scaleLabel.fontColor, globalDefaults.defaultFontColor);
			var scaleLabelFont = parseFontOptions(scaleLabel);

			var labelRotationRadians = helpers.toRadians(me.labelRotation);
			var cosRotation = Math.cos(labelRotationRadians);
			var longestRotatedLabel = me.longestLabelWidth * cosRotation;

			// Make sure we draw text in the correct color and font
			context.fillStyle = tickFontColor;

			var itemsToDraw = [];

			if (isHorizontal) {
				skipRatio = false;

				if ((longestRotatedLabel + optionTicks.autoSkipPadding) * me.ticks.length > (me.width - (me.paddingLeft + me.paddingRight))) {
					skipRatio = 1 + Math.floor(((longestRotatedLabel + optionTicks.autoSkipPadding) * me.ticks.length) / (me.width - (me.paddingLeft + me.paddingRight)));
				}

				// if they defined a max number of optionTicks,
				// increase skipRatio until that number is met
				if (maxTicks && me.ticks.length > maxTicks) {
					while (!skipRatio || me.ticks.length / (skipRatio || 1) > maxTicks) {
						if (!skipRatio) {
							skipRatio = 1;
						}
						skipRatio += 1;
					}
				}

				if (!useAutoskipper) {
					skipRatio = false;
				}
			}


			var xTickStart = options.position === 'right' ? me.left : me.right - tl;
			var xTickEnd = options.position === 'right' ? me.left + tl : me.right;
			var yTickStart = options.position === 'bottom' ? me.top : me.bottom - tl;
			var yTickEnd = options.position === 'bottom' ? me.top + tl : me.bottom;

			helpers.each(me.ticks, function(label, index) {
				// If the callback returned a null or undefined value, do not draw this line
				if (label === undefined || label === null) {
					return;
				}

				var isLastTick = me.ticks.length === index + 1;

				// Since we always show the last tick,we need may need to hide the last shown one before
				var shouldSkip = (skipRatio > 1 && index % skipRatio > 0) || (index % skipRatio === 0 && index + skipRatio >= me.ticks.length);
				if (shouldSkip && !isLastTick || (label === undefined || label === null)) {
					return;
				}

				var lineWidth, lineColor, borderDash, borderDashOffset;
				if (index === (typeof me.zeroLineIndex !== 'undefined' ? me.zeroLineIndex : 0)) {
					// Draw the first index specially
					lineWidth = gridLines.zeroLineWidth;
					lineColor = gridLines.zeroLineColor;
					borderDash = gridLines.zeroLineBorderDash;
					borderDashOffset = gridLines.zeroLineBorderDashOffset;
				} else {
					lineWidth = helpers.getValueAtIndexOrDefault(gridLines.lineWidth, index);
					lineColor = helpers.getValueAtIndexOrDefault(gridLines.color, index);
					borderDash = helpers.getValueOrDefault(gridLines.borderDash, globalDefaults.borderDash);
					borderDashOffset = helpers.getValueOrDefault(gridLines.borderDashOffset, globalDefaults.borderDashOffset);
				}

				// Common properties
				var tx1, ty1, tx2, ty2, x1, y1, x2, y2, labelX, labelY;
				var textAlign = 'middle';
				var textBaseline = 'middle';

				if (isHorizontal) {

					if (options.position === 'bottom') {
						// bottom
						textBaseline = !isRotated? 'top':'middle';
						textAlign = !isRotated? 'center': 'right';
						labelY = me.top + tl;
					} else {
						// top
						textBaseline = !isRotated? 'bottom':'middle';
						textAlign = !isRotated? 'center': 'left';
						labelY = me.bottom - tl;
					}

					var xLineValue = me.getPixelForTick(index) + helpers.aliasPixel(lineWidth); // xvalues for grid lines
					labelX = me.getPixelForTick(index, gridLines.offsetGridLines) + optionTicks.labelOffset; // x values for optionTicks (need to consider offsetLabel option)

					tx1 = tx2 = x1 = x2 = xLineValue;
					ty1 = yTickStart;
					ty2 = yTickEnd;
					y1 = chartArea.top;
					y2 = chartArea.bottom;
				} else {
					var isLeft = options.position === 'left';
					var tickPadding = optionTicks.padding;
					var labelXOffset;

					if (optionTicks.mirror) {
						textAlign = isLeft ? 'left' : 'right';
						labelXOffset = tickPadding;
					} else {
						textAlign = isLeft ? 'right' : 'left';
						labelXOffset = tl + tickPadding;
					}

					labelX = isLeft ? me.right - labelXOffset : me.left + labelXOffset;

					var yLineValue = me.getPixelForTick(index); // xvalues for grid lines
					yLineValue += helpers.aliasPixel(lineWidth);
					labelY = me.getPixelForTick(index, gridLines.offsetGridLines);

					tx1 = xTickStart;
					tx2 = xTickEnd;
					x1 = chartArea.left;
					x2 = chartArea.right;
					ty1 = ty2 = y1 = y2 = yLineValue;
				}

				itemsToDraw.push({
					tx1: tx1,
					ty1: ty1,
					tx2: tx2,
					ty2: ty2,
					x1: x1,
					y1: y1,
					x2: x2,
					y2: y2,
					labelX: labelX,
					labelY: labelY,
					glWidth: lineWidth,
					glColor: lineColor,
					glBorderDash: borderDash,
					glBorderDashOffset: borderDashOffset,
					rotation: -1 * labelRotationRadians,
					label: label,
					textBaseline: textBaseline,
					textAlign: textAlign
				});
			});

			// Draw all of the tick labels, tick marks, and grid lines at the correct places
			helpers.each(itemsToDraw, function(itemToDraw) {
				if (gridLines.display) {
					context.save();
					context.lineWidth = itemToDraw.glWidth;
					context.strokeStyle = itemToDraw.glColor;
					if (context.setLineDash) {
						context.setLineDash(itemToDraw.glBorderDash);
						context.lineDashOffset = itemToDraw.glBorderDashOffset;
					}

					context.beginPath();

					if (gridLines.drawTicks) {
						context.moveTo(itemToDraw.tx1, itemToDraw.ty1);
						context.lineTo(itemToDraw.tx2, itemToDraw.ty2);
					}

					if (gridLines.drawOnChartArea) {
						context.moveTo(itemToDraw.x1, itemToDraw.y1);
						context.lineTo(itemToDraw.x2, itemToDraw.y2);
					}

					context.stroke();
					context.restore();
				}

				if (optionTicks.display) {
					context.save();
					context.translate(itemToDraw.labelX, itemToDraw.labelY);
					context.rotate(itemToDraw.rotation);
					context.font = tickFont.font;
					context.textBaseline = itemToDraw.textBaseline;
					context.textAlign = itemToDraw.textAlign;

					var label = itemToDraw.label;
					if (helpers.isArray(label)) {
						for (var i = 0, y = 0; i < label.length; ++i) {
							// We just make sure the multiline element is a string here..
							context.fillText('' + label[i], 0, y);
							// apply same lineSpacing as calculated @ L#320
							y += (tickFont.size * 1.5);
						}
					} else {
						context.fillText(label, 0, 0);
					}
					context.restore();
				}
			});

			if (scaleLabel.display) {
				// Draw the scale label
				var scaleLabelX;
				var scaleLabelY;
				var rotation = 0;

				if (isHorizontal) {
					scaleLabelX = me.left + ((me.right - me.left) / 2); // midpoint of the width
					scaleLabelY = options.position === 'bottom' ? me.bottom - (scaleLabelFont.size / 2) : me.top + (scaleLabelFont.size / 2);
				} else {
					var isLeft = options.position === 'left';
					scaleLabelX = isLeft ? me.left + (scaleLabelFont.size / 2) : me.right - (scaleLabelFont.size / 2);
					scaleLabelY = me.top + ((me.bottom - me.top) / 2);
					rotation = isLeft ? -0.5 * Math.PI : 0.5 * Math.PI;
				}

				context.save();
				context.translate(scaleLabelX, scaleLabelY);
				context.rotate(rotation);
				context.textAlign = 'center';
				context.textBaseline = 'middle';
				context.fillStyle = scaleLabelFontColor; // render in correct colour
				context.font = scaleLabelFont.font;
				context.fillText(scaleLabel.labelString, 0, 0);
				context.restore();
			}

			if (gridLines.drawBorder) {
				// Draw the line at the edge of the axis
				context.lineWidth = helpers.getValueAtIndexOrDefault(gridLines.lineWidth, 0);
				context.strokeStyle = helpers.getValueAtIndexOrDefault(gridLines.color, 0);
				var x1 = me.left,
					x2 = me.right,
					y1 = me.top,
					y2 = me.bottom;

				var aliasPixel = helpers.aliasPixel(context.lineWidth);
				if (isHorizontal) {
					y1 = y2 = options.position === 'top' ? me.bottom : me.top;
					y1 += aliasPixel;
					y2 += aliasPixel;
				} else {
					x1 = x2 = options.position === 'left' ? me.right : me.left;
					x1 += aliasPixel;
					x2 += aliasPixel;
				}

				context.beginPath();
				context.moveTo(x1, y1);
				context.lineTo(x2, y2);
				context.stroke();
			}
		}
	});
};

},{}],32:[function(require,module,exports){
'use strict';

module.exports = function(Chart) {

	var helpers = Chart.helpers;

	Chart.scaleService = {
		// Scale registration object. Extensions can register new scale types (such as log or DB scales) and then
		// use the new chart options to grab the correct scale
		constructors: {},
		// Use a registration function so that we can move to an ES6 map when we no longer need to support
		// old browsers

		// Scale config defaults
		defaults: {},
		registerScaleType: function(type, scaleConstructor, defaults) {
			this.constructors[type] = scaleConstructor;
			this.defaults[type] = helpers.clone(defaults);
		},
		getScaleConstructor: function(type) {
			return this.constructors.hasOwnProperty(type) ? this.constructors[type] : undefined;
		},
		getScaleDefaults: function(type) {
			// Return the scale defaults merged with the global settings so that we always use the latest ones
			return this.defaults.hasOwnProperty(type) ? helpers.scaleMerge(Chart.defaults.scale, this.defaults[type]) : {};
		},
		updateScaleDefaults: function(type, additions) {
			var defaults = this.defaults;
			if (defaults.hasOwnProperty(type)) {
				defaults[type] = helpers.extend(defaults[type], additions);
			}
		},
		addScalesToLayout: function(chart) {
			// Adds each scale to the chart.boxes array to be sized accordingly
			helpers.each(chart.scales, function(scale) {
				// Set ILayoutItem parameters for backwards compatibility
				scale.fullWidth = scale.options.fullWidth;
				scale.position = scale.options.position;
				scale.weight = scale.options.weight;
				Chart.layoutService.addBox(chart, scale);
			});
		}
	};
};

},{}],33:[function(require,module,exports){
'use strict';

module.exports = function(Chart) {

	var helpers = Chart.helpers;

	/**
	 * Namespace to hold static tick generation functions
	 * @namespace Chart.Ticks
	 */
	Chart.Ticks = {
		/**
		 * Namespace to hold generators for different types of ticks
		 * @namespace Chart.Ticks.generators
		 */
		generators: {
			/**
			 * Interface for the options provided to the numeric tick generator
			 * @interface INumericTickGenerationOptions
			 */
			/**
			 * The maximum number of ticks to display
			 * @name INumericTickGenerationOptions#maxTicks
			 * @type Number
			 */
			/**
			 * The distance between each tick.
			 * @name INumericTickGenerationOptions#stepSize
			 * @type Number
			 * @optional
			 */
			/**
			 * Forced minimum for the ticks. If not specified, the minimum of the data range is used to calculate the tick minimum
			 * @name INumericTickGenerationOptions#min
			 * @type Number
			 * @optional
			 */
			/**
			 * The maximum value of the ticks. If not specified, the maximum of the data range is used to calculate the tick maximum
			 * @name INumericTickGenerationOptions#max
			 * @type Number
			 * @optional
			 */

			/**
			 * Generate a set of linear ticks
			 * @method Chart.Ticks.generators.linear
			 * @param generationOptions {INumericTickGenerationOptions} the options used to generate the ticks
			 * @param dataRange {IRange} the range of the data
			 * @returns {Array<Number>} array of tick values
			 */
			linear: function(generationOptions, dataRange) {
				var ticks = [];
				// To get a "nice" value for the tick spacing, we will use the appropriately named
				// "nice number" algorithm. See http://stackoverflow.com/questions/8506881/nice-label-algorithm-for-charts-with-minimum-ticks
				// for details.

				var spacing;
				if (generationOptions.stepSize && generationOptions.stepSize > 0) {
					spacing = generationOptions.stepSize;
				} else {
					var niceRange = helpers.niceNum(dataRange.max - dataRange.min, false);
					spacing = helpers.niceNum(niceRange / (generationOptions.maxTicks - 1), true);
				}
				var niceMin = Math.floor(dataRange.min / spacing) * spacing;
				var niceMax = Math.ceil(dataRange.max / spacing) * spacing;

				// If min, max and stepSize is set and they make an evenly spaced scale use it.
				if (generationOptions.min && generationOptions.max && generationOptions.stepSize) {
					// If very close to our whole number, use it.
					if (helpers.almostWhole((generationOptions.max - generationOptions.min) / generationOptions.stepSize, spacing / 1000)) {
						niceMin = generationOptions.min;
						niceMax = generationOptions.max;
					}
				}

				var numSpaces = (niceMax - niceMin) / spacing;
				// If very close to our rounded value, use it.
				if (helpers.almostEquals(numSpaces, Math.round(numSpaces), spacing / 1000)) {
					numSpaces = Math.round(numSpaces);
				} else {
					numSpaces = Math.ceil(numSpaces);
				}

				// Put the values into the ticks array
				ticks.push(generationOptions.min !== undefined ? generationOptions.min : niceMin);
				for (var j = 1; j < numSpaces; ++j) {
					ticks.push(niceMin + (j * spacing));
				}
				ticks.push(generationOptions.max !== undefined ? generationOptions.max : niceMax);

				return ticks;
			},

			/**
			 * Generate a set of logarithmic ticks
			 * @method Chart.Ticks.generators.logarithmic
			 * @param generationOptions {INumericTickGenerationOptions} the options used to generate the ticks
			 * @param dataRange {IRange} the range of the data
			 * @returns {Array<Number>} array of tick values
			 */
			logarithmic: function(generationOptions, dataRange) {
				var ticks = [];
				var getValueOrDefault = helpers.getValueOrDefault;

				// Figure out what the max number of ticks we can support it is based on the size of
				// the axis area. For now, we say that the minimum tick spacing in pixels must be 50
				// We also limit the maximum number of ticks to 11 which gives a nice 10 squares on
				// the graph
				var tickVal = getValueOrDefault(generationOptions.min, Math.pow(10, Math.floor(helpers.log10(dataRange.min))));

				var endExp = Math.floor(helpers.log10(dataRange.max));
				var endSignificand = Math.ceil(dataRange.max / Math.pow(10, endExp));
				var exp;
				var significand;

				if (tickVal === 0) {
					exp = Math.floor(helpers.log10(dataRange.minNotZero));
					significand = Math.floor(dataRange.minNotZero / Math.pow(10, exp));

					ticks.push(tickVal);
					tickVal = significand * Math.pow(10, exp);
				} else {
					exp = Math.floor(helpers.log10(tickVal));
					significand = Math.floor(tickVal / Math.pow(10, exp));
				}

				do {
					ticks.push(tickVal);

					++significand;
					if (significand === 10) {
						significand = 1;
						++exp;
					}

					tickVal = significand * Math.pow(10, exp);
				} while (exp < endExp || (exp === endExp && significand < endSignificand));

				var lastTick = getValueOrDefault(generationOptions.max, tickVal);
				ticks.push(lastTick);

				return ticks;
			}
		},

		/**
		 * Namespace to hold formatters for different types of ticks
		 * @namespace Chart.Ticks.formatters
		 */
		formatters: {
			/**
			 * Formatter for value labels
			 * @method Chart.Ticks.formatters.values
			 * @param value the value to display
			 * @return {String|Array} the label to display
			 */
			values: function(value) {
				return helpers.isArray(value) ? value : '' + value;
			},

			/**
			 * Formatter for linear numeric ticks
			 * @method Chart.Ticks.formatters.linear
			 * @param tickValue {Number} the value to be formatted
			 * @param index {Number} the position of the tickValue parameter in the ticks array
			 * @param ticks {Array<Number>} the list of ticks being converted
			 * @return {String} string representation of the tickValue parameter
			 */
			linear: function(tickValue, index, ticks) {
				// If we have lots of ticks, don't use the ones
				var delta = ticks.length > 3 ? ticks[2] - ticks[1] : ticks[1] - ticks[0];

				// If we have a number like 2.5 as the delta, figure out how many decimal places we need
				if (Math.abs(delta) > 1) {
					if (tickValue !== Math.floor(tickValue)) {
						// not an integer
						delta = tickValue - Math.floor(tickValue);
					}
				}

				var logDelta = helpers.log10(Math.abs(delta));
				var tickString = '';

				if (tickValue !== 0) {
					var numDecimal = -1 * Math.floor(logDelta);
					numDecimal = Math.max(Math.min(numDecimal, 20), 0); // toFixed has a max of 20 decimal places
					tickString = tickValue.toFixed(numDecimal);
				} else {
					tickString = '0'; // never show decimal places for 0
				}

				return tickString;
			},

			logarithmic: function(tickValue, index, ticks) {
				var remain = tickValue / (Math.pow(10, Math.floor(helpers.log10(tickValue))));

				if (tickValue === 0) {
					return '0';
				} else if (remain === 1 || remain === 2 || remain === 5 || index === 0 || index === ticks.length - 1) {
					return tickValue.toExponential();
				}
				return '';
			}
		}
	};
};

},{}],34:[function(require,module,exports){
'use strict';

module.exports = function(Chart) {

	var helpers = Chart.helpers;

	/**
 	 * Helper method to merge the opacity into a color
 	 */
	function mergeOpacity(colorString, opacity) {
		var color = helpers.color(colorString);
		return color.alpha(opacity * color.alpha()).rgbaString();
	}

	Chart.defaults.global.tooltips = {
		enabled: true,
		custom: null,
		mode: 'nearest',
		position: 'average',
		intersect: true,
		backgroundColor: 'rgba(0,0,0,0.8)',
		titleFontStyle: 'bold',
		titleSpacing: 2,
		titleMarginBottom: 6,
		titleFontColor: '#fff',
		titleAlign: 'left',
		bodySpacing: 2,
		bodyFontColor: '#fff',
		bodyAlign: 'left',
		footerFontStyle: 'bold',
		footerSpacing: 2,
		footerMarginTop: 6,
		footerFontColor: '#fff',
		footerAlign: 'left',
		yPadding: 6,
		xPadding: 6,
		caretPadding: 2,
		caretSize: 5,
		cornerRadius: 6,
		multiKeyBackground: '#fff',
		displayColors: true,
		borderColor: 'rgba(0,0,0,0)',
		borderWidth: 0,
		callbacks: {
			// Args are: (tooltipItems, data)
			beforeTitle: helpers.noop,
			title: function(tooltipItems, data) {
				// Pick first xLabel for now
				var title = '';
				var labels = data.labels;
				var labelCount = labels ? labels.length : 0;

				if (tooltipItems.length > 0) {
					var item = tooltipItems[0];

					if (item.xLabel) {
						title = item.xLabel;
					} else if (labelCount > 0 && item.index < labelCount) {
						title = labels[item.index];
					}
				}

				return title;
			},
			afterTitle: helpers.noop,

			// Args are: (tooltipItems, data)
			beforeBody: helpers.noop,

			// Args are: (tooltipItem, data)
			beforeLabel: helpers.noop,
			label: function(tooltipItem, data) {
				var label = data.datasets[tooltipItem.datasetIndex].label || '';

				if (label) {
					label += ': ';
				}
				label += tooltipItem.yLabel;
				return label;
			},
			labelColor: function(tooltipItem, chart) {
				var meta = chart.getDatasetMeta(tooltipItem.datasetIndex);
				var activeElement = meta.data[tooltipItem.index];
				var view = activeElement._view;
				return {
					borderColor: view.borderColor,
					backgroundColor: view.backgroundColor
				};
			},
			afterLabel: helpers.noop,

			// Args are: (tooltipItems, data)
			afterBody: helpers.noop,

			// Args are: (tooltipItems, data)
			beforeFooter: helpers.noop,
			footer: helpers.noop,
			afterFooter: helpers.noop
		}
	};

	// Helper to push or concat based on if the 2nd parameter is an array or not
	function pushOrConcat(base, toPush) {
		if (toPush) {
			if (helpers.isArray(toPush)) {
				// base = base.concat(toPush);
				Array.prototype.push.apply(base, toPush);
			} else {
				base.push(toPush);
			}
		}

		return base;
	}

	// Private helper to create a tooltip item model
	// @param element : the chart element (point, arc, bar) to create the tooltip item for
	// @return : new tooltip item
	function createTooltipItem(element) {
		var xScale = element._xScale;
		var yScale = element._yScale || element._scale; // handle radar || polarArea charts
		var index = element._index,
			datasetIndex = element._datasetIndex;

		return {
			xLabel: xScale ? xScale.getLabelForIndex(index, datasetIndex) : '',
			yLabel: yScale ? yScale.getLabelForIndex(index, datasetIndex) : '',
			index: index,
			datasetIndex: datasetIndex,
			x: element._model.x,
			y: element._model.y
		};
	}

	/**
	 * Helper to get the reset model for the tooltip
	 * @param tooltipOpts {Object} the tooltip options
	 */
	function getBaseModel(tooltipOpts) {
		var globalDefaults = Chart.defaults.global;
		var getValueOrDefault = helpers.getValueOrDefault;

		return {
			// Positioning
			xPadding: tooltipOpts.xPadding,
			yPadding: tooltipOpts.yPadding,
			xAlign: tooltipOpts.xAlign,
			yAlign: tooltipOpts.yAlign,

			// Body
			bodyFontColor: tooltipOpts.bodyFontColor,
			_bodyFontFamily: getValueOrDefault(tooltipOpts.bodyFontFamily, globalDefaults.defaultFontFamily),
			_bodyFontStyle: getValueOrDefault(tooltipOpts.bodyFontStyle, globalDefaults.defaultFontStyle),
			_bodyAlign: tooltipOpts.bodyAlign,
			bodyFontSize: getValueOrDefault(tooltipOpts.bodyFontSize, globalDefaults.defaultFontSize),
			bodySpacing: tooltipOpts.bodySpacing,

			// Title
			titleFontColor: tooltipOpts.titleFontColor,
			_titleFontFamily: getValueOrDefault(tooltipOpts.titleFontFamily, globalDefaults.defaultFontFamily),
			_titleFontStyle: getValueOrDefault(tooltipOpts.titleFontStyle, globalDefaults.defaultFontStyle),
			titleFontSize: getValueOrDefault(tooltipOpts.titleFontSize, globalDefaults.defaultFontSize),
			_titleAlign: tooltipOpts.titleAlign,
			titleSpacing: tooltipOpts.titleSpacing,
			titleMarginBottom: tooltipOpts.titleMarginBottom,

			// Footer
			footerFontColor: tooltipOpts.footerFontColor,
			_footerFontFamily: getValueOrDefault(tooltipOpts.footerFontFamily, globalDefaults.defaultFontFamily),
			_footerFontStyle: getValueOrDefault(tooltipOpts.footerFontStyle, globalDefaults.defaultFontStyle),
			footerFontSize: getValueOrDefault(tooltipOpts.footerFontSize, globalDefaults.defaultFontSize),
			_footerAlign: tooltipOpts.footerAlign,
			footerSpacing: tooltipOpts.footerSpacing,
			footerMarginTop: tooltipOpts.footerMarginTop,

			// Appearance
			caretSize: tooltipOpts.caretSize,
			cornerRadius: tooltipOpts.cornerRadius,
			backgroundColor: tooltipOpts.backgroundColor,
			opacity: 0,
			legendColorBackground: tooltipOpts.multiKeyBackground,
			displayColors: tooltipOpts.displayColors,
			borderColor: tooltipOpts.borderColor,
			borderWidth: tooltipOpts.borderWidth
		};
	}

	/**
	 * Get the size of the tooltip
	 */
	function getTooltipSize(tooltip, model) {
		var ctx = tooltip._chart.ctx;

		var height = model.yPadding * 2; // Tooltip Padding
		var width = 0;

		// Count of all lines in the body
		var body = model.body;
		var combinedBodyLength = body.reduce(function(count, bodyItem) {
			return count + bodyItem.before.length + bodyItem.lines.length + bodyItem.after.length;
		}, 0);
		combinedBodyLength += model.beforeBody.length + model.afterBody.length;

		var titleLineCount = model.title.length;
		var footerLineCount = model.footer.length;
		var titleFontSize = model.titleFontSize,
			bodyFontSize = model.bodyFontSize,
			footerFontSize = model.footerFontSize;

		height += titleLineCount * titleFontSize; // Title Lines
		height += titleLineCount ? (titleLineCount - 1) * model.titleSpacing : 0; // Title Line Spacing
		height += titleLineCount ? model.titleMarginBottom : 0; // Title's bottom Margin
		height += combinedBodyLength * bodyFontSize; // Body Lines
		height += combinedBodyLength ? (combinedBodyLength - 1) * model.bodySpacing : 0; // Body Line Spacing
		height += footerLineCount ? model.footerMarginTop : 0; // Footer Margin
		height += footerLineCount * (footerFontSize); // Footer Lines
		height += footerLineCount ? (footerLineCount - 1) * model.footerSpacing : 0; // Footer Line Spacing

		// Title width
		var widthPadding = 0;
		var maxLineWidth = function(line) {
			width = Math.max(width, ctx.measureText(line).width + widthPadding);
		};

		ctx.font = helpers.fontString(titleFontSize, model._titleFontStyle, model._titleFontFamily);
		helpers.each(model.title, maxLineWidth);

		// Body width
		ctx.font = helpers.fontString(bodyFontSize, model._bodyFontStyle, model._bodyFontFamily);
		helpers.each(model.beforeBody.concat(model.afterBody), maxLineWidth);

		// Body lines may include some extra width due to the color box
		widthPadding = model.displayColors ? (bodyFontSize + 2) : 0;
		helpers.each(body, function(bodyItem) {
			helpers.each(bodyItem.before, maxLineWidth);
			helpers.each(bodyItem.lines, maxLineWidth);
			helpers.each(bodyItem.after, maxLineWidth);
		});

		// Reset back to 0
		widthPadding = 0;

		// Footer width
		ctx.font = helpers.fontString(footerFontSize, model._footerFontStyle, model._footerFontFamily);
		helpers.each(model.footer, maxLineWidth);

		// Add padding
		width += 2 * model.xPadding;

		return {
			width: width,
			height: height
		};
	}

	/**
	 * Helper to get the alignment of a tooltip given the size
	 */
	function determineAlignment(tooltip, size) {
		var model = tooltip._model;
		var chart = tooltip._chart;
		var chartArea = tooltip._chart.chartArea;
		var xAlign = 'center';
		var yAlign = 'center';

		if (model.y < size.height) {
			yAlign = 'top';
		} else if (model.y > (chart.height - size.height)) {
			yAlign = 'bottom';
		}

		var lf, rf; // functions to determine left, right alignment
		var olf, orf; // functions to determine if left/right alignment causes tooltip to go outside chart
		var yf; // function to get the y alignment if the tooltip goes outside of the left or right edges
		var midX = (chartArea.left + chartArea.right) / 2;
		var midY = (chartArea.top + chartArea.bottom) / 2;

		if (yAlign === 'center') {
			lf = function(x) {
				return x <= midX;
			};
			rf = function(x) {
				return x > midX;
			};
		} else {
			lf = function(x) {
				return x <= (size.width / 2);
			};
			rf = function(x) {
				return x >= (chart.width - (size.width / 2));
			};
		}

		olf = function(x) {
			return x + size.width > chart.width;
		};
		orf = function(x) {
			return x - size.width < 0;
		};
		yf = function(y) {
			return y <= midY ? 'top' : 'bottom';
		};

		if (lf(model.x)) {
			xAlign = 'left';

			// Is tooltip too wide and goes over the right side of the chart.?
			if (olf(model.x)) {
				xAlign = 'center';
				yAlign = yf(model.y);
			}
		} else if (rf(model.x)) {
			xAlign = 'right';

			// Is tooltip too wide and goes outside left edge of canvas?
			if (orf(model.x)) {
				xAlign = 'center';
				yAlign = yf(model.y);
			}
		}

		var opts = tooltip._options;
		return {
			xAlign: opts.xAlign ? opts.xAlign : xAlign,
			yAlign: opts.yAlign ? opts.yAlign : yAlign
		};
	}

	/**
	 * @Helper to get the location a tooltip needs to be placed at given the initial position (via the vm) and the size and alignment
	 */
	function getBackgroundPoint(vm, size, alignment) {
		// Background Position
		var x = vm.x;
		var y = vm.y;

		var caretSize = vm.caretSize,
			caretPadding = vm.caretPadding,
			cornerRadius = vm.cornerRadius,
			xAlign = alignment.xAlign,
			yAlign = alignment.yAlign,
			paddingAndSize = caretSize + caretPadding,
			radiusAndPadding = cornerRadius + caretPadding;

		if (xAlign === 'right') {
			x -= size.width;
		} else if (xAlign === 'center') {
			x -= (size.width / 2);
		}

		if (yAlign === 'top') {
			y += paddingAndSize;
		} else if (yAlign === 'bottom') {
			y -= size.height + paddingAndSize;
		} else {
			y -= (size.height / 2);
		}

		if (yAlign === 'center') {
			if (xAlign === 'left') {
				x += paddingAndSize;
			} else if (xAlign === 'right') {
				x -= paddingAndSize;
			}
		} else if (xAlign === 'left') {
			x -= radiusAndPadding;
		} else if (xAlign === 'right') {
			x += radiusAndPadding;
		}

		return {
			x: x,
			y: y
		};
	}

	Chart.Tooltip = Chart.Element.extend({
		initialize: function() {
			this._model = getBaseModel(this._options);
		},

		// Get the title
		// Args are: (tooltipItem, data)
		getTitle: function() {
			var me = this;
			var opts = me._options;
			var callbacks = opts.callbacks;

			var beforeTitle = callbacks.beforeTitle.apply(me, arguments),
				title = callbacks.title.apply(me, arguments),
				afterTitle = callbacks.afterTitle.apply(me, arguments);

			var lines = [];
			lines = pushOrConcat(lines, beforeTitle);
			lines = pushOrConcat(lines, title);
			lines = pushOrConcat(lines, afterTitle);

			return lines;
		},

		// Args are: (tooltipItem, data)
		getBeforeBody: function() {
			var lines = this._options.callbacks.beforeBody.apply(this, arguments);
			return helpers.isArray(lines) ? lines : lines !== undefined ? [lines] : [];
		},

		// Args are: (tooltipItem, data)
		getBody: function(tooltipItems, data) {
			var me = this;
			var callbacks = me._options.callbacks;
			var bodyItems = [];

			helpers.each(tooltipItems, function(tooltipItem) {
				var bodyItem = {
					before: [],
					lines: [],
					after: []
				};
				pushOrConcat(bodyItem.before, callbacks.beforeLabel.call(me, tooltipItem, data));
				pushOrConcat(bodyItem.lines, callbacks.label.call(me, tooltipItem, data));
				pushOrConcat(bodyItem.after, callbacks.afterLabel.call(me, tooltipItem, data));

				bodyItems.push(bodyItem);
			});

			return bodyItems;
		},

		// Args are: (tooltipItem, data)
		getAfterBody: function() {
			var lines = this._options.callbacks.afterBody.apply(this, arguments);
			return helpers.isArray(lines) ? lines : lines !== undefined ? [lines] : [];
		},

		// Get the footer and beforeFooter and afterFooter lines
		// Args are: (tooltipItem, data)
		getFooter: function() {
			var me = this;
			var callbacks = me._options.callbacks;

			var beforeFooter = callbacks.beforeFooter.apply(me, arguments);
			var footer = callbacks.footer.apply(me, arguments);
			var afterFooter = callbacks.afterFooter.apply(me, arguments);

			var lines = [];
			lines = pushOrConcat(lines, beforeFooter);
			lines = pushOrConcat(lines, footer);
			lines = pushOrConcat(lines, afterFooter);

			return lines;
		},

		update: function(changed) {
			var me = this;
			var opts = me._options;

			// Need to regenerate the model because its faster than using extend and it is necessary due to the optimization in Chart.Element.transition
			// that does _view = _model if ease === 1. This causes the 2nd tooltip update to set properties in both the view and model at the same time
			// which breaks any animations.
			var existingModel = me._model;
			var model = me._model = getBaseModel(opts);
			var active = me._active;

			var data = me._data;

			// In the case where active.length === 0 we need to keep these at existing values for good animations
			var alignment = {
				xAlign: existingModel.xAlign,
				yAlign: existingModel.yAlign
			};
			var backgroundPoint = {
				x: existingModel.x,
				y: existingModel.y
			};
			var tooltipSize = {
				width: existingModel.width,
				height: existingModel.height
			};
			var tooltipPosition = {
				x: existingModel.caretX,
				y: existingModel.caretY
			};

			var i, len;

			if (active.length) {
				model.opacity = 1;

				var labelColors = [];
				tooltipPosition = Chart.Tooltip.positioners[opts.position](active, me._eventPosition);

				var tooltipItems = [];
				for (i = 0, len = active.length; i < len; ++i) {
					tooltipItems.push(createTooltipItem(active[i]));
				}

				// If the user provided a filter function, use it to modify the tooltip items
				if (opts.filter) {
					tooltipItems = tooltipItems.filter(function(a) {
						return opts.filter(a, data);
					});
				}

				// If the user provided a sorting function, use it to modify the tooltip items
				if (opts.itemSort) {
					tooltipItems = tooltipItems.sort(function(a, b) {
						return opts.itemSort(a, b, data);
					});
				}

				// Determine colors for boxes
				helpers.each(tooltipItems, function(tooltipItem) {
					labelColors.push(opts.callbacks.labelColor.call(me, tooltipItem, me._chart));
				});

				// Build the Text Lines
				model.title = me.getTitle(tooltipItems, data);
				model.beforeBody = me.getBeforeBody(tooltipItems, data);
				model.body = me.getBody(tooltipItems, data);
				model.afterBody = me.getAfterBody(tooltipItems, data);
				model.footer = me.getFooter(tooltipItems, data);

				// Initial positioning and colors
				model.x = Math.round(tooltipPosition.x);
				model.y = Math.round(tooltipPosition.y);
				model.caretPadding = opts.caretPadding;
				model.labelColors = labelColors;

				// data points
				model.dataPoints = tooltipItems;

				// We need to determine alignment of the tooltip
				tooltipSize = getTooltipSize(this, model);
				alignment = determineAlignment(this, tooltipSize);
				// Final Size and Position
				backgroundPoint = getBackgroundPoint(model, tooltipSize, alignment);
			} else {
				model.opacity = 0;
			}

			model.xAlign = alignment.xAlign;
			model.yAlign = alignment.yAlign;
			model.x = backgroundPoint.x;
			model.y = backgroundPoint.y;
			model.width = tooltipSize.width;
			model.height = tooltipSize.height;

			// Point where the caret on the tooltip points to
			model.caretX = tooltipPosition.x;
			model.caretY = tooltipPosition.y;

			me._model = model;

			if (changed && opts.custom) {
				opts.custom.call(me, model);
			}

			return me;
		},
		drawCaret: function(tooltipPoint, size) {
			var ctx = this._chart.ctx;
			var vm = this._view;
			var caretPosition = this.getCaretPosition(tooltipPoint, size, vm);

			ctx.lineTo(caretPosition.x1, caretPosition.y1);
			ctx.lineTo(caretPosition.x2, caretPosition.y2);
			ctx.lineTo(caretPosition.x3, caretPosition.y3);
		},
		getCaretPosition: function(tooltipPoint, size, vm) {
			var x1, x2, x3;
			var y1, y2, y3;
			var caretSize = vm.caretSize;
			var cornerRadius = vm.cornerRadius;
			var xAlign = vm.xAlign,
				yAlign = vm.yAlign;
			var ptX = tooltipPoint.x,
				ptY = tooltipPoint.y;
			var width = size.width,
				height = size.height;

			if (yAlign === 'center') {
				y2 = ptY + (height / 2);

				if (xAlign === 'left') {
					x1 = ptX;
					x2 = x1 - caretSize;
					x3 = x1;

					y1 = y2 + caretSize;
					y3 = y2 - caretSize;
				} else {
					x1 = ptX + width;
					x2 = x1 + caretSize;
					x3 = x1;

					y1 = y2 - caretSize;
					y3 = y2 + caretSize;
				}
			} else {
				if (xAlign === 'left') {
					x2 = ptX + cornerRadius + (caretSize);
					x1 = x2 - caretSize;
					x3 = x2 + caretSize;
				} else if (xAlign === 'right') {
					x2 = ptX + width - cornerRadius - caretSize;
					x1 = x2 - caretSize;
					x3 = x2 + caretSize;
				} else {
					x2 = ptX + (width / 2);
					x1 = x2 - caretSize;
					x3 = x2 + caretSize;
				}
				if (yAlign === 'top') {
					y1 = ptY;
					y2 = y1 - caretSize;
					y3 = y1;
				} else {
					y1 = ptY + height;
					y2 = y1 + caretSize;
					y3 = y1;
					// invert drawing order
					var tmp = x3;
					x3 = x1;
					x1 = tmp;
				}
			}
			return {x1: x1, x2: x2, x3: x3, y1: y1, y2: y2, y3: y3};
		},
		drawTitle: function(pt, vm, ctx, opacity) {
			var title = vm.title;

			if (title.length) {
				ctx.textAlign = vm._titleAlign;
				ctx.textBaseline = 'top';

				var titleFontSize = vm.titleFontSize,
					titleSpacing = vm.titleSpacing;

				ctx.fillStyle = mergeOpacity(vm.titleFontColor, opacity);
				ctx.font = helpers.fontString(titleFontSize, vm._titleFontStyle, vm._titleFontFamily);

				var i, len;
				for (i = 0, len = title.length; i < len; ++i) {
					ctx.fillText(title[i], pt.x, pt.y);
					pt.y += titleFontSize + titleSpacing; // Line Height and spacing

					if (i + 1 === title.length) {
						pt.y += vm.titleMarginBottom - titleSpacing; // If Last, add margin, remove spacing
					}
				}
			}
		},
		drawBody: function(pt, vm, ctx, opacity) {
			var bodyFontSize = vm.bodyFontSize;
			var bodySpacing = vm.bodySpacing;
			var body = vm.body;

			ctx.textAlign = vm._bodyAlign;
			ctx.textBaseline = 'top';

			var textColor = mergeOpacity(vm.bodyFontColor, opacity);
			ctx.fillStyle = textColor;
			ctx.font = helpers.fontString(bodyFontSize, vm._bodyFontStyle, vm._bodyFontFamily);

			// Before Body
			var xLinePadding = 0;
			var fillLineOfText = function(line) {
				ctx.fillText(line, pt.x + xLinePadding, pt.y);
				pt.y += bodyFontSize + bodySpacing;
			};

			// Before body lines
			helpers.each(vm.beforeBody, fillLineOfText);

			var drawColorBoxes = vm.displayColors;
			xLinePadding = drawColorBoxes ? (bodyFontSize + 2) : 0;

			// Draw body lines now
			helpers.each(body, function(bodyItem, i) {
				helpers.each(bodyItem.before, fillLineOfText);

				helpers.each(bodyItem.lines, function(line) {
					// Draw Legend-like boxes if needed
					if (drawColorBoxes) {
						// Fill a white rect so that colours merge nicely if the opacity is < 1
						ctx.fillStyle = mergeOpacity(vm.legendColorBackground, opacity);
						ctx.fillRect(pt.x, pt.y, bodyFontSize, bodyFontSize);

						// Border
						ctx.strokeStyle = mergeOpacity(vm.labelColors[i].borderColor, opacity);
						ctx.strokeRect(pt.x, pt.y, bodyFontSize, bodyFontSize);

						// Inner square
						ctx.fillStyle = mergeOpacity(vm.labelColors[i].backgroundColor, opacity);
						ctx.fillRect(pt.x + 1, pt.y + 1, bodyFontSize - 2, bodyFontSize - 2);

						ctx.fillStyle = textColor;
					}

					fillLineOfText(line);
				});

				helpers.each(bodyItem.after, fillLineOfText);
			});

			// Reset back to 0 for after body
			xLinePadding = 0;

			// After body lines
			helpers.each(vm.afterBody, fillLineOfText);
			pt.y -= bodySpacing; // Remove last body spacing
		},
		drawFooter: function(pt, vm, ctx, opacity) {
			var footer = vm.footer;

			if (footer.length) {
				pt.y += vm.footerMarginTop;

				ctx.textAlign = vm._footerAlign;
				ctx.textBaseline = 'top';

				ctx.fillStyle = mergeOpacity(vm.footerFontColor, opacity);
				ctx.font = helpers.fontString(vm.footerFontSize, vm._footerFontStyle, vm._footerFontFamily);

				helpers.each(footer, function(line) {
					ctx.fillText(line, pt.x, pt.y);
					pt.y += vm.footerFontSize + vm.footerSpacing;
				});
			}
		},
		drawBackground: function(pt, vm, ctx, tooltipSize, opacity) {
			ctx.fillStyle = mergeOpacity(vm.backgroundColor, opacity);
			ctx.strokeStyle = mergeOpacity(vm.borderColor, opacity);
			ctx.lineWidth = vm.borderWidth;
			var xAlign = vm.xAlign;
			var yAlign = vm.yAlign;
			var x = pt.x;
			var y = pt.y;
			var width = tooltipSize.width;
			var height = tooltipSize.height;
			var radius = vm.cornerRadius;

			ctx.beginPath();
			ctx.moveTo(x + radius, y);
			if (yAlign === 'top') {
				this.drawCaret(pt, tooltipSize);
			}
			ctx.lineTo(x + width - radius, y);
			ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
			if (yAlign === 'center' && xAlign === 'right') {
				this.drawCaret(pt, tooltipSize);
			}
			ctx.lineTo(x + width, y + height - radius);
			ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
			if (yAlign === 'bottom') {
				this.drawCaret(pt, tooltipSize);
			}
			ctx.lineTo(x + radius, y + height);
			ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
			if (yAlign === 'center' && xAlign === 'left') {
				this.drawCaret(pt, tooltipSize);
			}
			ctx.lineTo(x, y + radius);
			ctx.quadraticCurveTo(x, y, x + radius, y);
			ctx.closePath();

			ctx.fill();

			if (vm.borderWidth > 0) {
				ctx.stroke();
			}
		},
		draw: function() {
			var ctx = this._chart.ctx;
			var vm = this._view;

			if (vm.opacity === 0) {
				return;
			}

			var tooltipSize = {
				width: vm.width,
				height: vm.height
			};
			var pt = {
				x: vm.x,
				y: vm.y
			};

			// IE11/Edge does not like very small opacities, so snap to 0
			var opacity = Math.abs(vm.opacity < 1e-3) ? 0 : vm.opacity;

			// Truthy/falsey value for empty tooltip
			var hasTooltipContent = vm.title.length || vm.beforeBody.length || vm.body.length || vm.afterBody.length || vm.footer.length;

			if (this._options.enabled && hasTooltipContent) {
				// Draw Background
				this.drawBackground(pt, vm, ctx, tooltipSize, opacity);

				// Draw Title, Body, and Footer
				pt.x += vm.xPadding;
				pt.y += vm.yPadding;

				// Titles
				this.drawTitle(pt, vm, ctx, opacity);

				// Body
				this.drawBody(pt, vm, ctx, opacity);

				// Footer
				this.drawFooter(pt, vm, ctx, opacity);
			}
		},

		/**
		 * Handle an event
		 * @private
		 * @param {IEvent} event - The event to handle
		 * @returns {Boolean} true if the tooltip changed
		 */
		handleEvent: function(e) {
			var me = this;
			var options = me._options;
			var changed = false;

			me._lastActive = me._lastActive || [];

			// Find Active Elements for tooltips
			if (e.type === 'mouseout') {
				me._active = [];
			} else {
				me._active = me._chart.getElementsAtEventForMode(e, options.mode, options);
			}

			// Remember Last Actives
			changed = !helpers.arrayEquals(me._active, me._lastActive);

			// If tooltip didn't change, do not handle the target event
			if (!changed) {
				return false;
			}

			me._lastActive = me._active;

			if (options.enabled || options.custom) {
				me._eventPosition = {
					x: e.x,
					y: e.y
				};

				var model = me._model;
				me.update(true);
				me.pivot();

				// See if our tooltip position changed
				changed |= (model.x !== me._model.x) || (model.y !== me._model.y);
			}

			return changed;
		}
	});

	/**
	 * @namespace Chart.Tooltip.positioners
	 */
	Chart.Tooltip.positioners = {
		/**
		 * Average mode places the tooltip at the average position of the elements shown
		 * @function Chart.Tooltip.positioners.average
		 * @param elements {ChartElement[]} the elements being displayed in the tooltip
		 * @returns {Point} tooltip position
		 */
		average: function(elements) {
			if (!elements.length) {
				return false;
			}

			var i, len;
			var x = 0;
			var y = 0;
			var count = 0;

			for (i = 0, len = elements.length; i < len; ++i) {
				var el = elements[i];
				if (el && el.hasValue()) {
					var pos = el.tooltipPosition();
					x += pos.x;
					y += pos.y;
					++count;
				}
			}

			return {
				x: Math.round(x / count),
				y: Math.round(y / count)
			};
		},

		/**
		 * Gets the tooltip position nearest of the item nearest to the event position
		 * @function Chart.Tooltip.positioners.nearest
		 * @param elements {Chart.Element[]} the tooltip elements
		 * @param eventPosition {Point} the position of the event in canvas coordinates
		 * @returns {Point} the tooltip position
		 */
		nearest: function(elements, eventPosition) {
			var x = eventPosition.x;
			var y = eventPosition.y;

			var nearestElement;
			var minDistance = Number.POSITIVE_INFINITY;
			var i, len;
			for (i = 0, len = elements.length; i < len; ++i) {
				var el = elements[i];
				if (el && el.hasValue()) {
					var center = el.getCenterPoint();
					var d = helpers.distanceBetweenPoints(eventPosition, center);

					if (d < minDistance) {
						minDistance = d;
						nearestElement = el;
					}
				}
			}

			if (nearestElement) {
				var tp = nearestElement.tooltipPosition();
				x = tp.x;
				y = tp.y;
			}

			return {
				x: x,
				y: y
			};
		}
	};
};

},{}],35:[function(require,module,exports){
'use strict';

module.exports = function(Chart) {

	var helpers = Chart.helpers,
		globalOpts = Chart.defaults.global;

	globalOpts.elements.arc = {
		backgroundColor: globalOpts.defaultColor,
		borderColor: '#fff',
		borderWidth: 2
	};

	Chart.elements.Arc = Chart.Element.extend({
		inLabelRange: function(mouseX) {
			var vm = this._view;

			if (vm) {
				return (Math.pow(mouseX - vm.x, 2) < Math.pow(vm.radius + vm.hoverRadius, 2));
			}
			return false;
		},
		inRange: function(chartX, chartY) {
			var vm = this._view;

			if (vm) {
				var pointRelativePosition = helpers.getAngleFromPoint(vm, {
						x: chartX,
						y: chartY
					}),
					angle = pointRelativePosition.angle,
					distance = pointRelativePosition.distance;

				// Sanitise angle range
				var startAngle = vm.startAngle;
				var endAngle = vm.endAngle;
				while (endAngle < startAngle) {
					endAngle += 2.0 * Math.PI;
				}
				while (angle > endAngle) {
					angle -= 2.0 * Math.PI;
				}
				while (angle < startAngle) {
					angle += 2.0 * Math.PI;
				}

				// Check if within the range of the open/close angle
				var betweenAngles = (angle >= startAngle && angle <= endAngle),
					withinRadius = (distance >= vm.innerRadius && distance <= vm.outerRadius);

				return (betweenAngles && withinRadius);
			}
			return false;
		},
		getCenterPoint: function() {
			var vm = this._view;
			var halfAngle = (vm.startAngle + vm.endAngle) / 2;
			var halfRadius = (vm.innerRadius + vm.outerRadius) / 2;
			return {
				x: vm.x + Math.cos(halfAngle) * halfRadius,
				y: vm.y + Math.sin(halfAngle) * halfRadius
			};
		},
		getArea: function() {
			var vm = this._view;
			return Math.PI * ((vm.endAngle - vm.startAngle) / (2 * Math.PI)) * (Math.pow(vm.outerRadius, 2) - Math.pow(vm.innerRadius, 2));
		},
		tooltipPosition: function() {
			var vm = this._view;

			var centreAngle = vm.startAngle + ((vm.endAngle - vm.startAngle) / 2),
				rangeFromCentre = (vm.outerRadius - vm.innerRadius) / 2 + vm.innerRadius;
			return {
				x: vm.x + (Math.cos(centreAngle) * rangeFromCentre),
				y: vm.y + (Math.sin(centreAngle) * rangeFromCentre)
			};
		},
		draw: function() {

			var ctx = this._chart.ctx,
				vm = this._view,
				sA = vm.startAngle,
				eA = vm.endAngle;

			ctx.beginPath();

			ctx.arc(vm.x, vm.y, vm.outerRadius, sA, eA);
			ctx.arc(vm.x, vm.y, vm.innerRadius, eA, sA, true);

			ctx.closePath();
			ctx.strokeStyle = vm.borderColor;
			ctx.lineWidth = vm.borderWidth;

			ctx.fillStyle = vm.backgroundColor;

			ctx.fill();
			ctx.lineJoin = 'bevel';

			if (vm.borderWidth) {
				ctx.stroke();
			}
		}
	});
};

},{}],36:[function(require,module,exports){
'use strict';

module.exports = function(Chart) {

	var helpers = Chart.helpers;
	var globalDefaults = Chart.defaults.global;

	Chart.defaults.global.elements.line = {
		tension: 0.4,
		backgroundColor: globalDefaults.defaultColor,
		borderWidth: 3,
		borderColor: globalDefaults.defaultColor,
		borderCapStyle: 'butt',
		borderDash: [],
		borderDashOffset: 0.0,
		borderJoinStyle: 'miter',
		capBezierPoints: true,
		fill: true, // do we fill in the area between the line and its base axis
	};

	Chart.elements.Line = Chart.Element.extend({
		draw: function() {
			var me = this;
			var vm = me._view;
			var ctx = me._chart.ctx;
			var spanGaps = vm.spanGaps;
			var points = me._children.slice(); // clone array
			var globalOptionLineElements = globalDefaults.elements.line;
			var lastDrawnIndex = -1;
			var index, current, previous, currentVM;

			// If we are looping, adding the first point again
			if (me._loop && points.length) {
				points.push(points[0]);
			}

			ctx.save();

			// Stroke Line Options
			ctx.lineCap = vm.borderCapStyle || globalOptionLineElements.borderCapStyle;

			// IE 9 and 10 do not support line dash
			if (ctx.setLineDash) {
				ctx.setLineDash(vm.borderDash || globalOptionLineElements.borderDash);
			}

			ctx.lineDashOffset = vm.borderDashOffset || globalOptionLineElements.borderDashOffset;
			ctx.lineJoin = vm.borderJoinStyle || globalOptionLineElements.borderJoinStyle;
			ctx.lineWidth = vm.borderWidth || globalOptionLineElements.borderWidth;
			ctx.strokeStyle = vm.borderColor || globalDefaults.defaultColor;

			// Stroke Line
			ctx.beginPath();
			lastDrawnIndex = -1;

			for (index = 0; index < points.length; ++index) {
				current = points[index];
				previous = helpers.previousItem(points, index);
				currentVM = current._view;

				// First point moves to it's starting position no matter what
				if (index === 0) {
					if (!currentVM.skip) {
						ctx.moveTo(currentVM.x, currentVM.y);
						lastDrawnIndex = index;
					}
				} else {
					previous = lastDrawnIndex === -1 ? previous : points[lastDrawnIndex];

					if (!currentVM.skip) {
						if ((lastDrawnIndex !== (index - 1) && !spanGaps) || lastDrawnIndex === -1) {
							// There was a gap and this is the first point after the gap
							ctx.moveTo(currentVM.x, currentVM.y);
						} else {
							// Line to next point
							helpers.canvas.lineTo(ctx, previous._view, current._view);
						}
						lastDrawnIndex = index;
					}
				}
			}

			ctx.stroke();
			ctx.restore();
		}
	});
};

},{}],37:[function(require,module,exports){
'use strict';

module.exports = function(Chart) {

	var helpers = Chart.helpers,
		globalOpts = Chart.defaults.global,
		defaultColor = globalOpts.defaultColor;

	globalOpts.elements.point = {
		radius: 3,
		pointStyle: 'circle',
		backgroundColor: defaultColor,
		borderWidth: 1,
		borderColor: defaultColor,
		// Hover
		hitRadius: 1,
		hoverRadius: 4,
		hoverBorderWidth: 1
	};

	function xRange(mouseX) {
		var vm = this._view;
		return vm ? (Math.pow(mouseX - vm.x, 2) < Math.pow(vm.radius + vm.hitRadius, 2)) : false;
	}

	function yRange(mouseY) {
		var vm = this._view;
		return vm ? (Math.pow(mouseY - vm.y, 2) < Math.pow(vm.radius + vm.hitRadius, 2)) : false;
	}

	Chart.elements.Point = Chart.Element.extend({
		inRange: function(mouseX, mouseY) {
			var vm = this._view;
			return vm ? ((Math.pow(mouseX - vm.x, 2) + Math.pow(mouseY - vm.y, 2)) < Math.pow(vm.hitRadius + vm.radius, 2)) : false;
		},

		inLabelRange: xRange,
		inXRange: xRange,
		inYRange: yRange,

		getCenterPoint: function() {
			var vm = this._view;
			return {
				x: vm.x,
				y: vm.y
			};
		},
		getArea: function() {
			return Math.PI * Math.pow(this._view.radius, 2);
		},
		tooltipPosition: function() {
			var vm = this._view;
			return {
				x: vm.x,
				y: vm.y,
				padding: vm.radius + vm.borderWidth
			};
		},
		draw: function(chartArea) {
			var vm = this._view;
			var model = this._model;
			var ctx = this._chart.ctx;
			var pointStyle = vm.pointStyle;
			var radius = vm.radius;
			var x = vm.x;
			var y = vm.y;
			var color = Chart.helpers.color;
			var errMargin = 1.01; // 1.01 is margin for Accumulated error. (Especially Edge, IE.)
			var ratio = 0;

			if (vm.skip) {
				return;
			}

			ctx.strokeStyle = vm.borderColor || defaultColor;
			ctx.lineWidth = helpers.getValueOrDefault(vm.borderWidth, globalOpts.elements.point.borderWidth);
			ctx.fillStyle = vm.backgroundColor || defaultColor;

			// Cliping for Points.
			// going out from inner charArea?
			if ((chartArea !== undefined) && ((model.x < chartArea.left) || (chartArea.right*errMargin < model.x) || (model.y < chartArea.top) || (chartArea.bottom*errMargin < model.y))) {
				// Point fade out
				if (model.x < chartArea.left) {
					ratio = (x - model.x) / (chartArea.left - model.x);
				} else if (chartArea.right*errMargin < model.x) {
					ratio = (model.x - x) / (model.x - chartArea.right);
				} else if (model.y < chartArea.top) {
					ratio = (y - model.y) / (chartArea.top - model.y);
				} else if (chartArea.bottom*errMargin < model.y) {
					ratio = (model.y - y) / (model.y - chartArea.bottom);
				}
				ratio = Math.round(ratio*100) / 100;
				ctx.strokeStyle = color(ctx.strokeStyle).alpha(ratio).rgbString();
				ctx.fillStyle = color(ctx.fillStyle).alpha(ratio).rgbString();
			}

			Chart.canvasHelpers.drawPoint(ctx, pointStyle, radius, x, y);
		}
	});
};

},{}],38:[function(require,module,exports){
'use strict';

module.exports = function(Chart) {

	var globalOpts = Chart.defaults.global;

	globalOpts.elements.rectangle = {
		backgroundColor: globalOpts.defaultColor,
		borderWidth: 0,
		borderColor: globalOpts.defaultColor,
		borderSkipped: 'bottom'
	};

	function isVertical(bar) {
		return bar._view.width !== undefined;
	}

	/**
	 * Helper function to get the bounds of the bar regardless of the orientation
	 * @private
	 * @param bar {Chart.Element.Rectangle} the bar
	 * @return {Bounds} bounds of the bar
	 */
	function getBarBounds(bar) {
		var vm = bar._view;
		var x1, x2, y1, y2;

		if (isVertical(bar)) {
			// vertical
			var halfWidth = vm.width / 2;
			x1 = vm.x - halfWidth;
			x2 = vm.x + halfWidth;
			y1 = Math.min(vm.y, vm.base);
			y2 = Math.max(vm.y, vm.base);
		} else {
			// horizontal bar
			var halfHeight = vm.height / 2;
			x1 = Math.min(vm.x, vm.base);
			x2 = Math.max(vm.x, vm.base);
			y1 = vm.y - halfHeight;
			y2 = vm.y + halfHeight;
		}

		return {
			left: x1,
			top: y1,
			right: x2,
			bottom: y2
		};
	}

	Chart.elements.Rectangle = Chart.Element.extend({
		draw: function() {
			var ctx = this._chart.ctx;
			var vm = this._view;
			var left, right, top, bottom, signX, signY, borderSkipped;
			var borderWidth = vm.borderWidth;

			if (!vm.horizontal) {
				// bar
				left = vm.x - vm.width / 2;
				right = vm.x + vm.width / 2;
				top = vm.y;
				bottom = vm.base;
				signX = 1;
				signY = bottom > top? 1: -1;
				borderSkipped = vm.borderSkipped || 'bottom';
			} else {
				// horizontal bar
				left = vm.base;
				right = vm.x;
				top = vm.y - vm.height / 2;
				bottom = vm.y + vm.height / 2;
				signX = right > left? 1: -1;
				signY = 1;
				borderSkipped = vm.borderSkipped || 'left';
			}

			// Canvas doesn't allow us to stroke inside the width so we can
			// adjust the sizes to fit if we're setting a stroke on the line
			if (borderWidth) {
				// borderWidth shold be less than bar width and bar height.
				var barSize = Math.min(Math.abs(left - right), Math.abs(top - bottom));
				borderWidth = borderWidth > barSize? barSize: borderWidth;
				var halfStroke = borderWidth / 2;
				// Adjust borderWidth when bar top position is near vm.base(zero).
				var borderLeft = left + (borderSkipped !== 'left'? halfStroke * signX: 0);
				var borderRight = right + (borderSkipped !== 'right'? -halfStroke * signX: 0);
				var borderTop = top + (borderSkipped !== 'top'? halfStroke * signY: 0);
				var borderBottom = bottom + (borderSkipped !== 'bottom'? -halfStroke * signY: 0);
				// not become a vertical line?
				if (borderLeft !== borderRight) {
					top = borderTop;
					bottom = borderBottom;
				}
				// not become a horizontal line?
				if (borderTop !== borderBottom) {
					left = borderLeft;
					right = borderRight;
				}
			}

			ctx.beginPath();
			ctx.fillStyle = vm.backgroundColor;
			ctx.strokeStyle = vm.borderColor;
			ctx.lineWidth = borderWidth;

			// Corner points, from bottom-left to bottom-right clockwise
			// | 1 2 |
			// | 0 3 |
			var corners = [
				[left, bottom],
				[left, top],
				[right, top],
				[right, bottom]
			];

			// Find first (starting) corner with fallback to 'bottom'
			var borders = ['bottom', 'left', 'top', 'right'];
			var startCorner = borders.indexOf(borderSkipped, 0);
			if (startCorner === -1) {
				startCorner = 0;
			}

			function cornerAt(index) {
				return corners[(startCorner + index) % 4];
			}

			// Draw rectangle from 'startCorner'
			var corner = cornerAt(0);
			ctx.moveTo(corner[0], corner[1]);

			for (var i = 1; i < 4; i++) {
				corner = cornerAt(i);
				ctx.lineTo(corner[0], corner[1]);
			}

			ctx.fill();
			if (borderWidth) {
				ctx.stroke();
			}
		},
		height: function() {
			var vm = this._view;
			return vm.base - vm.y;
		},
		inRange: function(mouseX, mouseY) {
			var inRange = false;

			if (this._view) {
				var bounds = getBarBounds(this);
				inRange = mouseX >= bounds.left && mouseX <= bounds.right && mouseY >= bounds.top && mouseY <= bounds.bottom;
			}

			return inRange;
		},
		inLabelRange: function(mouseX, mouseY) {
			var me = this;
			if (!me._view) {
				return false;
			}

			var inRange = false;
			var bounds = getBarBounds(me);

			if (isVertical(me)) {
				inRange = mouseX >= bounds.left && mouseX <= bounds.right;
			} else {
				inRange = mouseY >= bounds.top && mouseY <= bounds.bottom;
			}

			return inRange;
		},
		inXRange: function(mouseX) {
			var bounds = getBarBounds(this);
			return mouseX >= bounds.left && mouseX <= bounds.right;
		},
		inYRange: function(mouseY) {
			var bounds = getBarBounds(this);
			return mouseY >= bounds.top && mouseY <= bounds.bottom;
		},
		getCenterPoint: function() {
			var vm = this._view;
			var x, y;
			if (isVertical(this)) {
				x = vm.x;
				y = (vm.y + vm.base) / 2;
			} else {
				x = (vm.x + vm.base) / 2;
				y = vm.y;
			}

			return {x: x, y: y};
		},
		getArea: function() {
			var vm = this._view;
			return vm.width * Math.abs(vm.y - vm.base);
		},
		tooltipPosition: function() {
			var vm = this._view;
			return {
				x: vm.x,
				y: vm.y
			};
		}
	});

};

},{}],39:[function(require,module,exports){
'use strict';

// Chart.Platform implementation for targeting a web browser
module.exports = function(Chart) {
	var helpers = Chart.helpers;

	// DOM event types -> Chart.js event types.
	// Note: only events with different types are mapped.
	// https://developer.mozilla.org/en-US/docs/Web/Events
	var eventTypeMap = {
		// Touch events
		touchstart: 'mousedown',
		touchmove: 'mousemove',
		touchend: 'mouseup',

		// Pointer events
		pointerenter: 'mouseenter',
		pointerdown: 'mousedown',
		pointermove: 'mousemove',
		pointerup: 'mouseup',
		pointerleave: 'mouseout',
		pointerout: 'mouseout'
	};

	/**
	 * The "used" size is the final value of a dimension property after all calculations have
	 * been performed. This method uses the computed style of `element` but returns undefined
	 * if the computed style is not expressed in pixels. That can happen in some cases where
	 * `element` has a size relative to its parent and this last one is not yet displayed,
	 * for example because of `display: none` on a parent node.
	 * @see https://developer.mozilla.org/en-US/docs/Web/CSS/used_value
	 * @returns {Number} Size in pixels or undefined if unknown.
	 */
	function readUsedSize(element, property) {
		var value = helpers.getStyle(element, property);
		var matches = value && value.match(/^(\d+)(\.\d+)?px$/);
		return matches? Number(matches[1]) : undefined;
	}

	/**
	 * Initializes the canvas style and render size without modifying the canvas display size,
	 * since responsiveness is handled by the controller.resize() method. The config is used
	 * to determine the aspect ratio to apply in case no explicit height has been specified.
	 */
	function initCanvas(canvas, config) {
		var style = canvas.style;

		// NOTE(SB) canvas.getAttribute('width') !== canvas.width: in the first case it
		// returns null or '' if no explicit value has been set to the canvas attribute.
		var renderHeight = canvas.getAttribute('height');
		var renderWidth = canvas.getAttribute('width');

		// Chart.js modifies some canvas values that we want to restore on destroy
		canvas._chartjs = {
			initial: {
				height: renderHeight,
				width: renderWidth,
				style: {
					display: style.display,
					height: style.height,
					width: style.width
				}
			}
		};

		// Force canvas to display as block to avoid extra space caused by inline
		// elements, which would interfere with the responsive resize process.
		// https://github.com/chartjs/Chart.js/issues/2538
		style.display = style.display || 'block';

		if (renderWidth === null || renderWidth === '') {
			var displayWidth = readUsedSize(canvas, 'width');
			if (displayWidth !== undefined) {
				canvas.width = displayWidth;
			}
		}

		if (renderHeight === null || renderHeight === '') {
			if (canvas.style.height === '') {
				// If no explicit render height and style height, let's apply the aspect ratio,
				// which one can be specified by the user but also by charts as default option
				// (i.e. options.aspectRatio). If not specified, use canvas aspect ratio of 2.
				canvas.height = canvas.width / (config.options.aspectRatio || 2);
			} else {
				var displayHeight = readUsedSize(canvas, 'height');
				if (displayWidth !== undefined) {
					canvas.height = displayHeight;
				}
			}
		}

		return canvas;
	}

	function createEvent(type, chart, x, y, nativeEvent) {
		return {
			type: type,
			chart: chart,
			native: nativeEvent || null,
			x: x !== undefined? x : null,
			y: y !== undefined? y : null,
		};
	}

	function fromNativeEvent(event, chart) {
		var type = eventTypeMap[event.type] || event.type;
		var pos = helpers.getRelativePosition(event, chart);
		return createEvent(type, chart, pos.x, pos.y, event);
	}

	function createResizer(handler) {
		var iframe = document.createElement('iframe');
		iframe.className = 'chartjs-hidden-iframe';
		iframe.style.cssText =
			'display:block;'+
			'overflow:hidden;'+
			'border:0;'+
			'margin:0;'+
			'top:0;'+
			'left:0;'+
			'bottom:0;'+
			'right:0;'+
			'height:100%;'+
			'width:100%;'+
			'position:absolute;'+
			'pointer-events:none;'+
			'z-index:-1;';

		// Prevent the iframe to gain focus on tab.
		// https://github.com/chartjs/Chart.js/issues/3090
		iframe.tabIndex = -1;

		// If the iframe is re-attached to the DOM, the resize listener is removed because the
		// content is reloaded, so make sure to install the handler after the iframe is loaded.
		// https://github.com/chartjs/Chart.js/issues/3521
		helpers.addEvent(iframe, 'load', function() {
			helpers.addEvent(iframe.contentWindow || iframe, 'resize', handler);

			// The iframe size might have changed while loading, which can also
			// happen if the size has been changed while detached from the DOM.
			handler();
		});

		return iframe;
	}

	function addResizeListener(node, listener, chart) {
		var stub = node._chartjs = {
			ticking: false
		};

		// Throttle the callback notification until the next animation frame.
		var notify = function() {
			if (!stub.ticking) {
				stub.ticking = true;
				helpers.requestAnimFrame.call(window, function() {
					if (stub.resizer) {
						stub.ticking = false;
						return listener(createEvent('resize', chart));
					}
				});
			}
		};

		// Let's keep track of this added iframe and thus avoid DOM query when removing it.
		stub.resizer = createResizer(notify);

		node.insertBefore(stub.resizer, node.firstChild);
	}

	function removeResizeListener(node) {
		if (!node || !node._chartjs) {
			return;
		}

		var resizer = node._chartjs.resizer;
		if (resizer) {
			resizer.parentNode.removeChild(resizer);
			node._chartjs.resizer = null;
		}

		delete node._chartjs;
	}

	return {
		acquireContext: function(item, config) {
			if (typeof item === 'string') {
				item = document.getElementById(item);
			} else if (item.length) {
				// Support for array based queries (such as jQuery)
				item = item[0];
			}

			if (item && item.canvas) {
				// Support for any object associated to a canvas (including a context2d)
				item = item.canvas;
			}

			// To prevent canvas fingerprinting, some add-ons undefine the getContext
			// method, for example: https://github.com/kkapsner/CanvasBlocker
			// https://github.com/chartjs/Chart.js/issues/2807
			var context = item && item.getContext && item.getContext('2d');

			// `instanceof HTMLCanvasElement/CanvasRenderingContext2D` fails when the item is
			// inside an iframe or when running in a protected environment. We could guess the
			// types from their toString() value but let's keep things flexible and assume it's
			// a sufficient condition if the item has a context2D which has item as `canvas`.
			// https://github.com/chartjs/Chart.js/issues/3887
			// https://github.com/chartjs/Chart.js/issues/4102
			// https://github.com/chartjs/Chart.js/issues/4152
			if (context && context.canvas === item) {
				initCanvas(item, config);
				return context;
			}

			return null;
		},

		releaseContext: function(context) {
			var canvas = context.canvas;
			if (!canvas._chartjs) {
				return;
			}

			var initial = canvas._chartjs.initial;
			['height', 'width'].forEach(function(prop) {
				var value = initial[prop];
				if (value === undefined || value === null) {
					canvas.removeAttribute(prop);
				} else {
					canvas.setAttribute(prop, value);
				}
			});

			helpers.each(initial.style || {}, function(value, key) {
				canvas.style[key] = value;
			});

			// The canvas render size might have been changed (and thus the state stack discarded),
			// we can't use save() and restore() to restore the initial state. So make sure that at
			// least the canvas context is reset to the default state by setting the canvas width.
			// https://www.w3.org/TR/2011/WD-html5-20110525/the-canvas-element.html
			canvas.width = canvas.width;

			delete canvas._chartjs;
		},

		addEventListener: function(chart, type, listener) {
			var canvas = chart.canvas;
			if (type === 'resize') {
				// Note: the resize event is not supported on all browsers.
				addResizeListener(canvas.parentNode, listener, chart);
				return;
			}

			var stub = listener._chartjs || (listener._chartjs = {});
			var proxies = stub.proxies || (stub.proxies = {});
			var proxy = proxies[chart.id + '_' + type] = function(event) {
				listener(fromNativeEvent(event, chart));
			};

			helpers.addEvent(canvas, type, proxy);
		},

		removeEventListener: function(chart, type, listener) {
			var canvas = chart.canvas;
			if (type === 'resize') {
				// Note: the resize event is not supported on all browsers.
				removeResizeListener(canvas.parentNode, listener);
				return;
			}

			var stub = listener._chartjs || {};
			var proxies = stub.proxies || {};
			var proxy = proxies[chart.id + '_' + type];
			if (!proxy) {
				return;
			}

			helpers.removeEvent(canvas, type, proxy);
		}
	};
};

},{}],40:[function(require,module,exports){
'use strict';

// By default, select the browser (DOM) platform.
// @TODO Make possible to select another platform at build time.
var implementation = require(39);

module.exports = function(Chart) {
	/**
	 * @namespace Chart.platform
	 * @see https://chartjs.gitbooks.io/proposals/content/Platform.html
	 * @since 2.4.0
	 */
	Chart.platform = {
		/**
		 * Called at chart construction time, returns a context2d instance implementing
		 * the [W3C Canvas 2D Context API standard]{@link https://www.w3.org/TR/2dcontext/}.
		 * @param {*} item - The native item from which to acquire context (platform specific)
		 * @param {Object} options - The chart options
		 * @returns {CanvasRenderingContext2D} context2d instance
		 */
		acquireContext: function() {},

		/**
		 * Called at chart destruction time, releases any resources associated to the context
		 * previously returned by the acquireContext() method.
		 * @param {CanvasRenderingContext2D} context - The context2d instance
		 * @returns {Boolean} true if the method succeeded, else false
		 */
		releaseContext: function() {},

		/**
		 * Registers the specified listener on the given chart.
		 * @param {Chart} chart - Chart from which to listen for event
		 * @param {String} type - The ({@link IEvent}) type to listen for
		 * @param {Function} listener - Receives a notification (an object that implements
		 * the {@link IEvent} interface) when an event of the specified type occurs.
		 */
		addEventListener: function() {},

		/**
		 * Removes the specified listener previously registered with addEventListener.
		 * @param {Chart} chart -Chart from which to remove the listener
		 * @param {String} type - The ({@link IEvent}) type to remove
		 * @param {Function} listener - The listener function to remove from the event target.
		 */
		removeEventListener: function() {}
	};

	/**
	 * @interface IPlatform
	 * Allows abstracting platform dependencies away from the chart
	 * @borrows Chart.platform.acquireContext as acquireContext
	 * @borrows Chart.platform.releaseContext as releaseContext
	 * @borrows Chart.platform.addEventListener as addEventListener
	 * @borrows Chart.platform.removeEventListener as removeEventListener
	 */

	/**
	 * @interface IEvent
	 * @prop {String} type - The event type name, possible values are:
	 * 'contextmenu', 'mouseenter', 'mousedown', 'mousemove', 'mouseup', 'mouseout',
	 * 'click', 'dblclick', 'keydown', 'keypress', 'keyup' and 'resize'
	 * @prop {*} native - The original native event (null for emulated events, e.g. 'resize')
	 * @prop {Number} x - The mouse x position, relative to the canvas (null for incompatible events)
	 * @prop {Number} y - The mouse y position, relative to the canvas (null for incompatible events)
	 */

	Chart.helpers.extend(Chart.platform, implementation(Chart));
};

},{"39":39}],41:[function(require,module,exports){
'use strict';

module.exports = function(Chart) {
	/**
	 * Plugin based on discussion from the following Chart.js issues:
	 * @see https://github.com/chartjs/Chart.js/issues/2380#issuecomment-279961569
	 * @see https://github.com/chartjs/Chart.js/issues/2440#issuecomment-256461897
	 */
	Chart.defaults.global.plugins.filler = {
		propagate: true
	};

	var defaults = Chart.defaults;
	var helpers = Chart.helpers;
	var mappers = {
		dataset: function(source) {
			var index = source.fill;
			var chart = source.chart;
			var meta = chart.getDatasetMeta(index);
			var visible = meta && chart.isDatasetVisible(index);
			var points = (visible && meta.dataset._children) || [];

			return !points.length? null : function(point, i) {
				return points[i]._view || null;
			};
		},

		boundary: function(source) {
			var boundary = source.boundary;
			var x = boundary? boundary.x : null;
			var y = boundary? boundary.y : null;

			return function(point) {
				return {
					x: x === null? point.x : x,
					y: y === null? point.y : y,
				};
			};
		}
	};

	// @todo if (fill[0] === '#')
	function decodeFill(el, index, count) {
		var model = el._model || {};
		var fill = model.fill;
		var target;

		if (fill === undefined) {
			fill = !!model.backgroundColor;
		}

		if (fill === false || fill === null) {
			return false;
		}

		if (fill === true) {
			return 'origin';
		}

		target = parseFloat(fill, 10);
		if (isFinite(target) && Math.floor(target) === target) {
			if (fill[0] === '-' || fill[0] === '+') {
				target = index + target;
			}

			if (target === index || target < 0 || target >= count) {
				return false;
			}

			return target;
		}

		switch (fill) {
		// compatibility
		case 'bottom':
			return 'start';
		case 'top':
			return 'end';
		case 'zero':
			return 'origin';
		// supported boundaries
		case 'origin':
		case 'start':
		case 'end':
			return fill;
		// invalid fill values
		default:
			return false;
		}
	}

	function computeBoundary(source) {
		var model = source.el._model || {};
		var scale = source.el._scale || {};
		var fill = source.fill;
		var target = null;
		var horizontal;

		if (isFinite(fill)) {
			return null;
		}

		// Backward compatibility: until v3, we still need to support boundary values set on
		// the model (scaleTop, scaleBottom and scaleZero) because some external plugins and
		// controllers might still use it (e.g. the Smith chart).

		if (fill === 'start') {
			target = model.scaleBottom === undefined? scale.bottom : model.scaleBottom;
		} else if (fill === 'end') {
			target = model.scaleTop === undefined? scale.top : model.scaleTop;
		} else if (model.scaleZero !== undefined) {
			target = model.scaleZero;
		} else if (scale.getBasePosition) {
			target = scale.getBasePosition();
		} else if (scale.getBasePixel) {
			target = scale.getBasePixel();
		}

		if (target !== undefined && target !== null) {
			if (target.x !== undefined && target.y !== undefined) {
				return target;
			}

			if (typeof target === 'number' && isFinite(target)) {
				horizontal = scale.isHorizontal();
				return {
					x: horizontal? target : null,
					y: horizontal? null : target
				};
			}
		}

		return null;
	}

	function resolveTarget(sources, index, propagate) {
		var source = sources[index];
		var fill = source.fill;
		var visited = [index];
		var target;

		if (!propagate) {
			return fill;
		}

		while (fill !== false && visited.indexOf(fill) === -1) {
			if (!isFinite(fill)) {
				return fill;
			}

			target = sources[fill];
			if (!target) {
				return false;
			}

			if (target.visible) {
				return fill;
			}

			visited.push(fill);
			fill = target.fill;
		}

		return false;
	}

	function createMapper(source) {
		var fill = source.fill;
		var type = 'dataset';

		if (fill === false) {
			return null;
		}

		if (!isFinite(fill)) {
			type = 'boundary';
		}

		return mappers[type](source);
	}

	function isDrawable(point) {
		return point && !point.skip;
	}

	function drawArea(ctx, curve0, curve1, len0, len1) {
		var i;

		if (!len0 || !len1) {
			return;
		}

		// building first area curve (normal)
		ctx.moveTo(curve0[0].x, curve0[0].y);
		for (i=1; i<len0; ++i) {
			helpers.canvas.lineTo(ctx, curve0[i-1], curve0[i]);
		}

		// joining the two area curves
		ctx.lineTo(curve1[len1-1].x, curve1[len1-1].y);

		// building opposite area curve (reverse)
		for (i=len1-1; i>0; --i) {
			helpers.canvas.lineTo(ctx, curve1[i], curve1[i-1], true);
		}
	}

	function doFill(ctx, points, mapper, view, color, loop) {
		var count = points.length;
		var span = view.spanGaps;
		var curve0 = [];
		var curve1 = [];
		var len0 = 0;
		var len1 = 0;
		var i, ilen, index, p0, p1, d0, d1;

		ctx.beginPath();

		for (i = 0, ilen = (count + !!loop); i < ilen; ++i) {
			index = i%count;
			p0 = points[index]._view;
			p1 = mapper(p0, index, view);
			d0 = isDrawable(p0);
			d1 = isDrawable(p1);

			if (d0 && d1) {
				len0 = curve0.push(p0);
				len1 = curve1.push(p1);
			} else if (len0 && len1) {
				if (!span) {
					drawArea(ctx, curve0, curve1, len0, len1);
					len0 = len1 = 0;
					curve0 = [];
					curve1 = [];
				} else {
					if (d0) {
						curve0.push(p0);
					}
					if (d1) {
						curve1.push(p1);
					}
				}
			}
		}

		drawArea(ctx, curve0, curve1, len0, len1);

		ctx.closePath();
		ctx.fillStyle = color;
		ctx.fill();
	}

	return {
		id: 'filler',

		afterDatasetsUpdate: function(chart, options) {
			var count = (chart.data.datasets || []).length;
			var propagate = options.propagate;
			var sources = [];
			var meta, i, el, source;

			for (i = 0; i < count; ++i) {
				meta = chart.getDatasetMeta(i);
				el = meta.dataset;
				source = null;

				if (el && el._model && el instanceof Chart.elements.Line) {
					source = {
						visible: chart.isDatasetVisible(i),
						fill: decodeFill(el, i, count),
						chart: chart,
						el: el
					};
				}

				meta.$filler = source;
				sources.push(source);
			}

			for (i=0; i<count; ++i) {
				source = sources[i];
				if (!source) {
					continue;
				}

				source.fill = resolveTarget(sources, i, propagate);
				source.boundary = computeBoundary(source);
				source.mapper = createMapper(source);
			}
		},

		beforeDatasetDraw: function(chart, args) {
			var meta = args.meta.$filler;
			if (!meta) {
				return;
			}

			var el = meta.el;
			var view = el._view;
			var points = el._children || [];
			var mapper = meta.mapper;
			var color = view.backgroundColor || defaults.global.defaultColor;

			if (mapper && color && points.length) {
				doFill(chart.ctx, points, mapper, view, color, el._loop);
			}
		}
	};
};

},{}],42:[function(require,module,exports){
'use strict';

module.exports = function(Chart) {

	var helpers = Chart.helpers;
	var layout = Chart.layoutService;
	var noop = helpers.noop;

	Chart.defaults.global.legend = {
		display: true,
		position: 'top',
		fullWidth: true,
		reverse: false,
		weight: 1000,

		// a callback that will handle
		onClick: function(e, legendItem) {
			var index = legendItem.datasetIndex;
			var ci = this.chart;
			var meta = ci.getDatasetMeta(index);

			// See controller.isDatasetVisible comment
			meta.hidden = meta.hidden === null? !ci.data.datasets[index].hidden : null;

			// We hid a dataset ... rerender the chart
			ci.update();
		},

		onHover: null,

		labels: {
			boxWidth: 40,
			padding: 10,
			// Generates labels shown in the legend
			// Valid properties to return:
			// text : text to display
			// fillStyle : fill of coloured box
			// strokeStyle: stroke of coloured box
			// hidden : if this legend item refers to a hidden item
			// lineCap : cap style for line
			// lineDash
			// lineDashOffset :
			// lineJoin :
			// lineWidth :
			generateLabels: function(chart) {
				var data = chart.data;
				return helpers.isArray(data.datasets) ? data.datasets.map(function(dataset, i) {
					return {
						text: dataset.label,
						fillStyle: (!helpers.isArray(dataset.backgroundColor) ? dataset.backgroundColor : dataset.backgroundColor[0]),
						hidden: !chart.isDatasetVisible(i),
						lineCap: dataset.borderCapStyle,
						lineDash: dataset.borderDash,
						lineDashOffset: dataset.borderDashOffset,
						lineJoin: dataset.borderJoinStyle,
						lineWidth: dataset.borderWidth,
						strokeStyle: dataset.borderColor,
						pointStyle: dataset.pointStyle,

						// Below is extra data used for toggling the datasets
						datasetIndex: i
					};
				}, this) : [];
			}
		}
	};

	/**
	 * Helper function to get the box width based on the usePointStyle option
	 * @param labelopts {Object} the label options on the legend
	 * @param fontSize {Number} the label font size
	 * @return {Number} width of the color box area
	 */
	function getBoxWidth(labelOpts, fontSize) {
		return labelOpts.usePointStyle ?
			fontSize * Math.SQRT2 :
			labelOpts.boxWidth;
	}

	Chart.Legend = Chart.Element.extend({

		initialize: function(config) {
			helpers.extend(this, config);

			// Contains hit boxes for each dataset (in dataset order)
			this.legendHitBoxes = [];

			// Are we in doughnut mode which has a different data type
			this.doughnutMode = false;
		},

		// These methods are ordered by lifecycle. Utilities then follow.
		// Any function defined here is inherited by all legend types.
		// Any function can be extended by the legend type

		beforeUpdate: noop,
		update: function(maxWidth, maxHeight, margins) {
			var me = this;

			// Update Lifecycle - Probably don't want to ever extend or overwrite this function ;)
			me.beforeUpdate();

			// Absorb the master measurements
			me.maxWidth = maxWidth;
			me.maxHeight = maxHeight;
			me.margins = margins;

			// Dimensions
			me.beforeSetDimensions();
			me.setDimensions();
			me.afterSetDimensions();
			// Labels
			me.beforeBuildLabels();
			me.buildLabels();
			me.afterBuildLabels();

			// Fit
			me.beforeFit();
			me.fit();
			me.afterFit();
			//
			me.afterUpdate();

			return me.minSize;
		},
		afterUpdate: noop,

		//

		beforeSetDimensions: noop,
		setDimensions: function() {
			var me = this;
			// Set the unconstrained dimension before label rotation
			if (me.isHorizontal()) {
				// Reset position before calculating rotation
				me.width = me.maxWidth;
				me.left = 0;
				me.right = me.width;
			} else {
				me.height = me.maxHeight;

				// Reset position before calculating rotation
				me.top = 0;
				me.bottom = me.height;
			}

			// Reset padding
			me.paddingLeft = 0;
			me.paddingTop = 0;
			me.paddingRight = 0;
			me.paddingBottom = 0;

			// Reset minSize
			me.minSize = {
				width: 0,
				height: 0
			};
		},
		afterSetDimensions: noop,

		//

		beforeBuildLabels: noop,
		buildLabels: function() {
			var me = this;
			var labelOpts = me.options.labels;
			var legendItems = labelOpts.generateLabels.call(me, me.chart);

			if (labelOpts.filter) {
				legendItems = legendItems.filter(function(item) {
					return labelOpts.filter(item, me.chart.data);
				});
			}

			if (me.options.reverse) {
				legendItems.reverse();
			}

			me.legendItems = legendItems;
		},
		afterBuildLabels: noop,

		//

		beforeFit: noop,
		fit: function() {
			var me = this;
			var opts = me.options;
			var labelOpts = opts.labels;
			var display = opts.display;

			var ctx = me.ctx;

			var globalDefault = Chart.defaults.global,
				itemOrDefault = helpers.getValueOrDefault,
				fontSize = itemOrDefault(labelOpts.fontSize, globalDefault.defaultFontSize),
				fontStyle = itemOrDefault(labelOpts.fontStyle, globalDefault.defaultFontStyle),
				fontFamily = itemOrDefault(labelOpts.fontFamily, globalDefault.defaultFontFamily),
				labelFont = helpers.fontString(fontSize, fontStyle, fontFamily);

			// Reset hit boxes
			var hitboxes = me.legendHitBoxes = [];

			var minSize = me.minSize;
			var isHorizontal = me.isHorizontal();

			if (isHorizontal) {
				minSize.width = me.maxWidth; // fill all the width
				minSize.height = display ? 10 : 0;
			} else {
				minSize.width = display ? 10 : 0;
				minSize.height = me.maxHeight; // fill all the height
			}

			// Increase sizes here
			if (display) {
				ctx.font = labelFont;

				if (isHorizontal) {
					// Labels

					// Width of each line of legend boxes. Labels wrap onto multiple lines when there are too many to fit on one
					var lineWidths = me.lineWidths = [0];
					var totalHeight = me.legendItems.length ? fontSize + (labelOpts.padding) : 0;

					ctx.textAlign = 'left';
					ctx.textBaseline = 'top';

					helpers.each(me.legendItems, function(legendItem, i) {
						var boxWidth = getBoxWidth(labelOpts, fontSize);
						var width = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width;

						if (lineWidths[lineWidths.length - 1] + width + labelOpts.padding >= me.width) {
							totalHeight += fontSize + (labelOpts.padding);
							lineWidths[lineWidths.length] = me.left;
						}

						// Store the hitbox width and height here. Final position will be updated in `draw`
						hitboxes[i] = {
							left: 0,
							top: 0,
							width: width,
							height: fontSize
						};

						lineWidths[lineWidths.length - 1] += width + labelOpts.padding;
					});

					minSize.height += totalHeight;

				} else {
					var vPadding = labelOpts.padding;
					var columnWidths = me.columnWidths = [];
					var totalWidth = labelOpts.padding;
					var currentColWidth = 0;
					var currentColHeight = 0;
					var itemHeight = fontSize + vPadding;

					helpers.each(me.legendItems, function(legendItem, i) {
						var boxWidth = getBoxWidth(labelOpts, fontSize);
						var itemWidth = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width;

						// If too tall, go to new column
						if (currentColHeight + itemHeight > minSize.height) {
							totalWidth += currentColWidth + labelOpts.padding;
							columnWidths.push(currentColWidth); // previous column width

							currentColWidth = 0;
							currentColHeight = 0;
						}

						// Get max width
						currentColWidth = Math.max(currentColWidth, itemWidth);
						currentColHeight += itemHeight;

						// Store the hitbox width and height here. Final position will be updated in `draw`
						hitboxes[i] = {
							left: 0,
							top: 0,
							width: itemWidth,
							height: fontSize
						};
					});

					totalWidth += currentColWidth;
					columnWidths.push(currentColWidth);
					minSize.width += totalWidth;
				}
			}

			me.width = minSize.width;
			me.height = minSize.height;
		},
		afterFit: noop,

		// Shared Methods
		isHorizontal: function() {
			return this.options.position === 'top' || this.options.position === 'bottom';
		},

		// Actually draw the legend on the canvas
		draw: function() {
			var me = this;
			var opts = me.options;
			var labelOpts = opts.labels;
			var globalDefault = Chart.defaults.global,
				lineDefault = globalDefault.elements.line,
				legendWidth = me.width,
				lineWidths = me.lineWidths;

			if (opts.display) {
				var ctx = me.ctx,
					cursor,
					itemOrDefault = helpers.getValueOrDefault,
					fontColor = itemOrDefault(labelOpts.fontColor, globalDefault.defaultFontColor),
					fontSize = itemOrDefault(labelOpts.fontSize, globalDefault.defaultFontSize),
					fontStyle = itemOrDefault(labelOpts.fontStyle, globalDefault.defaultFontStyle),
					fontFamily = itemOrDefault(labelOpts.fontFamily, globalDefault.defaultFontFamily),
					labelFont = helpers.fontString(fontSize, fontStyle, fontFamily);

				// Canvas setup
				ctx.textAlign = 'left';
				ctx.textBaseline = 'top';
				ctx.lineWidth = 0.5;
				ctx.strokeStyle = fontColor; // for strikethrough effect
				ctx.fillStyle = fontColor; // render in correct colour
				ctx.font = labelFont;

				var boxWidth = getBoxWidth(labelOpts, fontSize),
					hitboxes = me.legendHitBoxes;

				// current position
				var drawLegendBox = function(x, y, legendItem) {
					if (isNaN(boxWidth) || boxWidth <= 0) {
						return;
					}

					// Set the ctx for the box
					ctx.save();

					ctx.fillStyle = itemOrDefault(legendItem.fillStyle, globalDefault.defaultColor);
					ctx.lineCap = itemOrDefault(legendItem.lineCap, lineDefault.borderCapStyle);
					ctx.lineDashOffset = itemOrDefault(legendItem.lineDashOffset, lineDefault.borderDashOffset);
					ctx.lineJoin = itemOrDefault(legendItem.lineJoin, lineDefault.borderJoinStyle);
					ctx.lineWidth = itemOrDefault(legendItem.lineWidth, lineDefault.borderWidth);
					ctx.strokeStyle = itemOrDefault(legendItem.strokeStyle, globalDefault.defaultColor);
					var isLineWidthZero = (itemOrDefault(legendItem.lineWidth, lineDefault.borderWidth) === 0);

					if (ctx.setLineDash) {
						// IE 9 and 10 do not support line dash
						ctx.setLineDash(itemOrDefault(legendItem.lineDash, lineDefault.borderDash));
					}

					if (opts.labels && opts.labels.usePointStyle) {
						// Recalculate x and y for drawPoint() because its expecting
						// x and y to be center of figure (instead of top left)
						var radius = fontSize * Math.SQRT2 / 2;
						var offSet = radius / Math.SQRT2;
						var centerX = x + offSet;
						var centerY = y + offSet;

						// Draw pointStyle as legend symbol
						Chart.canvasHelpers.drawPoint(ctx, legendItem.pointStyle, radius, centerX, centerY);
					} else {
						// Draw box as legend symbol
						if (!isLineWidthZero) {
							ctx.strokeRect(x, y, boxWidth, fontSize);
						}
						ctx.fillRect(x, y, boxWidth, fontSize);
					}

					ctx.restore();
				};
				var fillText = function(x, y, legendItem, textWidth) {
					ctx.fillText(legendItem.text, boxWidth + (fontSize / 2) + x, y);

					if (legendItem.hidden) {
						// Strikethrough the text if hidden
						ctx.beginPath();
						ctx.lineWidth = 2;
						ctx.moveTo(boxWidth + (fontSize / 2) + x, y + (fontSize / 2));
						ctx.lineTo(boxWidth + (fontSize / 2) + x + textWidth, y + (fontSize / 2));
						ctx.stroke();
					}
				};

				// Horizontal
				var isHorizontal = me.isHorizontal();
				if (isHorizontal) {
					cursor = {
						x: me.left + ((legendWidth - lineWidths[0]) / 2),
						y: me.top + labelOpts.padding,
						line: 0
					};
				} else {
					cursor = {
						x: me.left + labelOpts.padding,
						y: me.top + labelOpts.padding,
						line: 0
					};
				}

				var itemHeight = fontSize + labelOpts.padding;
				helpers.each(me.legendItems, function(legendItem, i) {
					var textWidth = ctx.measureText(legendItem.text).width,
						width = boxWidth + (fontSize / 2) + textWidth,
						x = cursor.x,
						y = cursor.y;

					if (isHorizontal) {
						if (x + width >= legendWidth) {
							y = cursor.y += itemHeight;
							cursor.line++;
							x = cursor.x = me.left + ((legendWidth - lineWidths[cursor.line]) / 2);
						}
					} else if (y + itemHeight > me.bottom) {
						x = cursor.x = x + me.columnWidths[cursor.line] + labelOpts.padding;
						y = cursor.y = me.top + labelOpts.padding;
						cursor.line++;
					}

					drawLegendBox(x, y, legendItem);

					hitboxes[i].left = x;
					hitboxes[i].top = y;

					// Fill the actual label
					fillText(x, y, legendItem, textWidth);

					if (isHorizontal) {
						cursor.x += width + (labelOpts.padding);
					} else {
						cursor.y += itemHeight;
					}

				});
			}
		},

		/**
		 * Handle an event
		 * @private
		 * @param {IEvent} event - The event to handle
		 * @return {Boolean} true if a change occured
		 */
		handleEvent: function(e) {
			var me = this;
			var opts = me.options;
			var type = e.type === 'mouseup' ? 'click' : e.type;
			var changed = false;

			if (type === 'mousemove') {
				if (!opts.onHover) {
					return;
				}
			} else if (type === 'click') {
				if (!opts.onClick) {
					return;
				}
			} else {
				return;
			}

			// Chart event already has relative position in it
			var x = e.x,
				y = e.y;

			if (x >= me.left && x <= me.right && y >= me.top && y <= me.bottom) {
				// See if we are touching one of the dataset boxes
				var lh = me.legendHitBoxes;
				for (var i = 0; i < lh.length; ++i) {
					var hitBox = lh[i];

					if (x >= hitBox.left && x <= hitBox.left + hitBox.width && y >= hitBox.top && y <= hitBox.top + hitBox.height) {
						// Touching an element
						if (type === 'click') {
							// use e.native for backwards compatibility
							opts.onClick.call(me, e.native, me.legendItems[i]);
							changed = true;
							break;
						} else if (type === 'mousemove') {
							// use e.native for backwards compatibility
							opts.onHover.call(me, e.native, me.legendItems[i]);
							changed = true;
							break;
						}
					}
				}
			}

			return changed;
		}
	});

	function createNewLegendAndAttach(chart, legendOpts) {
		var legend = new Chart.Legend({
			ctx: chart.ctx,
			options: legendOpts,
			chart: chart
		});

		layout.configure(chart, legend, legendOpts);
		layout.addBox(chart, legend);
		chart.legend = legend;
	}

	return {
		id: 'legend',

		beforeInit: function(chart) {
			var legendOpts = chart.options.legend;

			if (legendOpts) {
				createNewLegendAndAttach(chart, legendOpts);
			}
		},

		beforeUpdate: function(chart) {
			var legendOpts = chart.options.legend;
			var legend = chart.legend;

			if (legendOpts) {
				legendOpts = helpers.configMerge(Chart.defaults.global.legend, legendOpts);

				if (legend) {
					layout.configure(chart, legend, legendOpts);
					legend.options = legendOpts;
				} else {
					createNewLegendAndAttach(chart, legendOpts);
				}
			} else if (legend) {
				layout.removeBox(chart, legend);
				delete chart.legend;
			}
		},

		afterEvent: function(chart, e) {
			var legend = chart.legend;
			if (legend) {
				legend.handleEvent(e);
			}
		}
	};
};

},{}],43:[function(require,module,exports){
'use strict';

module.exports = function(Chart) {

	var helpers = Chart.helpers;
	var layout = Chart.layoutService;
	var noop = helpers.noop;

	Chart.defaults.global.title = {
		display: false,
		position: 'top',
		fullWidth: true,
		weight: 2000,        // by default greater than legend (1000) to be above
		fontStyle: 'bold',
		padding: 10,

		// actual title
		text: ''
	};

	Chart.Title = Chart.Element.extend({
		initialize: function(config) {
			var me = this;
			helpers.extend(me, config);

			// Contains hit boxes for each dataset (in dataset order)
			me.legendHitBoxes = [];
		},

		// These methods are ordered by lifecycle. Utilities then follow.

		beforeUpdate: noop,
		update: function(maxWidth, maxHeight, margins) {
			var me = this;

			// Update Lifecycle - Probably don't want to ever extend or overwrite this function ;)
			me.beforeUpdate();

			// Absorb the master measurements
			me.maxWidth = maxWidth;
			me.maxHeight = maxHeight;
			me.margins = margins;

			// Dimensions
			me.beforeSetDimensions();
			me.setDimensions();
			me.afterSetDimensions();
			// Labels
			me.beforeBuildLabels();
			me.buildLabels();
			me.afterBuildLabels();

			// Fit
			me.beforeFit();
			me.fit();
			me.afterFit();
			//
			me.afterUpdate();

			return me.minSize;

		},
		afterUpdate: noop,

		//

		beforeSetDimensions: noop,
		setDimensions: function() {
			var me = this;
			// Set the unconstrained dimension before label rotation
			if (me.isHorizontal()) {
				// Reset position before calculating rotation
				me.width = me.maxWidth;
				me.left = 0;
				me.right = me.width;
			} else {
				me.height = me.maxHeight;

				// Reset position before calculating rotation
				me.top = 0;
				me.bottom = me.height;
			}

			// Reset padding
			me.paddingLeft = 0;
			me.paddingTop = 0;
			me.paddingRight = 0;
			me.paddingBottom = 0;

			// Reset minSize
			me.minSize = {
				width: 0,
				height: 0
			};
		},
		afterSetDimensions: noop,

		//

		beforeBuildLabels: noop,
		buildLabels: noop,
		afterBuildLabels: noop,

		//

		beforeFit: noop,
		fit: function() {
			var me = this,
				valueOrDefault = helpers.getValueOrDefault,
				opts = me.options,
				globalDefaults = Chart.defaults.global,
				display = opts.display,
				fontSize = valueOrDefault(opts.fontSize, globalDefaults.defaultFontSize),
				minSize = me.minSize;

			if (me.isHorizontal()) {
				minSize.width = me.maxWidth; // fill all the width
				minSize.height = display ? fontSize + (opts.padding * 2) : 0;
			} else {
				minSize.width = display ? fontSize + (opts.padding * 2) : 0;
				minSize.height = me.maxHeight; // fill all the height
			}

			me.width = minSize.width;
			me.height = minSize.height;

		},
		afterFit: noop,

		// Shared Methods
		isHorizontal: function() {
			var pos = this.options.position;
			return pos === 'top' || pos === 'bottom';
		},

		// Actually draw the title block on the canvas
		draw: function() {
			var me = this,
				ctx = me.ctx,
				valueOrDefault = helpers.getValueOrDefault,
				opts = me.options,
				globalDefaults = Chart.defaults.global;

			if (opts.display) {
				var fontSize = valueOrDefault(opts.fontSize, globalDefaults.defaultFontSize),
					fontStyle = valueOrDefault(opts.fontStyle, globalDefaults.defaultFontStyle),
					fontFamily = valueOrDefault(opts.fontFamily, globalDefaults.defaultFontFamily),
					titleFont = helpers.fontString(fontSize, fontStyle, fontFamily),
					rotation = 0,
					titleX,
					titleY,
					top = me.top,
					left = me.left,
					bottom = me.bottom,
					right = me.right,
					maxWidth;

				ctx.fillStyle = valueOrDefault(opts.fontColor, globalDefaults.defaultFontColor); // render in correct colour
				ctx.font = titleFont;

				// Horizontal
				if (me.isHorizontal()) {
					titleX = left + ((right - left) / 2); // midpoint of the width
					titleY = top + ((bottom - top) / 2); // midpoint of the height
					maxWidth = right - left;
				} else {
					titleX = opts.position === 'left' ? left + (fontSize / 2) : right - (fontSize / 2);
					titleY = top + ((bottom - top) / 2);
					maxWidth = bottom - top;
					rotation = Math.PI * (opts.position === 'left' ? -0.5 : 0.5);
				}

				ctx.save();
				ctx.translate(titleX, titleY);
				ctx.rotate(rotation);
				ctx.textAlign = 'center';
				ctx.textBaseline = 'middle';
				ctx.fillText(opts.text, 0, 0, maxWidth);
				ctx.restore();
			}
		}
	});

	function createNewTitleBlockAndAttach(chart, titleOpts) {
		var title = new Chart.Title({
			ctx: chart.ctx,
			options: titleOpts,
			chart: chart
		});

		layout.configure(chart, title, titleOpts);
		layout.addBox(chart, title);
		chart.titleBlock = title;
	}

	return {
		id: 'title',

		beforeInit: function(chart) {
			var titleOpts = chart.options.title;

			if (titleOpts) {
				createNewTitleBlockAndAttach(chart, titleOpts);
			}
		},

		beforeUpdate: function(chart) {
			var titleOpts = chart.options.title;
			var titleBlock = chart.titleBlock;

			if (titleOpts) {
				titleOpts = helpers.configMerge(Chart.defaults.global.title, titleOpts);

				if (titleBlock) {
					layout.configure(chart, titleBlock, titleOpts);
					titleBlock.options = titleOpts;
				} else {
					createNewTitleBlockAndAttach(chart, titleOpts);
				}
			} else if (titleBlock) {
				Chart.layoutService.removeBox(chart, titleBlock);
				delete chart.titleBlock;
			}
		}
	};
};

},{}],44:[function(require,module,exports){
'use strict';

module.exports = function(Chart) {

	var helpers = Chart.helpers;
	// Default config for a category scale
	var defaultConfig = {
		position: 'bottom'
	};

	var DatasetScale = Chart.Scale.extend({
		/**
		* Internal function to get the correct labels. If data.xLabels or data.yLabels are defined, use those
		* else fall back to data.labels
		* @private
		*/
		getLabels: function() {
			var data = this.chart.data;
			return (this.isHorizontal() ? data.xLabels : data.yLabels) || data.labels;
		},

		determineDataLimits: function() {
			var me = this;
			var labels = me.getLabels();
			me.minIndex = 0;
			me.maxIndex = labels.length - 1;
			var findIndex;

			if (me.options.ticks.min !== undefined) {
				// user specified min value
				findIndex = helpers.indexOf(labels, me.options.ticks.min);
				me.minIndex = findIndex !== -1 ? findIndex : me.minIndex;
			}

			if (me.options.ticks.max !== undefined) {
				// user specified max value
				findIndex = helpers.indexOf(labels, me.options.ticks.max);
				me.maxIndex = findIndex !== -1 ? findIndex : me.maxIndex;
			}

			me.min = labels[me.minIndex];
			me.max = labels[me.maxIndex];
		},

		buildTicks: function() {
			var me = this;
			var labels = me.getLabels();
			// If we are viewing some subset of labels, slice the original array
			me.ticks = (me.minIndex === 0 && me.maxIndex === labels.length - 1) ? labels : labels.slice(me.minIndex, me.maxIndex + 1);
		},

		getLabelForIndex: function(index, datasetIndex) {
			var me = this;
			var data = me.chart.data;
			var isHorizontal = me.isHorizontal();

			if (data.yLabels && !isHorizontal) {
				return me.getRightValue(data.datasets[datasetIndex].data[index]);
			}
			return me.ticks[index - me.minIndex];
		},

		// Used to get data value locations.  Value can either be an index or a numerical value
		getPixelForValue: function(value, index, datasetIndex, includeOffset) {
			var me = this;
			// 1 is added because we need the length but we have the indexes
			var offsetAmt = Math.max((me.maxIndex + 1 - me.minIndex - ((me.options.gridLines.offsetGridLines) ? 0 : 1)), 1);

			// If value is a data object, then index is the index in the data array,
			// not the index of the scale. We need to change that.
			var valueCategory;
			if (value !== undefined && value !== null) {
				valueCategory = me.isHorizontal() ? value.x : value.y;
			}
			if (valueCategory !== undefined || (value !== undefined && isNaN(index))) {
				var labels = me.getLabels();
				value = valueCategory || value;
				var idx = labels.indexOf(value);
				index = idx !== -1 ? idx : index;
			}

			if (me.isHorizontal()) {
				var valueWidth = me.width / offsetAmt;
				var widthOffset = (valueWidth * (index - me.minIndex));

				if (me.options.gridLines.offsetGridLines && includeOffset || me.maxIndex === me.minIndex && includeOffset) {
					widthOffset += (valueWidth / 2);
				}

				return me.left + Math.round(widthOffset);
			}
			var valueHeight = me.height / offsetAmt;
			var heightOffset = (valueHeight * (index - me.minIndex));

			if (me.options.gridLines.offsetGridLines && includeOffset) {
				heightOffset += (valueHeight / 2);
			}

			return me.top + Math.round(heightOffset);
		},
		getPixelForTick: function(index, includeOffset) {
			return this.getPixelForValue(this.ticks[index], index + this.minIndex, null, includeOffset);
		},
		getValueForPixel: function(pixel) {
			var me = this;
			var value;
			var offsetAmt = Math.max((me.ticks.length - ((me.options.gridLines.offsetGridLines) ? 0 : 1)), 1);
			var horz = me.isHorizontal();
			var valueDimension = (horz ? me.width : me.height) / offsetAmt;

			pixel -= horz ? me.left : me.top;

			if (me.options.gridLines.offsetGridLines) {
				pixel -= (valueDimension / 2);
			}

			if (pixel <= 0) {
				value = 0;
			} else {
				value = Math.round(pixel / valueDimension);
			}

			return value;
		},
		getBasePixel: function() {
			return this.bottom;
		}
	});

	Chart.scaleService.registerScaleType('category', DatasetScale, defaultConfig);

};

},{}],45:[function(require,module,exports){
'use strict';

module.exports = function(Chart) {

	var helpers = Chart.helpers;

	var defaultConfig = {
		position: 'left',
		ticks: {
			callback: Chart.Ticks.formatters.linear
		}
	};

	var LinearScale = Chart.LinearScaleBase.extend({

		determineDataLimits: function() {
			var me = this;
			var opts = me.options;
			var chart = me.chart;
			var data = chart.data;
			var datasets = data.datasets;
			var isHorizontal = me.isHorizontal();
			var DEFAULT_MIN = 0;
			var DEFAULT_MAX = 1;

			function IDMatches(meta) {
				return isHorizontal ? meta.xAxisID === me.id : meta.yAxisID === me.id;
			}

			// First Calculate the range
			me.min = null;
			me.max = null;

			var hasStacks = opts.stacked;
			if (hasStacks === undefined) {
				helpers.each(datasets, function(dataset, datasetIndex) {
					if (hasStacks) {
						return;
					}

					var meta = chart.getDatasetMeta(datasetIndex);
					if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta) &&
						meta.stack !== undefined) {
						hasStacks = true;
					}
				});
			}

			if (opts.stacked || hasStacks) {
				var valuesPerStack = {};

				helpers.each(datasets, function(dataset, datasetIndex) {
					var meta = chart.getDatasetMeta(datasetIndex);
					var key = [
						meta.type,
						// we have a separate stack for stack=undefined datasets when the opts.stacked is undefined
						((opts.stacked === undefined && meta.stack === undefined) ? datasetIndex : ''),
						meta.stack
					].join('.');

					if (valuesPerStack[key] === undefined) {
						valuesPerStack[key] = {
							positiveValues: [],
							negativeValues: []
						};
					}

					// Store these per type
					var positiveValues = valuesPerStack[key].positiveValues;
					var negativeValues = valuesPerStack[key].negativeValues;

					if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
						helpers.each(dataset.data, function(rawValue, index) {
							var value = +me.getRightValue(rawValue);
							if (isNaN(value) || meta.data[index].hidden) {
								return;
							}

							positiveValues[index] = positiveValues[index] || 0;
							negativeValues[index] = negativeValues[index] || 0;

							if (opts.relativePoints) {
								positiveValues[index] = 100;
							} else if (value < 0) {
								negativeValues[index] += value;
							} else {
								positiveValues[index] += value;
							}
						});
					}
				});

				helpers.each(valuesPerStack, function(valuesForType) {
					var values = valuesForType.positiveValues.concat(valuesForType.negativeValues);
					var minVal = helpers.min(values);
					var maxVal = helpers.max(values);
					me.min = me.min === null ? minVal : Math.min(me.min, minVal);
					me.max = me.max === null ? maxVal : Math.max(me.max, maxVal);
				});

			} else {
				helpers.each(datasets, function(dataset, datasetIndex) {
					var meta = chart.getDatasetMeta(datasetIndex);
					if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
						helpers.each(dataset.data, function(rawValue, index) {
							var value = +me.getRightValue(rawValue);
							if (isNaN(value) || meta.data[index].hidden) {
								return;
							}

							if (me.min === null) {
								me.min = value;
							} else if (value < me.min) {
								me.min = value;
							}

							if (me.max === null) {
								me.max = value;
							} else if (value > me.max) {
								me.max = value;
							}
						});
					}
				});
			}

			me.min = isFinite(me.min) ? me.min : DEFAULT_MIN;
			me.max = isFinite(me.max) ? me.max : DEFAULT_MAX;

			// Common base implementation to handle ticks.min, ticks.max, ticks.beginAtZero
			this.handleTickRangeOptions();
		},
		getTickLimit: function() {
			var maxTicks;
			var me = this;
			var tickOpts = me.options.ticks;

			if (me.isHorizontal()) {
				maxTicks = Math.min(tickOpts.maxTicksLimit ? tickOpts.maxTicksLimit : 11, Math.ceil(me.width / 50));
			} else {
				// The factor of 2 used to scale the font size has been experimentally determined.
				var tickFontSize = helpers.getValueOrDefault(tickOpts.fontSize, Chart.defaults.global.defaultFontSize);
				maxTicks = Math.min(tickOpts.maxTicksLimit ? tickOpts.maxTicksLimit : 11, Math.ceil(me.height / (2 * tickFontSize)));
			}

			return maxTicks;
		},
		// Called after the ticks are built. We need
		handleDirectionalChanges: function() {
			if (!this.isHorizontal()) {
				// We are in a vertical orientation. The top value is the highest. So reverse the array
				this.ticks.reverse();
			}
		},
		getLabelForIndex: function(index, datasetIndex) {
			return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]);
		},
		// Utils
		getPixelForValue: function(value) {
			// This must be called after fit has been run so that
			// this.left, this.top, this.right, and this.bottom have been defined
			var me = this;
			var start = me.start;

			var rightValue = +me.getRightValue(value);
			var pixel;
			var range = me.end - start;

			if (me.isHorizontal()) {
				pixel = me.left + (me.width / range * (rightValue - start));
				return Math.round(pixel);
			}

			pixel = me.bottom - (me.height / range * (rightValue - start));
			return Math.round(pixel);
		},
		getValueForPixel: function(pixel) {
			var me = this;
			var isHorizontal = me.isHorizontal();
			var innerDimension = isHorizontal ? me.width : me.height;
			var offset = (isHorizontal ? pixel - me.left : me.bottom - pixel) / innerDimension;
			return me.start + ((me.end - me.start) * offset);
		},
		getPixelForTick: function(index) {
			return this.getPixelForValue(this.ticksAsNumbers[index]);
		}
	});
	Chart.scaleService.registerScaleType('linear', LinearScale, defaultConfig);

};

},{}],46:[function(require,module,exports){
'use strict';

module.exports = function(Chart) {

	var helpers = Chart.helpers,
		noop = helpers.noop;

	Chart.LinearScaleBase = Chart.Scale.extend({
		handleTickRangeOptions: function() {
			var me = this;
			var opts = me.options;
			var tickOpts = opts.ticks;

			// If we are forcing it to begin at 0, but 0 will already be rendered on the chart,
			// do nothing since that would make the chart weird. If the user really wants a weird chart
			// axis, they can manually override it
			if (tickOpts.beginAtZero) {
				var minSign = helpers.sign(me.min);
				var maxSign = helpers.sign(me.max);

				if (minSign < 0 && maxSign < 0) {
					// move the top up to 0
					me.max = 0;
				} else if (minSign > 0 && maxSign > 0) {
					// move the bottom down to 0
					me.min = 0;
				}
			}

			if (tickOpts.min !== undefined) {
				me.min = tickOpts.min;
			} else if (tickOpts.suggestedMin !== undefined) {
				if (me.min === null) {
					me.min = tickOpts.suggestedMin;
				} else {
					me.min = Math.min(me.min, tickOpts.suggestedMin);
				}
			}

			if (tickOpts.max !== undefined) {
				me.max = tickOpts.max;
			} else if (tickOpts.suggestedMax !== undefined) {
				if (me.max === null) {
					me.max = tickOpts.suggestedMax;
				} else {
					me.max = Math.max(me.max, tickOpts.suggestedMax);
				}
			}

			if (me.min === me.max) {
				me.max++;

				if (!tickOpts.beginAtZero) {
					me.min--;
				}
			}
		},
		getTickLimit: noop,
		handleDirectionalChanges: noop,

		buildTicks: function() {
			var me = this;
			var opts = me.options;
			var tickOpts = opts.ticks;

			// Figure out what the max number of ticks we can support it is based on the size of
			// the axis area. For now, we say that the minimum tick spacing in pixels must be 50
			// We also limit the maximum number of ticks to 11 which gives a nice 10 squares on
			// the graph. Make sure we always have at least 2 ticks
			var maxTicks = me.getTickLimit();
			maxTicks = Math.max(2, maxTicks);

			var numericGeneratorOptions = {
				maxTicks: maxTicks,
				min: tickOpts.min,
				max: tickOpts.max,
				stepSize: helpers.getValueOrDefault(tickOpts.fixedStepSize, tickOpts.stepSize)
			};
			var ticks = me.ticks = Chart.Ticks.generators.linear(numericGeneratorOptions, me);

			me.handleDirectionalChanges();

			// At this point, we need to update our max and min given the tick values since we have expanded the
			// range of the scale
			me.max = helpers.max(ticks);
			me.min = helpers.min(ticks);

			if (tickOpts.reverse) {
				ticks.reverse();

				me.start = me.max;
				me.end = me.min;
			} else {
				me.start = me.min;
				me.end = me.max;
			}
		},
		convertTicksToLabels: function() {
			var me = this;
			me.ticksAsNumbers = me.ticks.slice();
			me.zeroLineIndex = me.ticks.indexOf(0);

			Chart.Scale.prototype.convertTicksToLabels.call(me);
		}
	});
};

},{}],47:[function(require,module,exports){
'use strict';

module.exports = function(Chart) {

	var helpers = Chart.helpers;

	var defaultConfig = {
		position: 'left',

		// label settings
		ticks: {
			callback: Chart.Ticks.formatters.logarithmic
		}
	};

	var LogarithmicScale = Chart.Scale.extend({
		determineDataLimits: function() {
			var me = this;
			var opts = me.options;
			var tickOpts = opts.ticks;
			var chart = me.chart;
			var data = chart.data;
			var datasets = data.datasets;
			var getValueOrDefault = helpers.getValueOrDefault;
			var isHorizontal = me.isHorizontal();
			function IDMatches(meta) {
				return isHorizontal ? meta.xAxisID === me.id : meta.yAxisID === me.id;
			}

			// Calculate Range
			me.min = null;
			me.max = null;
			me.minNotZero = null;

			var hasStacks = opts.stacked;
			if (hasStacks === undefined) {
				helpers.each(datasets, function(dataset, datasetIndex) {
					if (hasStacks) {
						return;
					}

					var meta = chart.getDatasetMeta(datasetIndex);
					if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta) &&
						meta.stack !== undefined) {
						hasStacks = true;
					}
				});
			}

			if (opts.stacked || hasStacks) {
				var valuesPerStack = {};

				helpers.each(datasets, function(dataset, datasetIndex) {
					var meta = chart.getDatasetMeta(datasetIndex);
					var key = [
						meta.type,
						// we have a separate stack for stack=undefined datasets when the opts.stacked is undefined
						((opts.stacked === undefined && meta.stack === undefined) ? datasetIndex : ''),
						meta.stack
					].join('.');

					if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
						if (valuesPerStack[key] === undefined) {
							valuesPerStack[key] = [];
						}

						helpers.each(dataset.data, function(rawValue, index) {
							var values = valuesPerStack[key];
							var value = +me.getRightValue(rawValue);
							if (isNaN(value) || meta.data[index].hidden) {
								return;
							}

							values[index] = values[index] || 0;

							if (opts.relativePoints) {
								values[index] = 100;
							} else {
								// Don't need to split positive and negative since the log scale can't handle a 0 crossing
								values[index] += value;
							}
						});
					}
				});

				helpers.each(valuesPerStack, function(valuesForType) {
					var minVal = helpers.min(valuesForType);
					var maxVal = helpers.max(valuesForType);
					me.min = me.min === null ? minVal : Math.min(me.min, minVal);
					me.max = me.max === null ? maxVal : Math.max(me.max, maxVal);
				});

			} else {
				helpers.each(datasets, function(dataset, datasetIndex) {
					var meta = chart.getDatasetMeta(datasetIndex);
					if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
						helpers.each(dataset.data, function(rawValue, index) {
							var value = +me.getRightValue(rawValue);
							if (isNaN(value) || meta.data[index].hidden) {
								return;
							}

							if (me.min === null) {
								me.min = value;
							} else if (value < me.min) {
								me.min = value;
							}

							if (me.max === null) {
								me.max = value;
							} else if (value > me.max) {
								me.max = value;
							}

							if (value !== 0 && (me.minNotZero === null || value < me.minNotZero)) {
								me.minNotZero = value;
							}
						});
					}
				});
			}

			me.min = getValueOrDefault(tickOpts.min, me.min);
			me.max = getValueOrDefault(tickOpts.max, me.max);

			if (me.min === me.max) {
				if (me.min !== 0 && me.min !== null) {
					me.min = Math.pow(10, Math.floor(helpers.log10(me.min)) - 1);
					me.max = Math.pow(10, Math.floor(helpers.log10(me.max)) + 1);
				} else {
					me.min = 1;
					me.max = 10;
				}
			}
		},
		buildTicks: function() {
			var me = this;
			var opts = me.options;
			var tickOpts = opts.ticks;

			var generationOptions = {
				min: tickOpts.min,
				max: tickOpts.max
			};
			var ticks = me.ticks = Chart.Ticks.generators.logarithmic(generationOptions, me);

			if (!me.isHorizontal()) {
				// We are in a vertical orientation. The top value is the highest. So reverse the array
				ticks.reverse();
			}

			// At this point, we need to update our max and min given the tick values since we have expanded the
			// range of the scale
			me.max = helpers.max(ticks);
			me.min = helpers.min(ticks);

			if (tickOpts.reverse) {
				ticks.reverse();

				me.start = me.max;
				me.end = me.min;
			} else {
				me.start = me.min;
				me.end = me.max;
			}
		},
		convertTicksToLabels: function() {
			this.tickValues = this.ticks.slice();

			Chart.Scale.prototype.convertTicksToLabels.call(this);
		},
		// Get the correct tooltip label
		getLabelForIndex: function(index, datasetIndex) {
			return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]);
		},
		getPixelForTick: function(index) {
			return this.getPixelForValue(this.tickValues[index]);
		},
		getPixelForValue: function(value) {
			var me = this;
			var innerDimension;
			var pixel;

			var start = me.start;
			var newVal = +me.getRightValue(value);
			var range;
			var opts = me.options;
			var tickOpts = opts.ticks;

			if (me.isHorizontal()) {
				range = helpers.log10(me.end) - helpers.log10(start); // todo: if start === 0
				if (newVal === 0) {
					pixel = me.left;
				} else {
					innerDimension = me.width;
					pixel = me.left + (innerDimension / range * (helpers.log10(newVal) - helpers.log10(start)));
				}
			} else {
				// Bottom - top since pixels increase downward on a screen
				innerDimension = me.height;
				if (start === 0 && !tickOpts.reverse) {
					range = helpers.log10(me.end) - helpers.log10(me.minNotZero);
					if (newVal === start) {
						pixel = me.bottom;
					} else if (newVal === me.minNotZero) {
						pixel = me.bottom - innerDimension * 0.02;
					} else {
						pixel = me.bottom - innerDimension * 0.02 - (innerDimension * 0.98/ range * (helpers.log10(newVal)-helpers.log10(me.minNotZero)));
					}
				} else if (me.end === 0 && tickOpts.reverse) {
					range = helpers.log10(me.start) - helpers.log10(me.minNotZero);
					if (newVal === me.end) {
						pixel = me.top;
					} else if (newVal === me.minNotZero) {
						pixel = me.top + innerDimension * 0.02;
					} else {
						pixel = me.top + innerDimension * 0.02 + (innerDimension * 0.98/ range * (helpers.log10(newVal)-helpers.log10(me.minNotZero)));
					}
				} else if (newVal === 0) {
					pixel = tickOpts.reverse ? me.top : me.bottom;
				} else {
					range = helpers.log10(me.end) - helpers.log10(start);
					innerDimension = me.height;
					pixel = me.bottom - (innerDimension / range * (helpers.log10(newVal) - helpers.log10(start)));
				}
			}
			return pixel;
		},
		getValueForPixel: function(pixel) {
			var me = this;
			var range = helpers.log10(me.end) - helpers.log10(me.start);
			var value, innerDimension;

			if (me.isHorizontal()) {
				innerDimension = me.width;
				value = me.start * Math.pow(10, (pixel - me.left) * range / innerDimension);
			} else {  // todo: if start === 0
				innerDimension = me.height;
				value = Math.pow(10, (me.bottom - pixel) * range / innerDimension) / me.start;
			}
			return value;
		}
	});
	Chart.scaleService.registerScaleType('logarithmic', LogarithmicScale, defaultConfig);

};

},{}],48:[function(require,module,exports){
'use strict';

module.exports = function(Chart) {

	var helpers = Chart.helpers;
	var globalDefaults = Chart.defaults.global;

	var defaultConfig = {
		display: true,

		// Boolean - Whether to animate scaling the chart from the centre
		animate: true,
		position: 'chartArea',

		angleLines: {
			display: true,
			color: 'rgba(0, 0, 0, 0.1)',
			lineWidth: 1
		},

		gridLines: {
			circular: false
		},

		// label settings
		ticks: {
			// Boolean - Show a backdrop to the scale label
			showLabelBackdrop: true,

			// String - The colour of the label backdrop
			backdropColor: 'rgba(255,255,255,0.75)',

			// Number - The backdrop padding above & below the label in pixels
			backdropPaddingY: 2,

			// Number - The backdrop padding to the side of the label in pixels
			backdropPaddingX: 2,

			callback: Chart.Ticks.formatters.linear
		},

		pointLabels: {
			// Boolean - if true, show point labels
			display: true,

			// Number - Point label font size in pixels
			fontSize: 10,

			// Function - Used to convert point labels
			callback: function(label) {
				return label;
			}
		}
	};

	function getValueCount(scale) {
		var opts = scale.options;
		return opts.angleLines.display || opts.pointLabels.display ? scale.chart.data.labels.length : 0;
	}

	function getPointLabelFontOptions(scale) {
		var pointLabelOptions = scale.options.pointLabels;
		var fontSize = helpers.getValueOrDefault(pointLabelOptions.fontSize, globalDefaults.defaultFontSize);
		var fontStyle = helpers.getValueOrDefault(pointLabelOptions.fontStyle, globalDefaults.defaultFontStyle);
		var fontFamily = helpers.getValueOrDefault(pointLabelOptions.fontFamily, globalDefaults.defaultFontFamily);
		var font = helpers.fontString(fontSize, fontStyle, fontFamily);

		return {
			size: fontSize,
			style: fontStyle,
			family: fontFamily,
			font: font
		};
	}

	function measureLabelSize(ctx, fontSize, label) {
		if (helpers.isArray(label)) {
			return {
				w: helpers.longestText(ctx, ctx.font, label),
				h: (label.length * fontSize) + ((label.length - 1) * 1.5 * fontSize)
			};
		}

		return {
			w: ctx.measureText(label).width,
			h: fontSize
		};
	}

	function determineLimits(angle, pos, size, min, max) {
		if (angle === min || angle === max) {
			return {
				start: pos - (size / 2),
				end: pos + (size / 2)
			};
		} else if (angle < min || angle > max) {
			return {
				start: pos - size - 5,
				end: pos
			};
		}

		return {
			start: pos,
			end: pos + size + 5
		};
	}

	/**
	 * Helper function to fit a radial linear scale with point labels
	 */
	function fitWithPointLabels(scale) {
		/*
		 * Right, this is really confusing and there is a lot of maths going on here
		 * The gist of the problem is here: https://gist.github.com/nnnick/696cc9c55f4b0beb8fe9
		 *
		 * Reaction: https://dl.dropboxusercontent.com/u/34601363/toomuchscience.gif
		 *
		 * Solution:
		 *
		 * We assume the radius of the polygon is half the size of the canvas at first
		 * at each index we check if the text overlaps.
		 *
		 * Where it does, we store that angle and that index.
		 *
		 * After finding the largest index and angle we calculate how much we need to remove
		 * from the shape radius to move the point inwards by that x.
		 *
		 * We average the left and right distances to get the maximum shape radius that can fit in the box
		 * along with labels.
		 *
		 * Once we have that, we can find the centre point for the chart, by taking the x text protrusion
		 * on each side, removing that from the size, halving it and adding the left x protrusion width.
		 *
		 * This will mean we have a shape fitted to the canvas, as large as it can be with the labels
		 * and position it in the most space efficient manner
		 *
		 * https://dl.dropboxusercontent.com/u/34601363/yeahscience.gif
		 */

		var plFont = getPointLabelFontOptions(scale);

		// Get maximum radius of the polygon. Either half the height (minus the text width) or half the width.
		// Use this to calculate the offset + change. - Make sure L/R protrusion is at least 0 to stop issues with centre points
		var largestPossibleRadius = Math.min(scale.height / 2, scale.width / 2);
		var furthestLimits = {
			r: scale.width,
			l: 0,
			t: scale.height,
			b: 0
		};
		var furthestAngles = {};
		var i;
		var textSize;
		var pointPosition;

		scale.ctx.font = plFont.font;
		scale._pointLabelSizes = [];

		var valueCount = getValueCount(scale);
		for (i = 0; i < valueCount; i++) {
			pointPosition = scale.getPointPosition(i, largestPossibleRadius);
			textSize = measureLabelSize(scale.ctx, plFont.size, scale.pointLabels[i] || '');
			scale._pointLabelSizes[i] = textSize;

			// Add quarter circle to make degree 0 mean top of circle
			var angleRadians = scale.getIndexAngle(i);
			var angle = helpers.toDegrees(angleRadians) % 360;
			var hLimits = determineLimits(angle, pointPosition.x, textSize.w, 0, 180);
			var vLimits = determineLimits(angle, pointPosition.y, textSize.h, 90, 270);

			if (hLimits.start < furthestLimits.l) {
				furthestLimits.l = hLimits.start;
				furthestAngles.l = angleRadians;
			}

			if (hLimits.end > furthestLimits.r) {
				furthestLimits.r = hLimits.end;
				furthestAngles.r = angleRadians;
			}

			if (vLimits.start < furthestLimits.t) {
				furthestLimits.t = vLimits.start;
				furthestAngles.t = angleRadians;
			}

			if (vLimits.end > furthestLimits.b) {
				furthestLimits.b = vLimits.end;
				furthestAngles.b = angleRadians;
			}
		}

		scale.setReductions(largestPossibleRadius, furthestLimits, furthestAngles);
	}

	/**
	 * Helper function to fit a radial linear scale with no point labels
	 */
	function fit(scale) {
		var largestPossibleRadius = Math.min(scale.height / 2, scale.width / 2);
		scale.drawingArea = Math.round(largestPossibleRadius);
		scale.setCenterPoint(0, 0, 0, 0);
	}

	function getTextAlignForAngle(angle) {
		if (angle === 0 || angle === 180) {
			return 'center';
		} else if (angle < 180) {
			return 'left';
		}

		return 'right';
	}

	function fillText(ctx, text, position, fontSize) {
		if (helpers.isArray(text)) {
			var y = position.y;
			var spacing = 1.5 * fontSize;

			for (var i = 0; i < text.length; ++i) {
				ctx.fillText(text[i], position.x, y);
				y+= spacing;
			}
		} else {
			ctx.fillText(text, position.x, position.y);
		}
	}

	function adjustPointPositionForLabelHeight(angle, textSize, position) {
		if (angle === 90 || angle === 270) {
			position.y -= (textSize.h / 2);
		} else if (angle > 270 || angle < 90) {
			position.y -= textSize.h;
		}
	}

	function drawPointLabels(scale) {
		var ctx = scale.ctx;
		var getValueOrDefault = helpers.getValueOrDefault;
		var opts = scale.options;
		var angleLineOpts = opts.angleLines;
		var pointLabelOpts = opts.pointLabels;

		ctx.lineWidth = angleLineOpts.lineWidth;
		ctx.strokeStyle = angleLineOpts.color;

		var outerDistance = scale.getDistanceFromCenterForValue(opts.reverse ? scale.min : scale.max);

		// Point Label Font
		var plFont = getPointLabelFontOptions(scale);

		ctx.textBaseline = 'top';

		for (var i = getValueCount(scale) - 1; i >= 0; i--) {
			if (angleLineOpts.display) {
				var outerPosition = scale.getPointPosition(i, outerDistance);
				ctx.beginPath();
				ctx.moveTo(scale.xCenter, scale.yCenter);
				ctx.lineTo(outerPosition.x, outerPosition.y);
				ctx.stroke();
				ctx.closePath();
			}

			if (pointLabelOpts.display) {
				// Extra 3px out for some label spacing
				var pointLabelPosition = scale.getPointPosition(i, outerDistance + 5);

				// Keep this in loop since we may support array properties here
				var pointLabelFontColor = getValueOrDefault(pointLabelOpts.fontColor, globalDefaults.defaultFontColor);
				ctx.font = plFont.font;
				ctx.fillStyle = pointLabelFontColor;

				var angleRadians = scale.getIndexAngle(i);
				var angle = helpers.toDegrees(angleRadians);
				ctx.textAlign = getTextAlignForAngle(angle);
				adjustPointPositionForLabelHeight(angle, scale._pointLabelSizes[i], pointLabelPosition);
				fillText(ctx, scale.pointLabels[i] || '', pointLabelPosition, plFont.size);
			}
		}
	}

	function drawRadiusLine(scale, gridLineOpts, radius, index) {
		var ctx = scale.ctx;
		ctx.strokeStyle = helpers.getValueAtIndexOrDefault(gridLineOpts.color, index - 1);
		ctx.lineWidth = helpers.getValueAtIndexOrDefault(gridLineOpts.lineWidth, index - 1);

		if (scale.options.gridLines.circular) {
			// Draw circular arcs between the points
			ctx.beginPath();
			ctx.arc(scale.xCenter, scale.yCenter, radius, 0, Math.PI * 2);
			ctx.closePath();
			ctx.stroke();
		} else {
			// Draw straight lines connecting each index
			var valueCount = getValueCount(scale);

			if (valueCount === 0) {
				return;
			}

			ctx.beginPath();
			var pointPosition = scale.getPointPosition(0, radius);
			ctx.moveTo(pointPosition.x, pointPosition.y);

			for (var i = 1; i < valueCount; i++) {
				pointPosition = scale.getPointPosition(i, radius);
				ctx.lineTo(pointPosition.x, pointPosition.y);
			}

			ctx.closePath();
			ctx.stroke();
		}
	}

	function numberOrZero(param) {
		return helpers.isNumber(param) ? param : 0;
	}

	var LinearRadialScale = Chart.LinearScaleBase.extend({
		setDimensions: function() {
			var me = this;
			var opts = me.options;
			var tickOpts = opts.ticks;
			// Set the unconstrained dimension before label rotation
			me.width = me.maxWidth;
			me.height = me.maxHeight;
			me.xCenter = Math.round(me.width / 2);
			me.yCenter = Math.round(me.height / 2);

			var minSize = helpers.min([me.height, me.width]);
			var tickFontSize = helpers.getValueOrDefault(tickOpts.fontSize, globalDefaults.defaultFontSize);
			me.drawingArea = opts.display ? (minSize / 2) - (tickFontSize / 2 + tickOpts.backdropPaddingY) : (minSize / 2);
		},
		determineDataLimits: function() {
			var me = this;
			var chart = me.chart;
			var min = Number.POSITIVE_INFINITY;
			var max = Number.NEGATIVE_INFINITY;

			helpers.each(chart.data.datasets, function(dataset, datasetIndex) {
				if (chart.isDatasetVisible(datasetIndex)) {
					var meta = chart.getDatasetMeta(datasetIndex);

					helpers.each(dataset.data, function(rawValue, index) {
						var value = +me.getRightValue(rawValue);
						if (isNaN(value) || meta.data[index].hidden) {
							return;
						}

						min = Math.min(value, min);
						max = Math.max(value, max);
					});
				}
			});

			me.min = (min === Number.POSITIVE_INFINITY ? 0 : min);
			me.max = (max === Number.NEGATIVE_INFINITY ? 0 : max);

			// Common base implementation to handle ticks.min, ticks.max, ticks.beginAtZero
			me.handleTickRangeOptions();
		},
		getTickLimit: function() {
			var tickOpts = this.options.ticks;
			var tickFontSize = helpers.getValueOrDefault(tickOpts.fontSize, globalDefaults.defaultFontSize);
			return Math.min(tickOpts.maxTicksLimit ? tickOpts.maxTicksLimit : 11, Math.ceil(this.drawingArea / (1.5 * tickFontSize)));
		},
		convertTicksToLabels: function() {
			var me = this;
			Chart.LinearScaleBase.prototype.convertTicksToLabels.call(me);

			// Point labels
			me.pointLabels = me.chart.data.labels.map(me.options.pointLabels.callback, me);
		},
		getLabelForIndex: function(index, datasetIndex) {
			return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]);
		},
		fit: function() {
			if (this.options.pointLabels.display) {
				fitWithPointLabels(this);
			} else {
				fit(this);
			}
		},
		/**
		 * Set radius reductions and determine new radius and center point
		 * @private
		 */
		setReductions: function(largestPossibleRadius, furthestLimits, furthestAngles) {
			var me = this;
			var radiusReductionLeft = furthestLimits.l / Math.sin(furthestAngles.l);
			var radiusReductionRight = Math.max(furthestLimits.r - me.width, 0) / Math.sin(furthestAngles.r);
			var radiusReductionTop = -furthestLimits.t / Math.cos(furthestAngles.t);
			var radiusReductionBottom = -Math.max(furthestLimits.b - me.height, 0) / Math.cos(furthestAngles.b);

			radiusReductionLeft = numberOrZero(radiusReductionLeft);
			radiusReductionRight = numberOrZero(radiusReductionRight);
			radiusReductionTop = numberOrZero(radiusReductionTop);
			radiusReductionBottom = numberOrZero(radiusReductionBottom);

			me.drawingArea = Math.min(
				Math.round(largestPossibleRadius - (radiusReductionLeft + radiusReductionRight) / 2),
				Math.round(largestPossibleRadius - (radiusReductionTop + radiusReductionBottom) / 2));
			me.setCenterPoint(radiusReductionLeft, radiusReductionRight, radiusReductionTop, radiusReductionBottom);
		},
		setCenterPoint: function(leftMovement, rightMovement, topMovement, bottomMovement) {
			var me = this;
			var maxRight = me.width - rightMovement - me.drawingArea,
				maxLeft = leftMovement + me.drawingArea,
				maxTop = topMovement + me.drawingArea,
				maxBottom = me.height - bottomMovement - me.drawingArea;

			me.xCenter = Math.round(((maxLeft + maxRight) / 2) + me.left);
			me.yCenter = Math.round(((maxTop + maxBottom) / 2) + me.top);
		},

		getIndexAngle: function(index) {
			var angleMultiplier = (Math.PI * 2) / getValueCount(this);
			var startAngle = this.chart.options && this.chart.options.startAngle ?
				this.chart.options.startAngle :
				0;

			var startAngleRadians = startAngle * Math.PI * 2 / 360;

			// Start from the top instead of right, so remove a quarter of the circle
			return index * angleMultiplier + startAngleRadians;
		},
		getDistanceFromCenterForValue: function(value) {
			var me = this;

			if (value === null) {
				return 0; // null always in center
			}

			// Take into account half font size + the yPadding of the top value
			var scalingFactor = me.drawingArea / (me.max - me.min);
			if (me.options.reverse) {
				return (me.max - value) * scalingFactor;
			}
			return (value - me.min) * scalingFactor;
		},
		getPointPosition: function(index, distanceFromCenter) {
			var me = this;
			var thisAngle = me.getIndexAngle(index) - (Math.PI / 2);
			return {
				x: Math.round(Math.cos(thisAngle) * distanceFromCenter) + me.xCenter,
				y: Math.round(Math.sin(thisAngle) * distanceFromCenter) + me.yCenter
			};
		},
		getPointPositionForValue: function(index, value) {
			return this.getPointPosition(index, this.getDistanceFromCenterForValue(value));
		},

		getBasePosition: function() {
			var me = this;
			var min = me.min;
			var max = me.max;

			return me.getPointPositionForValue(0,
				me.beginAtZero? 0:
				min < 0 && max < 0? max :
				min > 0 && max > 0? min :
				0);
		},

		draw: function() {
			var me = this;
			var opts = me.options;
			var gridLineOpts = opts.gridLines;
			var tickOpts = opts.ticks;
			var getValueOrDefault = helpers.getValueOrDefault;

			if (opts.display) {
				var ctx = me.ctx;

				// Tick Font
				var tickFontSize = getValueOrDefault(tickOpts.fontSize, globalDefaults.defaultFontSize);
				var tickFontStyle = getValueOrDefault(tickOpts.fontStyle, globalDefaults.defaultFontStyle);
				var tickFontFamily = getValueOrDefault(tickOpts.fontFamily, globalDefaults.defaultFontFamily);
				var tickLabelFont = helpers.fontString(tickFontSize, tickFontStyle, tickFontFamily);

				helpers.each(me.ticks, function(label, index) {
					// Don't draw a centre value (if it is minimum)
					if (index > 0 || opts.reverse) {
						var yCenterOffset = me.getDistanceFromCenterForValue(me.ticksAsNumbers[index]);
						var yHeight = me.yCenter - yCenterOffset;

						// Draw circular lines around the scale
						if (gridLineOpts.display && index !== 0) {
							drawRadiusLine(me, gridLineOpts, yCenterOffset, index);
						}

						if (tickOpts.display) {
							var tickFontColor = getValueOrDefault(tickOpts.fontColor, globalDefaults.defaultFontColor);
							ctx.font = tickLabelFont;

							if (tickOpts.showLabelBackdrop) {
								var labelWidth = ctx.measureText(label).width;
								ctx.fillStyle = tickOpts.backdropColor;
								ctx.fillRect(
									me.xCenter - labelWidth / 2 - tickOpts.backdropPaddingX,
									yHeight - tickFontSize / 2 - tickOpts.backdropPaddingY,
									labelWidth + tickOpts.backdropPaddingX * 2,
									tickFontSize + tickOpts.backdropPaddingY * 2
								);
							}

							ctx.textAlign = 'center';
							ctx.textBaseline = 'middle';
							ctx.fillStyle = tickFontColor;
							ctx.fillText(label, me.xCenter, yHeight);
						}
					}
				});

				if (opts.angleLines.display || opts.pointLabels.display) {
					drawPointLabels(me);
				}
			}
		}
	});
	Chart.scaleService.registerScaleType('radialLinear', LinearRadialScale, defaultConfig);

};

},{}],49:[function(require,module,exports){
/* global window: false */
'use strict';

var moment = require(1);
moment = typeof(moment) === 'function' ? moment : window.moment;

module.exports = function(Chart) {

	var helpers = Chart.helpers;
	var interval = {
		millisecond: {
			size: 1,
			steps: [1, 2, 5, 10, 20, 50, 100, 250, 500]
		},
		second: {
			size: 1000,
			steps: [1, 2, 5, 10, 30]
		},
		minute: {
			size: 60000,
			steps: [1, 2, 5, 10, 30]
		},
		hour: {
			size: 3600000,
			steps: [1, 2, 3, 6, 12]
		},
		day: {
			size: 86400000,
			steps: [1, 2, 5]
		},
		week: {
			size: 604800000,
			maxStep: 4
		},
		month: {
			size: 2.628e9,
			maxStep: 3
		},
		quarter: {
			size: 7.884e9,
			maxStep: 4
		},
		year: {
			size: 3.154e10,
			maxStep: false
		}
	};

	var defaultConfig = {
		position: 'bottom',

		time: {
			parser: false, // false == a pattern string from http://momentjs.com/docs/#/parsing/string-format/ or a custom callback that converts its argument to a moment
			format: false, // DEPRECATED false == date objects, moment object, callback or a pattern string from http://momentjs.com/docs/#/parsing/string-format/
			unit: false, // false == automatic or override with week, month, year, etc.
			round: false, // none, or override with week, month, year, etc.
			displayFormat: false, // DEPRECATED
			isoWeekday: false, // override week start day - see http://momentjs.com/docs/#/get-set/iso-weekday/
			minUnit: 'millisecond',

			// defaults to unit's corresponding unitFormat below or override using pattern string from http://momentjs.com/docs/#/displaying/format/
			displayFormats: {
				millisecond: 'h:mm:ss.SSS a', // 11:20:01.123 AM,
				second: 'h:mm:ss a', // 11:20:01 AM
				minute: 'h:mm:ss a', // 11:20:01 AM
				hour: 'MMM D, hA', // Sept 4, 5PM
				day: 'll', // Sep 4 2015
				week: 'll', // Week 46, or maybe "[W]WW - YYYY" ?
				month: 'MMM YYYY', // Sept 2015
				quarter: '[Q]Q - YYYY', // Q3
				year: 'YYYY' // 2015
			},
		},
		ticks: {
			autoSkip: false
		}
	};

	/**
	 * Helper function to parse time to a moment object
	 * @param axis {TimeAxis} the time axis
	 * @param label {Date|string|number|Moment} The thing to parse
	 * @return {Moment} parsed time
	 */
	function parseTime(axis, label) {
		var timeOpts = axis.options.time;
		if (typeof timeOpts.parser === 'string') {
			return moment(label, timeOpts.parser);
		}
		if (typeof timeOpts.parser === 'function') {
			return timeOpts.parser(label);
		}
		if (typeof label.getMonth === 'function' || typeof label === 'number') {
			// Date objects
			return moment(label);
		}
		if (label.isValid && label.isValid()) {
			// Moment support
			return label;
		}
		var format = timeOpts.format;
		if (typeof format !== 'string' && format.call) {
			// Custom parsing (return an instance of moment)
			console.warn('options.time.format is deprecated and replaced by options.time.parser.');
			return format(label);
		}
		// Moment format parsing
		return moment(label, format);
	}

	/**
	 * Figure out which is the best unit for the scale
	 * @param minUnit {String} minimum unit to use
	 * @param min {Number} scale minimum
	 * @param max {Number} scale maximum
	 * @return {String} the unit to use
	 */
	function determineUnit(minUnit, min, max, maxTicks) {
		var units = Object.keys(interval);
		var unit;
		var numUnits = units.length;

		for (var i = units.indexOf(minUnit); i < numUnits; i++) {
			unit = units[i];
			var unitDetails = interval[unit];
			var steps = (unitDetails.steps && unitDetails.steps[unitDetails.steps.length - 1]) || unitDetails.maxStep;
			if (steps === undefined || Math.ceil((max - min) / (steps * unitDetails.size)) <= maxTicks) {
				break;
			}
		}

		return unit;
	}

	/**
	 * Determines how we scale the unit
	 * @param min {Number} the scale minimum
	 * @param max {Number} the scale maximum
	 * @param unit {String} the unit determined by the {@see determineUnit} method
	 * @return {Number} the axis step size as a multiple of unit
	 */
	function determineStepSize(min, max, unit, maxTicks) {
		// Using our unit, figoure out what we need to scale as
		var unitDefinition = interval[unit];
		var unitSizeInMilliSeconds = unitDefinition.size;
		var sizeInUnits = Math.ceil((max - min) / unitSizeInMilliSeconds);
		var multiplier = 1;
		var range = max - min;

		if (unitDefinition.steps) {
			// Have an array of steps
			var numSteps = unitDefinition.steps.length;
			for (var i = 0; i < numSteps && sizeInUnits > maxTicks; i++) {
				multiplier = unitDefinition.steps[i];
				sizeInUnits = Math.ceil(range / (unitSizeInMilliSeconds * multiplier));
			}
		} else {
			while (sizeInUnits > maxTicks && maxTicks > 0) {
				++multiplier;
				sizeInUnits = Math.ceil(range / (unitSizeInMilliSeconds * multiplier));
			}
		}

		return multiplier;
	}

	/**
	 * Helper for generating axis labels.
	 * @param options {ITimeGeneratorOptions} the options for generation
	 * @param dataRange {IRange} the data range
	 * @param niceRange {IRange} the pretty range to display
	 * @return {Number[]} ticks
	 */
	function generateTicks(options, dataRange, niceRange) {
		var ticks = [];
		if (options.maxTicks) {
			var stepSize = options.stepSize;
			ticks.push(options.min !== undefined ? options.min : niceRange.min);
			var cur = moment(niceRange.min);
			while (cur.add(stepSize, options.unit).valueOf() < niceRange.max) {
				ticks.push(cur.valueOf());
			}
			var realMax = options.max || niceRange.max;
			if (ticks[ticks.length - 1] !== realMax) {
				ticks.push(realMax);
			}
		}
		return ticks;
	}

	/**
	 * @function Chart.Ticks.generators.time
	 * @param options {ITimeGeneratorOptions} the options for generation
	 * @param dataRange {IRange} the data range
	 * @return {Number[]} ticks
	 */
	Chart.Ticks.generators.time = function(options, dataRange) {
		var niceMin;
		var niceMax;
		var isoWeekday = options.isoWeekday;
		if (options.unit === 'week' && isoWeekday !== false) {
			niceMin = moment(dataRange.min).startOf('isoWeek').isoWeekday(isoWeekday).valueOf();
			niceMax = moment(dataRange.max).startOf('isoWeek').isoWeekday(isoWeekday);
			if (dataRange.max - niceMax > 0) {
				niceMax.add(1, 'week');
			}
			niceMax = niceMax.valueOf();
		} else {
			niceMin = moment(dataRange.min).startOf(options.unit).valueOf();
			niceMax = moment(dataRange.max).startOf(options.unit);
			if (dataRange.max - niceMax > 0) {
				niceMax.add(1, options.unit);
			}
			niceMax = niceMax.valueOf();
		}
		return generateTicks(options, dataRange, {
			min: niceMin,
			max: niceMax
		});
	};

	var TimeScale = Chart.Scale.extend({
		initialize: function() {
			if (!moment) {
				throw new Error('Chart.js - Moment.js could not be found! You must include it before Chart.js to use the time scale. Download at https://momentjs.com');
			}

			Chart.Scale.prototype.initialize.call(this);
		},
		determineDataLimits: function() {
			var me = this;
			var timeOpts = me.options.time;

			// We store the data range as unix millisecond timestamps so dataMin and dataMax will always be integers.
			var dataMin = Number.MAX_SAFE_INTEGER;
			var dataMax = Number.MIN_SAFE_INTEGER;

			var chartData = me.chart.data;
			var parsedData = {
				labels: [],
				datasets: []
			};

			var timestamp;

			helpers.each(chartData.labels, function(label, labelIndex) {
				var labelMoment = parseTime(me, label);

				if (labelMoment.isValid()) {
					// We need to round the time
					if (timeOpts.round) {
						labelMoment.startOf(timeOpts.round);
					}

					timestamp = labelMoment.valueOf();
					dataMin = Math.min(timestamp, dataMin);
					dataMax = Math.max(timestamp, dataMax);

					// Store this value for later
					parsedData.labels[labelIndex] = timestamp;
				}
			});

			helpers.each(chartData.datasets, function(dataset, datasetIndex) {
				var timestamps = [];

				if (typeof dataset.data[0] === 'object' && dataset.data[0] !== null && me.chart.isDatasetVisible(datasetIndex)) {
					// We have potential point data, so we need to parse this
					helpers.each(dataset.data, function(value, dataIndex) {
						var dataMoment = parseTime(me, me.getRightValue(value));

						if (dataMoment.isValid()) {
							if (timeOpts.round) {
								dataMoment.startOf(timeOpts.round);
							}

							timestamp = dataMoment.valueOf();
							dataMin = Math.min(timestamp, dataMin);
							dataMax = Math.max(timestamp, dataMax);
							timestamps[dataIndex] = timestamp;
						}
					});
				} else {
					// We have no x coordinates, so use the ones from the labels
					timestamps = parsedData.labels.slice();
				}

				parsedData.datasets[datasetIndex] = timestamps;
			});

			me.dataMin = dataMin;
			me.dataMax = dataMax;
			me._parsedData = parsedData;
		},
		buildTicks: function() {
			var me = this;
			var timeOpts = me.options.time;

			var minTimestamp;
			var maxTimestamp;
			var dataMin = me.dataMin;
			var dataMax = me.dataMax;

			if (timeOpts.min) {
				var minMoment = parseTime(me, timeOpts.min);
				if (timeOpts.round) {
					minMoment.round(timeOpts.round);
				}
				minTimestamp = minMoment.valueOf();
			}

			if (timeOpts.max) {
				maxTimestamp = parseTime(me, timeOpts.max).valueOf();
			}

			var maxTicks = me.getLabelCapacity(minTimestamp || dataMin);
			var unit = timeOpts.unit || determineUnit(timeOpts.minUnit, minTimestamp || dataMin, maxTimestamp || dataMax, maxTicks);
			me.displayFormat = timeOpts.displayFormats[unit];

			var stepSize = timeOpts.stepSize || determineStepSize(minTimestamp || dataMin, maxTimestamp || dataMax, unit, maxTicks);
			me.ticks = Chart.Ticks.generators.time({
				maxTicks: maxTicks,
				min: minTimestamp,
				max: maxTimestamp,
				stepSize: stepSize,
				unit: unit,
				isoWeekday: timeOpts.isoWeekday
			}, {
				min: dataMin,
				max: dataMax
			});

			// At this point, we need to update our max and min given the tick values since we have expanded the
			// range of the scale
			me.max = helpers.max(me.ticks);
			me.min = helpers.min(me.ticks);
		},
		// Get tooltip label
		getLabelForIndex: function(index, datasetIndex) {
			var me = this;
			var label = me.chart.data.labels && index < me.chart.data.labels.length ? me.chart.data.labels[index] : '';
			var value = me.chart.data.datasets[datasetIndex].data[index];

			if (value !== null && typeof value === 'object') {
				label = me.getRightValue(value);
			}

			// Format nicely
			if (me.options.time.tooltipFormat) {
				label = parseTime(me, label).format(me.options.time.tooltipFormat);
			}

			return label;
		},
		// Function to format an individual tick mark
		tickFormatFunction: function(tick, index, ticks) {
			var formattedTick = tick.format(this.displayFormat);
			var tickOpts = this.options.ticks;
			var callback = helpers.getValueOrDefault(tickOpts.callback, tickOpts.userCallback);

			if (callback) {
				return callback(formattedTick, index, ticks);
			}
			return formattedTick;
		},
		convertTicksToLabels: function() {
			var me = this;
			me.ticksAsTimestamps = me.ticks;
			me.ticks = me.ticks.map(function(tick) {
				return moment(tick);
			}).map(me.tickFormatFunction, me);
		},
		getPixelForOffset: function(offset) {
			var me = this;
			var epochWidth = me.max - me.min;
			var decimal = epochWidth ? (offset - me.min) / epochWidth : 0;

			if (me.isHorizontal()) {
				var valueOffset = (me.width * decimal);
				return me.left + Math.round(valueOffset);
			}

			var heightOffset = (me.height * decimal);
			return me.top + Math.round(heightOffset);
		},
		getPixelForValue: function(value, index, datasetIndex) {
			var me = this;
			var offset = null;
			if (index !== undefined && datasetIndex !== undefined) {
				offset = me._parsedData.datasets[datasetIndex][index];
			}

			if (offset === null) {
				if (!value || !value.isValid) {
					// not already a moment object
					value = parseTime(me, me.getRightValue(value));
				}

				if (value && value.isValid && value.isValid()) {
					offset = value.valueOf();
				}
			}

			if (offset !== null) {
				return me.getPixelForOffset(offset);
			}
		},
		getPixelForTick: function(index) {
			return this.getPixelForOffset(this.ticksAsTimestamps[index]);
		},
		getValueForPixel: function(pixel) {
			var me = this;
			var innerDimension = me.isHorizontal() ? me.width : me.height;
			var offset = (pixel - (me.isHorizontal() ? me.left : me.top)) / innerDimension;
			return moment(me.min + (offset * (me.max - me.min)));
		},
		// Crude approximation of what the label width might be
		getLabelWidth: function(label) {
			var me = this;
			var ticks = me.options.ticks;

			var tickLabelWidth = me.ctx.measureText(label).width;
			var cosRotation = Math.cos(helpers.toRadians(ticks.maxRotation));
			var sinRotation = Math.sin(helpers.toRadians(ticks.maxRotation));
			var tickFontSize = helpers.getValueOrDefault(ticks.fontSize, Chart.defaults.global.defaultFontSize);
			return (tickLabelWidth * cosRotation) + (tickFontSize * sinRotation);
		},
		getLabelCapacity: function(exampleTime) {
			var me = this;

			me.displayFormat = me.options.time.displayFormats.millisecond;	// Pick the longest format for guestimation
			var exampleLabel = me.tickFormatFunction(moment(exampleTime), 0, []);
			var tickLabelWidth = me.getLabelWidth(exampleLabel);

			var innerWidth = me.isHorizontal() ? me.width : me.height;
			var labelCapacity = innerWidth / tickLabelWidth;
			return labelCapacity;
		}
	});
	Chart.scaleService.registerScaleType('time', TimeScale, defaultConfig);

};

},{"1":1}]},{},[7])(7)
});;
/*!
 * clipboard.js v1.7.1
 * https://zenorocha.github.io/clipboard.js
 *
 * Licensed MIT © Zeno Rocha
 */
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Clipboard = f()}})(function(){var define,module,exports;return (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);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.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){
var DOCUMENT_NODE_TYPE = 9;

/**
 * A polyfill for Element.matches()
 */
if (typeof Element !== 'undefined' && !Element.prototype.matches) {
    var proto = Element.prototype;

    proto.matches = proto.matchesSelector ||
                    proto.mozMatchesSelector ||
                    proto.msMatchesSelector ||
                    proto.oMatchesSelector ||
                    proto.webkitMatchesSelector;
}

/**
 * Finds the closest parent that matches a selector.
 *
 * @param {Element} element
 * @param {String} selector
 * @return {Function}
 */
function closest (element, selector) {
    while (element && element.nodeType !== DOCUMENT_NODE_TYPE) {
        if (typeof element.matches === 'function' &&
            element.matches(selector)) {
          return element;
        }
        element = element.parentNode;
    }
}

module.exports = closest;

},{}],2:[function(require,module,exports){
var closest = require('./closest');

/**
 * Delegates event to a selector.
 *
 * @param {Element} element
 * @param {String} selector
 * @param {String} type
 * @param {Function} callback
 * @param {Boolean} useCapture
 * @return {Object}
 */
function delegate(element, selector, type, callback, useCapture) {
    var listenerFn = listener.apply(this, arguments);

    element.addEventListener(type, listenerFn, useCapture);

    return {
        destroy: function() {
            element.removeEventListener(type, listenerFn, useCapture);
        }
    }
}

/**
 * Finds closest match and invokes callback.
 *
 * @param {Element} element
 * @param {String} selector
 * @param {String} type
 * @param {Function} callback
 * @return {Function}
 */
function listener(element, selector, type, callback) {
    return function(e) {
        e.delegateTarget = closest(e.target, selector);

        if (e.delegateTarget) {
            callback.call(element, e);
        }
    }
}

module.exports = delegate;

},{"./closest":1}],3:[function(require,module,exports){
/**
 * Check if argument is a HTML element.
 *
 * @param {Object} value
 * @return {Boolean}
 */
exports.node = function(value) {
    return value !== undefined
        && value instanceof HTMLElement
        && value.nodeType === 1;
};

/**
 * Check if argument is a list of HTML elements.
 *
 * @param {Object} value
 * @return {Boolean}
 */
exports.nodeList = function(value) {
    var type = Object.prototype.toString.call(value);

    return value !== undefined
        && (type === '[object NodeList]' || type === '[object HTMLCollection]')
        && ('length' in value)
        && (value.length === 0 || exports.node(value[0]));
};

/**
 * Check if argument is a string.
 *
 * @param {Object} value
 * @return {Boolean}
 */
exports.string = function(value) {
    return typeof value === 'string'
        || value instanceof String;
};

/**
 * Check if argument is a function.
 *
 * @param {Object} value
 * @return {Boolean}
 */
exports.fn = function(value) {
    var type = Object.prototype.toString.call(value);

    return type === '[object Function]';
};

},{}],4:[function(require,module,exports){
var is = require('./is');
var delegate = require('delegate');

/**
 * Validates all params and calls the right
 * listener function based on its target type.
 *
 * @param {String|HTMLElement|HTMLCollection|NodeList} target
 * @param {String} type
 * @param {Function} callback
 * @return {Object}
 */
function listen(target, type, callback) {
    if (!target && !type && !callback) {
        throw new Error('Missing required arguments');
    }

    if (!is.string(type)) {
        throw new TypeError('Second argument must be a String');
    }

    if (!is.fn(callback)) {
        throw new TypeError('Third argument must be a Function');
    }

    if (is.node(target)) {
        return listenNode(target, type, callback);
    }
    else if (is.nodeList(target)) {
        return listenNodeList(target, type, callback);
    }
    else if (is.string(target)) {
        return listenSelector(target, type, callback);
    }
    else {
        throw new TypeError('First argument must be a String, HTMLElement, HTMLCollection, or NodeList');
    }
}

/**
 * Adds an event listener to a HTML element
 * and returns a remove listener function.
 *
 * @param {HTMLElement} node
 * @param {String} type
 * @param {Function} callback
 * @return {Object}
 */
function listenNode(node, type, callback) {
    node.addEventListener(type, callback);

    return {
        destroy: function() {
            node.removeEventListener(type, callback);
        }
    }
}

/**
 * Add an event listener to a list of HTML elements
 * and returns a remove listener function.
 *
 * @param {NodeList|HTMLCollection} nodeList
 * @param {String} type
 * @param {Function} callback
 * @return {Object}
 */
function listenNodeList(nodeList, type, callback) {
    Array.prototype.forEach.call(nodeList, function(node) {
        node.addEventListener(type, callback);
    });

    return {
        destroy: function() {
            Array.prototype.forEach.call(nodeList, function(node) {
                node.removeEventListener(type, callback);
            });
        }
    }
}

/**
 * Add an event listener to a selector
 * and returns a remove listener function.
 *
 * @param {String} selector
 * @param {String} type
 * @param {Function} callback
 * @return {Object}
 */
function listenSelector(selector, type, callback) {
    return delegate(document.body, selector, type, callback);
}

module.exports = listen;

},{"./is":3,"delegate":2}],5:[function(require,module,exports){
function select(element) {
    var selectedText;

    if (element.nodeName === 'SELECT') {
        element.focus();

        selectedText = element.value;
    }
    else if (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA') {
        var isReadOnly = element.hasAttribute('readonly');

        if (!isReadOnly) {
            element.setAttribute('readonly', '');
        }

        element.select();
        element.setSelectionRange(0, element.value.length);

        if (!isReadOnly) {
            element.removeAttribute('readonly');
        }

        selectedText = element.value;
    }
    else {
        if (element.hasAttribute('contenteditable')) {
            element.focus();
        }

        var selection = window.getSelection();
        var range = document.createRange();

        range.selectNodeContents(element);
        selection.removeAllRanges();
        selection.addRange(range);

        selectedText = selection.toString();
    }

    return selectedText;
}

module.exports = select;

},{}],6:[function(require,module,exports){
function E () {
  // Keep this empty so it's easier to inherit from
  // (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)
}

E.prototype = {
  on: function (name, callback, ctx) {
    var e = this.e || (this.e = {});

    (e[name] || (e[name] = [])).push({
      fn: callback,
      ctx: ctx
    });

    return this;
  },

  once: function (name, callback, ctx) {
    var self = this;
    function listener () {
      self.off(name, listener);
      callback.apply(ctx, arguments);
    };

    listener._ = callback
    return this.on(name, listener, ctx);
  },

  emit: function (name) {
    var data = [].slice.call(arguments, 1);
    var evtArr = ((this.e || (this.e = {}))[name] || []).slice();
    var i = 0;
    var len = evtArr.length;

    for (i; i < len; i++) {
      evtArr[i].fn.apply(evtArr[i].ctx, data);
    }

    return this;
  },

  off: function (name, callback) {
    var e = this.e || (this.e = {});
    var evts = e[name];
    var liveEvents = [];

    if (evts && callback) {
      for (var i = 0, len = evts.length; i < len; i++) {
        if (evts[i].fn !== callback && evts[i].fn._ !== callback)
          liveEvents.push(evts[i]);
      }
    }

    // Remove event from queue to prevent memory leak
    // Suggested by https://github.com/lazd
    // Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910

    (liveEvents.length)
      ? e[name] = liveEvents
      : delete e[name];

    return this;
  }
};

module.exports = E;

},{}],7:[function(require,module,exports){
(function (global, factory) {
    if (typeof define === "function" && define.amd) {
        define(['module', 'select'], factory);
    } else if (typeof exports !== "undefined") {
        factory(module, require('select'));
    } else {
        var mod = {
            exports: {}
        };
        factory(mod, global.select);
        global.clipboardAction = mod.exports;
    }
})(this, function (module, _select) {
    'use strict';

    var _select2 = _interopRequireDefault(_select);

    function _interopRequireDefault(obj) {
        return obj && obj.__esModule ? obj : {
            default: obj
        };
    }

    var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
        return typeof obj;
    } : function (obj) {
        return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
    };

    function _classCallCheck(instance, Constructor) {
        if (!(instance instanceof Constructor)) {
            throw new TypeError("Cannot call a class as a function");
        }
    }

    var _createClass = function () {
        function defineProperties(target, props) {
            for (var i = 0; i < props.length; i++) {
                var descriptor = props[i];
                descriptor.enumerable = descriptor.enumerable || false;
                descriptor.configurable = true;
                if ("value" in descriptor) descriptor.writable = true;
                Object.defineProperty(target, descriptor.key, descriptor);
            }
        }

        return function (Constructor, protoProps, staticProps) {
            if (protoProps) defineProperties(Constructor.prototype, protoProps);
            if (staticProps) defineProperties(Constructor, staticProps);
            return Constructor;
        };
    }();

    var ClipboardAction = function () {
        /**
         * @param {Object} options
         */
        function ClipboardAction(options) {
            _classCallCheck(this, ClipboardAction);

            this.resolveOptions(options);
            this.initSelection();
        }

        /**
         * Defines base properties passed from constructor.
         * @param {Object} options
         */


        _createClass(ClipboardAction, [{
            key: 'resolveOptions',
            value: function resolveOptions() {
                var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};

                this.action = options.action;
                this.container = options.container;
                this.emitter = options.emitter;
                this.target = options.target;
                this.text = options.text;
                this.trigger = options.trigger;

                this.selectedText = '';
            }
        }, {
            key: 'initSelection',
            value: function initSelection() {
                if (this.text) {
                    this.selectFake();
                } else if (this.target) {
                    this.selectTarget();
                }
            }
        }, {
            key: 'selectFake',
            value: function selectFake() {
                var _this = this;

                var isRTL = document.documentElement.getAttribute('dir') == 'rtl';

                this.removeFake();

                this.fakeHandlerCallback = function () {
                    return _this.removeFake();
                };
                this.fakeHandler = this.container.addEventListener('click', this.fakeHandlerCallback) || true;

                this.fakeElem = document.createElement('textarea');
                // Prevent zooming on iOS
                this.fakeElem.style.fontSize = '12pt';
                // Reset box model
                this.fakeElem.style.border = '0';
                this.fakeElem.style.padding = '0';
                this.fakeElem.style.margin = '0';
                // Move element out of screen horizontally
                this.fakeElem.style.position = 'absolute';
                this.fakeElem.style[isRTL ? 'right' : 'left'] = '-9999px';
                // Move element to the same position vertically
                var yPosition = window.pageYOffset || document.documentElement.scrollTop;
                this.fakeElem.style.top = yPosition + 'px';

                this.fakeElem.setAttribute('readonly', '');
                this.fakeElem.value = this.text;

                this.container.appendChild(this.fakeElem);

                this.selectedText = (0, _select2.default)(this.fakeElem);
                this.copyText();
            }
        }, {
            key: 'removeFake',
            value: function removeFake() {
                if (this.fakeHandler) {
                    this.container.removeEventListener('click', this.fakeHandlerCallback);
                    this.fakeHandler = null;
                    this.fakeHandlerCallback = null;
                }

                if (this.fakeElem) {
                    this.container.removeChild(this.fakeElem);
                    this.fakeElem = null;
                }
            }
        }, {
            key: 'selectTarget',
            value: function selectTarget() {
                this.selectedText = (0, _select2.default)(this.target);
                this.copyText();
            }
        }, {
            key: 'copyText',
            value: function copyText() {
                var succeeded = void 0;

                try {
                    succeeded = document.execCommand(this.action);
                } catch (err) {
                    succeeded = false;
                }

                this.handleResult(succeeded);
            }
        }, {
            key: 'handleResult',
            value: function handleResult(succeeded) {
                this.emitter.emit(succeeded ? 'success' : 'error', {
                    action: this.action,
                    text: this.selectedText,
                    trigger: this.trigger,
                    clearSelection: this.clearSelection.bind(this)
                });
            }
        }, {
            key: 'clearSelection',
            value: function clearSelection() {
                if (this.trigger) {
                    this.trigger.focus();
                }

                window.getSelection().removeAllRanges();
            }
        }, {
            key: 'destroy',
            value: function destroy() {
                this.removeFake();
            }
        }, {
            key: 'action',
            set: function set() {
                var action = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'copy';

                this._action = action;

                if (this._action !== 'copy' && this._action !== 'cut') {
                    throw new Error('Invalid "action" value, use either "copy" or "cut"');
                }
            },
            get: function get() {
                return this._action;
            }
        }, {
            key: 'target',
            set: function set(target) {
                if (target !== undefined) {
                    if (target && (typeof target === 'undefined' ? 'undefined' : _typeof(target)) === 'object' && target.nodeType === 1) {
                        if (this.action === 'copy' && target.hasAttribute('disabled')) {
                            throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');
                        }

                        if (this.action === 'cut' && (target.hasAttribute('readonly') || target.hasAttribute('disabled'))) {
                            throw new Error('Invalid "target" attribute. You can\'t cut text from elements with "readonly" or "disabled" attributes');
                        }

                        this._target = target;
                    } else {
                        throw new Error('Invalid "target" value, use a valid Element');
                    }
                }
            },
            get: function get() {
                return this._target;
            }
        }]);

        return ClipboardAction;
    }();

    module.exports = ClipboardAction;
});

},{"select":5}],8:[function(require,module,exports){
(function (global, factory) {
    if (typeof define === "function" && define.amd) {
        define(['module', './clipboard-action', 'tiny-emitter', 'good-listener'], factory);
    } else if (typeof exports !== "undefined") {
        factory(module, require('./clipboard-action'), require('tiny-emitter'), require('good-listener'));
    } else {
        var mod = {
            exports: {}
        };
        factory(mod, global.clipboardAction, global.tinyEmitter, global.goodListener);
        global.clipboard = mod.exports;
    }
})(this, function (module, _clipboardAction, _tinyEmitter, _goodListener) {
    'use strict';

    var _clipboardAction2 = _interopRequireDefault(_clipboardAction);

    var _tinyEmitter2 = _interopRequireDefault(_tinyEmitter);

    var _goodListener2 = _interopRequireDefault(_goodListener);

    function _interopRequireDefault(obj) {
        return obj && obj.__esModule ? obj : {
            default: obj
        };
    }

    var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
        return typeof obj;
    } : function (obj) {
        return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
    };

    function _classCallCheck(instance, Constructor) {
        if (!(instance instanceof Constructor)) {
            throw new TypeError("Cannot call a class as a function");
        }
    }

    var _createClass = function () {
        function defineProperties(target, props) {
            for (var i = 0; i < props.length; i++) {
                var descriptor = props[i];
                descriptor.enumerable = descriptor.enumerable || false;
                descriptor.configurable = true;
                if ("value" in descriptor) descriptor.writable = true;
                Object.defineProperty(target, descriptor.key, descriptor);
            }
        }

        return function (Constructor, protoProps, staticProps) {
            if (protoProps) defineProperties(Constructor.prototype, protoProps);
            if (staticProps) defineProperties(Constructor, staticProps);
            return Constructor;
        };
    }();

    function _possibleConstructorReturn(self, call) {
        if (!self) {
            throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
        }

        return call && (typeof call === "object" || typeof call === "function") ? call : self;
    }

    function _inherits(subClass, superClass) {
        if (typeof superClass !== "function" && superClass !== null) {
            throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
        }

        subClass.prototype = Object.create(superClass && superClass.prototype, {
            constructor: {
                value: subClass,
                enumerable: false,
                writable: true,
                configurable: true
            }
        });
        if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
    }

    var Clipboard = function (_Emitter) {
        _inherits(Clipboard, _Emitter);

        /**
         * @param {String|HTMLElement|HTMLCollection|NodeList} trigger
         * @param {Object} options
         */
        function Clipboard(trigger, options) {
            _classCallCheck(this, Clipboard);

            var _this = _possibleConstructorReturn(this, (Clipboard.__proto__ || Object.getPrototypeOf(Clipboard)).call(this));

            _this.resolveOptions(options);
            _this.listenClick(trigger);
            return _this;
        }

        /**
         * Defines if attributes would be resolved using internal setter functions
         * or custom functions that were passed in the constructor.
         * @param {Object} options
         */


        _createClass(Clipboard, [{
            key: 'resolveOptions',
            value: function resolveOptions() {
                var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};

                this.action = typeof options.action === 'function' ? options.action : this.defaultAction;
                this.target = typeof options.target === 'function' ? options.target : this.defaultTarget;
                this.text = typeof options.text === 'function' ? options.text : this.defaultText;
                this.container = _typeof(options.container) === 'object' ? options.container : document.body;
            }
        }, {
            key: 'listenClick',
            value: function listenClick(trigger) {
                var _this2 = this;

                this.listener = (0, _goodListener2.default)(trigger, 'click', function (e) {
                    return _this2.onClick(e);
                });
            }
        }, {
            key: 'onClick',
            value: function onClick(e) {
                var trigger = e.delegateTarget || e.currentTarget;

                if (this.clipboardAction) {
                    this.clipboardAction = null;
                }

                this.clipboardAction = new _clipboardAction2.default({
                    action: this.action(trigger),
                    target: this.target(trigger),
                    text: this.text(trigger),
                    container: this.container,
                    trigger: trigger,
                    emitter: this
                });
            }
        }, {
            key: 'defaultAction',
            value: function defaultAction(trigger) {
                return getAttributeValue('action', trigger);
            }
        }, {
            key: 'defaultTarget',
            value: function defaultTarget(trigger) {
                var selector = getAttributeValue('target', trigger);

                if (selector) {
                    return document.querySelector(selector);
                }
            }
        }, {
            key: 'defaultText',
            value: function defaultText(trigger) {
                return getAttributeValue('text', trigger);
            }
        }, {
            key: 'destroy',
            value: function destroy() {
                this.listener.destroy();

                if (this.clipboardAction) {
                    this.clipboardAction.destroy();
                    this.clipboardAction = null;
                }
            }
        }], [{
            key: 'isSupported',
            value: function isSupported() {
                var action = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ['copy', 'cut'];

                var actions = typeof action === 'string' ? [action] : action;
                var support = !!document.queryCommandSupported;

                actions.forEach(function (action) {
                    support = support && !!document.queryCommandSupported(action);
                });

                return support;
            }
        }]);

        return Clipboard;
    }(_tinyEmitter2.default);

    /**
     * Helper function to retrieve attribute value.
     * @param {String} suffix
     * @param {Element} element
     */
    function getAttributeValue(suffix, element) {
        var attribute = 'data-clipboard-' + suffix;

        if (!element.hasAttribute(attribute)) {
            return;
        }

        return element.getAttribute(attribute);
    }

    module.exports = Clipboard;
});

},{"./clipboard-action":7,"good-listener":4,"tiny-emitter":6}]},{},[8])(8)
});;
/*!
 * headroom.js v0.9.3 - Give your page some headroom. Hide your header until you need it
 * Copyright (c) 2016 Nick Williams - http://wicky.nillia.ms/headroom.js
 * License: MIT
 */
!function (a, b) {
    "use strict";
    "function" == typeof define && define.amd ? define([], b) : "object" == typeof exports ? module.exports = b() : a.Headroom = b();
}(this, function () {
    "use strict";
    function a(a) { this.callback = a, this.ticking = !1; }
    function b(a) { return a && "undefined" != typeof window && (a === window || a.nodeType); }
    function c(a) {
        if (arguments.length <= 0)
            throw new Error("Missing arguments in extend function");
        var d, e, f = a || {};
        for (e = 1; e < arguments.length; e++) {
            var g = arguments[e] || {};
            for (d in g)
                "object" != typeof f[d] || b(f[d]) ? f[d] = f[d] || g[d] : f[d] = c(f[d], g[d]);
        }
        return f;
    }
    function d(a) { return a === Object(a) ? a : { down: a, up: a }; }
    function e(a, b) { b = c(b, e.options), this.lastKnownScrollY = 0, this.elem = a, this.tolerance = d(b.tolerance), this.classes = b.classes, this.offset = b.offset, this.scroller = b.scroller, this.initialised = !1, this.onPin = b.onPin, this.onUnpin = b.onUnpin, this.onTop = b.onTop, this.onNotTop = b.onNotTop, this.onBottom = b.onBottom, this.onNotBottom = b.onNotBottom; }
    var f = { bind: !!function () { }.bind, classList: "classList" in document.documentElement, rAF: !!(window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame) };
    return window.requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame, a.prototype = { constructor: a, update: function () { this.callback && this.callback(), this.ticking = !1; }, requestTick: function () { this.ticking || (requestAnimationFrame(this.rafCallback || (this.rafCallback = this.update.bind(this))), this.ticking = !0); }, handleEvent: function () { this.requestTick(); } }, e.prototype = { constructor: e, init: function () { return e.cutsTheMustard ? (this.debouncer = new a(this.update.bind(this)), this.elem.classList.add(this.classes.initial), setTimeout(this.attachEvent.bind(this), 100), this) : void 0; }, destroy: function () { var a = this.classes; this.initialised = !1, this.elem.classList.remove(a.unpinned, a.pinned, a.top, a.notTop, a.initial), this.scroller.removeEventListener("scroll", this.debouncer, !1); }, attachEvent: function () { this.initialised || (this.lastKnownScrollY = this.getScrollY(), this.initialised = !0, this.scroller.addEventListener("scroll", this.debouncer, !1), this.debouncer.handleEvent()); }, unpin: function () { var a = this.elem.classList, b = this.classes; !a.contains(b.pinned) && a.contains(b.unpinned) || (a.add(b.unpinned), a.remove(b.pinned), this.onUnpin && this.onUnpin.call(this)); }, pin: function () { var a = this.elem.classList, b = this.classes; a.contains(b.unpinned) && (a.remove(b.unpinned), a.add(b.pinned), this.onPin && this.onPin.call(this)); }, top: function () { var a = this.elem.classList, b = this.classes; a.contains(b.top) || (a.add(b.top), a.remove(b.notTop), this.onTop && this.onTop.call(this)); }, notTop: function () { var a = this.elem.classList, b = this.classes; a.contains(b.notTop) || (a.add(b.notTop), a.remove(b.top), this.onNotTop && this.onNotTop.call(this)); }, bottom: function () { var a = this.elem.classList, b = this.classes; a.contains(b.bottom) || (a.add(b.bottom), a.remove(b.notBottom), this.onBottom && this.onBottom.call(this)); }, notBottom: function () { var a = this.elem.classList, b = this.classes; a.contains(b.notBottom) || (a.add(b.notBottom), a.remove(b.bottom), this.onNotBottom && this.onNotBottom.call(this)); }, getScrollY: function () { return void 0 !== this.scroller.pageYOffset ? this.scroller.pageYOffset : void 0 !== this.scroller.scrollTop ? this.scroller.scrollTop : (document.documentElement || document.body.parentNode || document.body).scrollTop; }, getViewportHeight: function () { return window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight; }, getElementPhysicalHeight: function (a) { return Math.max(a.offsetHeight, a.clientHeight); }, getScrollerPhysicalHeight: function () { return this.scroller === window || this.scroller === document.body ? this.getViewportHeight() : this.getElementPhysicalHeight(this.scroller); }, getDocumentHeight: function () { var a = document.body, b = document.documentElement; return Math.max(a.scrollHeight, b.scrollHeight, a.offsetHeight, b.offsetHeight, a.clientHeight, b.clientHeight); }, getElementHeight: function (a) { return Math.max(a.scrollHeight, a.offsetHeight, a.clientHeight); }, getScrollerHeight: function () { return this.scroller === window || this.scroller === document.body ? this.getDocumentHeight() : this.getElementHeight(this.scroller); }, isOutOfBounds: function (a) { var b = 0 > a, c = a + this.getScrollerPhysicalHeight() > this.getScrollerHeight(); return b || c; }, toleranceExceeded: function (a, b) { return Math.abs(a - this.lastKnownScrollY) >= this.tolerance[b]; }, shouldUnpin: function (a, b) { var c = a > this.lastKnownScrollY, d = a >= this.offset; return c && d && b; }, shouldPin: function (a, b) { var c = a < this.lastKnownScrollY, d = a <= this.offset; return c && b || d; }, update: function () { var a = this.getScrollY(), b = a > this.lastKnownScrollY ? "down" : "up", c = this.toleranceExceeded(a, b); this.isOutOfBounds(a) || (a <= this.offset ? this.top() : this.notTop(), a + this.getViewportHeight() >= this.getScrollerHeight() ? this.bottom() : this.notBottom(), this.shouldUnpin(a, c) ? this.unpin() : this.shouldPin(a, c) && this.pin(), this.lastKnownScrollY = a); } }, e.options = { tolerance: { up: 0, down: 0 }, offset: 0, scroller: window, classes: { pinned: "headroom--pinned", unpinned: "headroom--unpinned", top: "headroom--top", notTop: "headroom--not-top", bottom: "headroom--bottom", notBottom: "headroom--not-bottom", initial: "headroom" } }, e.cutsTheMustard = "undefined" != typeof f && f.rAF && f.bind && f.classList, e;
});
//# sourceMappingURL=headroom.js.map 
//# sourceMappingURL=headroom.js.map 
//# sourceMappingURL=headroom.js.map 
//# sourceMappingURL=headroom.js.map 
//# sourceMappingURL=headroom.js.map 
//# sourceMappingURL=headroom.js.map 
//# sourceMappingURL=headroom.js.map 
//# sourceMappingURL=headroom.js.map;
/**
* jquery-match-height 0.7.0 by @liabru
* http://brm.io/jquery-match-height/
* License: MIT
*/
;
(function (factory) {
    'use strict';
    if (typeof define === 'function' && define.amd) {
        // AMD
        define(['jquery'], factory);
    }
    else if (typeof module !== 'undefined' && module.exports) {
        // CommonJS
        module.exports = factory(require('jquery'));
    }
    else {
        // Global
        factory(jQuery);
    }
})(function ($) {
    /*
    *  internal
    */
    var _previousResizeWidth = -1, _updateTimeout = -1;
    /*
    *  _parse
    *  value parse utility function
    */
    var _parse = function (value) {
        // parse value and convert NaN to 0
        return parseFloat(value) || 0;
    };
    /*
    *  _rows
    *  utility function returns array of jQuery selections representing each row
    *  (as displayed after float wrapping applied by browser)
    */
    var _rows = function (elements) {
        var tolerance = 1, $elements = $(elements), lastTop = null, rows = [];
        // group elements by their top position
        $elements.each(function () {
            var $that = $(this), top = $that.offset().top - _parse($that.css('margin-top')), lastRow = rows.length > 0 ? rows[rows.length - 1] : null;
            if (lastRow === null) {
                // first item on the row, so just push it
                rows.push($that);
            }
            else {
                // if the row top is the same, add to the row group
                if (Math.floor(Math.abs(lastTop - top)) <= tolerance) {
                    rows[rows.length - 1] = lastRow.add($that);
                }
                else {
                    // otherwise start a new row group
                    rows.push($that);
                }
            }
            // keep track of the last row top
            lastTop = top;
        });
        return rows;
    };
    /*
    *  _parseOptions
    *  handle plugin options
    */
    var _parseOptions = function (options) {
        var opts = {
            byRow: true,
            property: 'height',
            target: null,
            remove: false
        };
        if (typeof options === 'object') {
            return $.extend(opts, options);
        }
        if (typeof options === 'boolean') {
            opts.byRow = options;
        }
        else if (options === 'remove') {
            opts.remove = true;
        }
        return opts;
    };
    /*
    *  matchHeight
    *  plugin definition
    */
    var matchHeight = $.fn.matchHeight = function (options) {
        var opts = _parseOptions(options);
        // handle remove
        if (opts.remove) {
            var that = this;
            // remove fixed height from all selected elements
            this.css(opts.property, '');
            // remove selected elements from all groups
            $.each(matchHeight._groups, function (key, group) {
                group.elements = group.elements.not(that);
            });
            // TODO: cleanup empty groups
            return this;
        }
        if (this.length <= 1 && !opts.target) {
            return this;
        }
        // keep track of this group so we can re-apply later on load and resize events
        matchHeight._groups.push({
            elements: this,
            options: opts
        });
        // match each element's height to the tallest element in the selection
        matchHeight._apply(this, opts);
        return this;
    };
    /*
    *  plugin global options
    */
    matchHeight.version = '0.7.0';
    matchHeight._groups = [];
    matchHeight._throttle = 80;
    matchHeight._maintainScroll = false;
    matchHeight._beforeUpdate = null;
    matchHeight._afterUpdate = null;
    matchHeight._rows = _rows;
    matchHeight._parse = _parse;
    matchHeight._parseOptions = _parseOptions;
    /*
    *  matchHeight._apply
    *  apply matchHeight to given elements
    */
    matchHeight._apply = function (elements, options) {
        var opts = _parseOptions(options), $elements = $(elements), rows = [$elements];
        // take note of scroll position
        var scrollTop = $(window).scrollTop(), htmlHeight = $('html').outerHeight(true);
        // get hidden parents
        var $hiddenParents = $elements.parents().filter(':hidden');
        // cache the original inline style
        $hiddenParents.each(function () {
            var $that = $(this);
            $that.data('style-cache', $that.attr('style'));
        });
        // temporarily must force hidden parents visible
        $hiddenParents.css('display', 'block');
        // get rows if using byRow, otherwise assume one row
        if (opts.byRow && !opts.target) {
            // must first force an arbitrary equal height so floating elements break evenly
            $elements.each(function () {
                var $that = $(this), display = $that.css('display');
                // temporarily force a usable display value
                if (display !== 'inline-block' && display !== 'flex' && display !== 'inline-flex') {
                    display = 'block';
                }
                // cache the original inline style
                $that.data('style-cache', $that.attr('style'));
                $that.css({
                    'display': display,
                    'padding-top': '0',
                    'padding-bottom': '0',
                    'margin-top': '0',
                    'margin-bottom': '0',
                    'border-top-width': '0',
                    'border-bottom-width': '0',
                    'height': '100px',
                    'overflow': 'hidden'
                });
            });
            // get the array of rows (based on element top position)
            rows = _rows($elements);
            // revert original inline styles
            $elements.each(function () {
                var $that = $(this);
                $that.attr('style', $that.data('style-cache') || '');
            });
        }
        $.each(rows, function (key, row) {
            var $row = $(row), targetHeight = 0;
            if (!opts.target) {
                // skip apply to rows with only one item
                if (opts.byRow && $row.length <= 1) {
                    $row.css(opts.property, '');
                    return;
                }
                // iterate the row and find the max height
                $row.each(function () {
                    var $that = $(this), style = $that.attr('style'), display = $that.css('display');
                    // temporarily force a usable display value
                    if (display !== 'inline-block' && display !== 'flex' && display !== 'inline-flex') {
                        display = 'block';
                    }
                    // ensure we get the correct actual height (and not a previously set height value)
                    var css = { 'display': display };
                    css[opts.property] = '';
                    $that.css(css);
                    // find the max height (including padding, but not margin)
                    if ($that.outerHeight(false) > targetHeight) {
                        targetHeight = $that.outerHeight(false);
                    }
                    // revert styles
                    if (style) {
                        $that.attr('style', style);
                    }
                    else {
                        $that.css('display', '');
                    }
                });
            }
            else {
                // if target set, use the height of the target element
                targetHeight = opts.target.outerHeight(false);
            }
            // iterate the row and apply the height to all elements
            $row.each(function () {
                var $that = $(this), verticalPadding = 0;
                // don't apply to a target
                if (opts.target && $that.is(opts.target)) {
                    return;
                }
                // handle padding and border correctly (required when not using border-box)
                if ($that.css('box-sizing') !== 'border-box') {
                    verticalPadding += _parse($that.css('border-top-width')) + _parse($that.css('border-bottom-width'));
                    verticalPadding += _parse($that.css('padding-top')) + _parse($that.css('padding-bottom'));
                }
                // set the height (accounting for padding and border)
                $that.css(opts.property, (targetHeight - verticalPadding) + 'px');
            });
        });
        // revert hidden parents
        $hiddenParents.each(function () {
            var $that = $(this);
            $that.attr('style', $that.data('style-cache') || null);
        });
        // restore scroll position if enabled
        if (matchHeight._maintainScroll) {
            $(window).scrollTop((scrollTop / htmlHeight) * $('html').outerHeight(true));
        }
        return this;
    };
    /*
    *  matchHeight._applyDataApi
    *  applies matchHeight to all elements with a data-match-height attribute
    */
    matchHeight._applyDataApi = function () {
        var groups = {};
        // generate groups by their groupId set by elements using data-match-height
        $('[data-match-height], [data-mh]').each(function () {
            var $this = $(this), groupId = $this.attr('data-mh') || $this.attr('data-match-height');
            if (groupId in groups) {
                groups[groupId] = groups[groupId].add($this);
            }
            else {
                groups[groupId] = $this;
            }
        });
        // apply matchHeight to each group
        $.each(groups, function () {
            this.matchHeight(true);
        });
    };
    /*
    *  matchHeight._update
    *  updates matchHeight on all current groups with their correct options
    */
    var _update = function (event) {
        if (matchHeight._beforeUpdate) {
            matchHeight._beforeUpdate(event, matchHeight._groups);
        }
        $.each(matchHeight._groups, function () {
            matchHeight._apply(this.elements, this.options);
        });
        if (matchHeight._afterUpdate) {
            matchHeight._afterUpdate(event, matchHeight._groups);
        }
    };
    matchHeight._update = function (throttle, event) {
        // prevent update if fired from a resize event
        // where the viewport width hasn't actually changed
        // fixes an event looping bug in IE8
        if (event && event.type === 'resize') {
            var windowWidth = $(window).width();
            if (windowWidth === _previousResizeWidth) {
                return;
            }
            _previousResizeWidth = windowWidth;
        }
        // throttle updates
        if (!throttle) {
            _update(event);
        }
        else if (_updateTimeout === -1) {
            _updateTimeout = setTimeout(function () {
                _update(event);
                _updateTimeout = -1;
            }, matchHeight._throttle);
        }
    };
    /*
    *  bind events
    */
    // apply on DOM ready event
    $(matchHeight._applyDataApi);
    // update heights on load and resize events
    $(window).bind('load', function (event) {
        matchHeight._update(false, event);
    });
    // throttled update heights on resize events
    $(window).bind('resize orientationchange', function (event) {
        matchHeight._update(true, event);
    });
});
//# sourceMappingURL=jquery.matchHeight.js.map 
//# sourceMappingURL=jquery.matchHeight.js.map 
//# sourceMappingURL=jquery.matchHeight.js.map 
//# sourceMappingURL=jquery.matchHeight.js.map 
//# sourceMappingURL=jquery.matchHeight.js.map 
//# sourceMappingURL=jquery.matchHeight.js.map 
//# sourceMappingURL=jquery.matchHeight.js.map 
//# sourceMappingURL=jquery.matchHeight.js.map;
/* ===========================================================
 * jquery-simple-text-rotator.js v1
 * ===========================================================
 * Copyright 2013 Pete Rojwongsuriya.
 * http://www.thepetedesign.com
 *
 * A very simple and light weight jQuery plugin that
 * allows you to rotate multiple text without changing
 * the layout
 * https://github.com/peachananr/simple-text-rotator
 *
 * ========================================================== */
!function ($) {
    var defaults = {
        animation: "dissolve",
        separator: ",",
        speed: 2000
    };
    $.fx.step.textShadowBlur = function (fx) {
        $(fx.elem).prop('textShadowBlur', fx.now).css({ textShadow: '0 0 ' + Math.floor(fx.now) + 'px black' });
    };
    $.fn.textrotator = function (options) {
        var settings = $.extend({}, defaults, options);
        return this.each(function () {
            var el = $(this);
            var array = [];
            $.each(el.text().split(settings.separator), function (key, value) {
                array.push(value);
            });
            el.text(array[0]);
            // animation option
            var rotate = function () {
                switch (settings.animation) {
                    case 'dissolve':
                        el.animate({
                            textShadowBlur: 20,
                            opacity: 0
                        }, 500, function () {
                            index = $.inArray(el.text(), array);
                            if ((index + 1) == array.length)
                                index = -1;
                            el.text(array[index + 1]).animate({
                                textShadowBlur: 0,
                                opacity: 1
                            }, 500);
                        });
                        break;
                    case 'flip':
                        if (el.find(".back").length > 0) {
                            el.html(el.find(".back").html());
                        }
                        var initial = el.text();
                        var index = $.inArray(initial, array);
                        if ((index + 1) == array.length)
                            index = -1;
                        el.html("");
                        $("<span class='front'>" + initial + "</span>").appendTo(el);
                        $("<span class='back'>" + array[index + 1] + "</span>").appendTo(el);
                        el.wrapInner("<span class='rotating' />").find(".rotating").hide().addClass("flip").show().css({
                            "-webkit-transform": " rotateY(-180deg)",
                            "-moz-transform": " rotateY(-180deg)",
                            "-o-transform": " rotateY(-180deg)",
                            "transform": " rotateY(-180deg)"
                        });
                        break;
                    case 'flipUp':
                        if (el.find(".back").length > 0) {
                            el.html(el.find(".back").html());
                        }
                        var initial = el.text();
                        var index = $.inArray(initial, array);
                        if ((index + 1) == array.length)
                            index = -1;
                        el.html("");
                        $("<span class='front'>" + initial + "</span>").appendTo(el);
                        $("<span class='back'>" + array[index + 1] + "</span>").appendTo(el);
                        el.wrapInner("<span class='rotating' />").find(".rotating").hide().addClass("flip up").show().css({
                            "-webkit-transform": " rotateX(-180deg)",
                            "-moz-transform": " rotateX(-180deg)",
                            "-o-transform": " rotateX(-180deg)",
                            "transform": " rotateX(-180deg)"
                        });
                        break;
                    case 'flipCube':
                        if (el.find(".back").length > 0) {
                            el.html(el.find(".back").html());
                        }
                        var initial = el.text();
                        var index = $.inArray(initial, array);
                        if ((index + 1) == array.length)
                            index = -1;
                        el.html("");
                        $("<span class='front'>" + initial + "</span>").appendTo(el);
                        $("<span class='back'>" + array[index + 1] + "</span>").appendTo(el);
                        el.wrapInner("<span class='rotating' />").find(".rotating").hide().addClass("flip cube").show().css({
                            "-webkit-transform": " rotateY(180deg)",
                            "-moz-transform": " rotateY(180deg)",
                            "-o-transform": " rotateY(180deg)",
                            "transform": " rotateY(180deg)"
                        });
                        break;
                    case 'flipCubeUp':
                        if (el.find(".back").length > 0) {
                            el.html(el.find(".back").html());
                        }
                        var initial = el.text();
                        var index = $.inArray(initial, array);
                        if ((index + 1) == array.length)
                            index = -1;
                        el.html("");
                        $("<span class='front'>" + initial + "</span>").appendTo(el);
                        $("<span class='back'>" + array[index + 1] + "</span>").appendTo(el);
                        el.wrapInner("<span class='rotating' />").find(".rotating").hide().addClass("flip cube up").show().css({
                            "-webkit-transform": " rotateX(180deg)",
                            "-moz-transform": " rotateX(180deg)",
                            "-o-transform": " rotateX(180deg)",
                            "transform": " rotateX(180deg)"
                        });
                        break;
                    case 'spin':
                        if (el.find(".rotating").length > 0) {
                            el.html(el.find(".rotating").html());
                        }
                        index = $.inArray(el.text(), array);
                        if ((index + 1) == array.length)
                            index = -1;
                        el.wrapInner("<span class='rotating spin' />").find(".rotating").hide().text(array[index + 1]).show().css({
                            "-webkit-transform": " rotate(0) scale(1)",
                            "-moz-transform": "rotate(0) scale(1)",
                            "-o-transform": "rotate(0) scale(1)",
                            "transform": "rotate(0) scale(1)"
                        });
                        break;
                    case 'fade':
                        el.fadeOut(settings.speed, function () {
                            index = $.inArray(el.text(), array);
                            if ((index + 1) == array.length)
                                index = -1;
                            el.text(array[index + 1]).fadeIn(settings.speed);
                        });
                        break;
                }
            };
            setInterval(rotate, settings.speed);
        });
    };
}(window.jQuery);
//# sourceMappingURL=jquery.simple-text-rotator.js.map 
//# sourceMappingURL=jquery.simple-text-rotator.js.map 
//# sourceMappingURL=jquery.simple-text-rotator.js.map 
//# sourceMappingURL=jquery.simple-text-rotator.js.map 
//# sourceMappingURL=jquery.simple-text-rotator.js.map 
//# sourceMappingURL=jquery.simple-text-rotator.js.map 
//# sourceMappingURL=jquery.simple-text-rotator.js.map 
//# sourceMappingURL=jquery.simple-text-rotator.js.map;
/*!
 * JavaScript Cookie v2.1.3
 * https://github.com/js-cookie/js-cookie
 *
 * Copyright 2006, 2015 Klaus Hartl & Fagner Brack
 * Released under the MIT license
 */
;
(function (factory) {
    var registeredInModuleLoader = false;
    if (typeof define === 'function' && define.amd) {
        define(factory);
        registeredInModuleLoader = true;
    }
    if (typeof exports === 'object') {
        module.exports = factory();
        registeredInModuleLoader = true;
    }
    if (!registeredInModuleLoader) {
        var OldCookies = window.Cookies;
        var api = window.Cookies = factory();
        api.noConflict = function () {
            window.Cookies = OldCookies;
            return api;
        };
    }
}(function () {
    function extend() {
        var i = 0;
        var result = {};
        for (; i < arguments.length; i++) {
            var attributes = arguments[i];
            for (var key in attributes) {
                result[key] = attributes[key];
            }
        }
        return result;
    }
    function init(converter) {
        function api(key, value, attributes) {
            var result;
            if (typeof document === 'undefined') {
                return;
            }
            // Write
            if (arguments.length > 1) {
                attributes = extend({
                    path: '/'
                }, api.defaults, attributes);
                if (typeof attributes.expires === 'number') {
                    var expires = new Date();
                    expires.setMilliseconds(expires.getMilliseconds() + attributes.expires * 864e+5);
                    attributes.expires = expires;
                }
                // We're using "expires" because "max-age" is not supported by IE
                attributes.expires = attributes.expires ? attributes.expires.toUTCString() : '';
                try {
                    result = JSON.stringify(value);
                    if (/^[\{\[]/.test(result)) {
                        value = result;
                    }
                }
                catch (e) { }
                if (!converter.write) {
                    value = encodeURIComponent(String(value))
                        .replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g, decodeURIComponent);
                }
                else {
                    value = converter.write(value, key);
                }
                key = encodeURIComponent(String(key));
                key = key.replace(/%(23|24|26|2B|5E|60|7C)/g, decodeURIComponent);
                key = key.replace(/[\(\)]/g, escape);
                var stringifiedAttributes = '';
                for (var attributeName in attributes) {
                    if (!attributes[attributeName]) {
                        continue;
                    }
                    stringifiedAttributes += '; ' + attributeName;
                    if (attributes[attributeName] === true) {
                        continue;
                    }
                    stringifiedAttributes += '=' + attributes[attributeName];
                }
                return (document.cookie = key + '=' + value + stringifiedAttributes);
            }
            // Read
            if (!key) {
                result = {};
            }
            // To prevent the for loop in the first place assign an empty array
            // in case there are no cookies at all. Also prevents odd result when
            // calling "get()"
            var cookies = document.cookie ? document.cookie.split('; ') : [];
            var rdecode = /(%[0-9A-Z]{2})+/g;
            var i = 0;
            for (; i < cookies.length; i++) {
                var parts = cookies[i].split('=');
                var cookie = parts.slice(1).join('=');
                if (cookie.charAt(0) === '"') {
                    cookie = cookie.slice(1, -1);
                }
                try {
                    var name = parts[0].replace(rdecode, decodeURIComponent);
                    cookie = converter.read ?
                        converter.read(cookie, name) : converter(cookie, name) ||
                        cookie.replace(rdecode, decodeURIComponent);
                    if (this.json) {
                        try {
                            cookie = JSON.parse(cookie);
                        }
                        catch (e) { }
                    }
                    if (key === name) {
                        result = cookie;
                        break;
                    }
                    if (!key) {
                        result[name] = cookie;
                    }
                }
                catch (e) { }
            }
            return result;
        }
        api.set = api;
        api.get = function (key) {
            return api.call(api, key);
        };
        api.getJSON = function () {
            return api.apply({
                json: true
            }, [].slice.call(arguments));
        };
        api.defaults = {};
        api.remove = function (key, attributes) {
            api(key, '', extend(attributes, {
                expires: -1
            }));
        };
        api.withConverter = init;
        return api;
    }
    return init(function () { });
}));
//# sourceMappingURL=js.cookie.js.map 
//# sourceMappingURL=js.cookie.js.map 
//# sourceMappingURL=js.cookie.js.map 
//# sourceMappingURL=js.cookie.js.map 
//# sourceMappingURL=js.cookie.js.map;
(function (root, factory) {
    if (typeof exports == "object")
        module.exports = factory();
    else if (typeof define == "function" && define.amd)
        define(factory);
    else
        root.Spinner = factory();
})(this, function () {
    "use strict";
    var prefixes = ["webkit", "Moz", "ms", "O"], animations = {}, useCssAnimations;
    function createEl(tag, prop) {
        var el = document.createElement(tag || "div"), n;
        for (n in prop)
            el[n] = prop[n];
        return el;
    }
    function ins(parent) {
        for (var i = 1, n = arguments.length; i < n; i++)
            parent.appendChild(arguments[i]);
        return parent;
    }
    var sheet = function () {
        var el = createEl("style", {
            type: "text/css"
        });
        ins(document.getElementsByTagName("head")[0], el);
        return el.sheet || el.styleSheet;
    }();
    function addAnimation(alpha, trail, i, lines) {
        var name = ["opacity", trail, ~~(alpha * 100), i, lines].join("-"), start = .01 + i / lines * 100, z = Math.max(1 - (1 - alpha) / trail * (100 - start), alpha), prefix = useCssAnimations.substring(0, useCssAnimations.indexOf("Animation")).toLowerCase(), pre = prefix && "-" + prefix + "-" || "";
        if (!animations[name]) {
            sheet.insertRule("@" + pre + "keyframes " + name + "{" + "0%{opacity:" + z + "}" + start + "%{opacity:" + alpha + "}" + (start + .01) + "%{opacity:1}" + (start + trail) % 100 + "%{opacity:" + alpha + "}" + "100%{opacity:" + z + "}" + "}", sheet.cssRules.length);
            animations[name] = 1;
        }
        return name;
    }
    function vendor(el, prop) {
        var s = el.style, pp, i;
        prop = prop.charAt(0).toUpperCase() + prop.slice(1);
        for (i = 0; i < prefixes.length; i++) {
            pp = prefixes[i] + prop;
            if (s[pp] !== undefined)
                return pp;
        }
        if (s[prop] !== undefined)
            return prop;
    }
    function css(el, prop) {
        for (var n in prop)
            el.style[vendor(el, n) || n] = prop[n];
        return el;
    }
    function merge(obj) {
        for (var i = 1; i < arguments.length; i++) {
            var def = arguments[i];
            for (var n in def)
                if (obj[n] === undefined)
                    obj[n] = def[n];
        }
        return obj;
    }
    function pos(el) {
        var o = {
            x: el.offsetLeft,
            y: el.offsetTop
        };
        while (el = el.offsetParent)
            o.x += el.offsetLeft, o.y += el.offsetTop;
        return o;
    }
    function getColor(color, idx) {
        return typeof color == "string" ? color : color[idx % color.length];
    }
    var defaults = {
        lines: 12,
        length: 7,
        width: 5,
        radius: 10,
        rotate: 0,
        corners: 1,
        color: "#000",
        direction: 1,
        speed: 1,
        trail: 100,
        opacity: 1 / 4,
        fps: 20,
        zIndex: 2e9,
        className: "spinner",
        top: "50%",
        left: "50%",
        position: "absolute"
    };
    function Spinner(o) {
        this.opts = merge(o || {}, Spinner.defaults, defaults);
    }
    Spinner.defaults = {};
    merge(Spinner.prototype, {
        spin: function (target) {
            this.stop();
            var self = this, o = self.opts, el = self.el = css(createEl(0, {
                className: o.className
            }), {
                position: o.position,
                width: 0,
                zIndex: o.zIndex
            }), mid = o.radius + o.length + o.width;
            css(el, {
                left: o.left,
                top: o.top
            });
            if (target) {
                target.insertBefore(el, target.firstChild || null);
            }
            el.setAttribute("role", "progressbar");
            self.lines(el, self.opts);
            if (!useCssAnimations) {
                var i = 0, start = (o.lines - 1) * (1 - o.direction) / 2, alpha, fps = o.fps, f = fps / o.speed, ostep = (1 - o.opacity) / (f * o.trail / 100), astep = f / o.lines;
                (function anim() {
                    i++;
                    for (var j = 0; j < o.lines; j++) {
                        alpha = Math.max(1 - (i + (o.lines - j) * astep) % f * ostep, o.opacity);
                        self.opacity(el, j * o.direction + start, alpha, o);
                    }
                    self.timeout = self.el && setTimeout(anim, ~~(1e3 / fps));
                })();
            }
            return self;
        },
        stop: function () {
            var el = this.el;
            if (el) {
                clearTimeout(this.timeout);
                if (el.parentNode)
                    el.parentNode.removeChild(el);
                this.el = undefined;
            }
            return this;
        },
        lines: function (el, o) {
            var i = 0, start = (o.lines - 1) * (1 - o.direction) / 2, seg;
            function fill(color, shadow) {
                return css(createEl(), {
                    position: "absolute",
                    width: o.length + o.width + "px",
                    height: o.width + "px",
                    background: color,
                    boxShadow: shadow,
                    transformOrigin: "left",
                    transform: "rotate(" + ~~(360 / o.lines * i + o.rotate) + "deg) translate(" + o.radius + "px" + ",0)",
                    borderRadius: (o.corners * o.width >> 1) + "px"
                });
            }
            for (; i < o.lines; i++) {
                seg = css(createEl(), {
                    position: "absolute",
                    top: 1 + ~(o.width / 2) + "px",
                    transform: o.hwaccel ? "translate3d(0,0,0)" : "",
                    opacity: o.opacity,
                    animation: useCssAnimations && addAnimation(o.opacity, o.trail, start + i * o.direction, o.lines) + " " + 1 / o.speed + "s linear infinite"
                });
                if (o.shadow)
                    ins(seg, css(fill("#000", "0 0 4px " + "#000"), {
                        top: 2 + "px"
                    }));
                ins(el, ins(seg, fill(getColor(o.color, i), "0 0 1px rgba(0,0,0,.1)")));
            }
            return el;
        },
        opacity: function (el, i, val) {
            if (i < el.childNodes.length)
                el.childNodes[i].style.opacity = val;
        }
    });
    function initVML() {
        function vml(tag, attr) {
            return createEl("<" + tag + ' xmlns="urn:schemas-microsoft.com:vml" class="spin-vml">', attr);
        }
        sheet.addRule(".spin-vml", "behavior:url(#default#VML)");
        Spinner.prototype.lines = function (el, o) {
            var r = o.length + o.width, s = 2 * r;
            function grp() {
                return css(vml("group", {
                    coordsize: s + " " + s,
                    coordorigin: -r + " " + -r
                }), {
                    width: s,
                    height: s
                });
            }
            var margin = -(o.width + o.length) * 2 + "px", g = css(grp(), {
                position: "absolute",
                top: margin,
                left: margin
            }), i;
            function seg(i, dx, filter) {
                ins(g, ins(css(grp(), {
                    rotation: 360 / o.lines * i + "deg",
                    left: ~~dx
                }), ins(css(vml("roundrect", {
                    arcsize: o.corners
                }), {
                    width: r,
                    height: o.width,
                    left: o.radius,
                    top: -o.width >> 1,
                    filter: filter
                }), vml("fill", {
                    color: getColor(o.color, i),
                    opacity: o.opacity
                }), vml("stroke", {
                    opacity: 0
                }))));
            }
            if (o.shadow)
                for (i = 1; i <= o.lines; i++)
                    seg(i, -2, "progid:DXImageTransform.Microsoft.Blur(pixelradius=2,makeshadow=1,shadowopacity=.3)");
            for (i = 1; i <= o.lines; i++)
                seg(i);
            return ins(el, g);
        };
        Spinner.prototype.opacity = function (el, i, val, o) {
            var c = el.firstChild;
            o = o.shadow && o.lines || 0;
            if (c && i + o < c.childNodes.length) {
                c = c.childNodes[i + o];
                c = c && c.firstChild;
                c = c && c.firstChild;
                if (c)
                    c.opacity = val;
            }
        };
    }
    var probe = css(createEl("group"), {
        behavior: "url(#default#VML)"
    });
    if (!vendor(probe, "transform") && probe.adj)
        initVML();
    else
        useCssAnimations = vendor(probe, "animation");
    return Spinner;
});
(function (root, factory) {
    if (typeof exports === "object") {
        module.exports = factory();
    }
    else if (typeof define === "function" && define.amd) {
        define(["./spin"], factory);
    }
    else {
        root.Ladda = factory(root.Spinner);
    }
})(this, function (Spinner) {
    "use strict";
    var ALL_INSTANCES = [];
    function create(button) {
        if (typeof button === "undefined") {
            console.warn("Ladda button target must be defined.");
            return;
        }
        if (!button.querySelector(".ladda-label")) {
            button.innerHTML = '<span class="ladda-label">' + button.innerHTML + "</span>";
        }
        var spinner = createSpinner(button);
        var spinnerWrapper = document.createElement("span");
        spinnerWrapper.className = "ladda-spinner";
        button.appendChild(spinnerWrapper);
        var timer;
        var instance = {
            start: function () {
                button.setAttribute("disabled", "");
                button.setAttribute("data-loading", "");
                clearTimeout(timer);
                spinner.spin(spinnerWrapper);
                this.setProgress(0);
                return this;
            },
            startAfter: function (delay) {
                clearTimeout(timer);
                timer = setTimeout(function () {
                    instance.start();
                }, delay);
                return this;
            },
            stop: function () {
                button.removeAttribute("disabled");
                button.removeAttribute("data-loading");
                clearTimeout(timer);
                timer = setTimeout(function () {
                    spinner.stop();
                }, 1e3);
                return this;
            },
            remove: function () {
                if (this.isLoading()) {
                    this.stop();
                }
                spinnerWrapper.parentNode.removeChild(spinnerWrapper);
                return this;
            },
            toggle: function () {
                if (this.isLoading()) {
                    this.stop();
                }
                else {
                    this.start();
                }
                return this;
            },
            setProgress: function (progress) {
                progress = Math.max(Math.min(progress, 1), 0);
                var progressElement = button.querySelector(".ladda-progress");
                if (progress === 0 && progressElement && progressElement.parentNode) {
                    progressElement.parentNode.removeChild(progressElement);
                }
                else {
                    if (!progressElement) {
                        progressElement = document.createElement("div");
                        progressElement.className = "ladda-progress";
                        button.appendChild(progressElement);
                    }
                    progressElement.style.width = (progress || 0) * button.offsetWidth + "px";
                }
            },
            enable: function () {
                this.stop();
                return this;
            },
            disable: function () {
                this.stop();
                button.setAttribute("disabled", "");
                return this;
            },
            isLoading: function () {
                return button.hasAttribute("data-loading");
            },
            getTarget: function () {
                return button;
            }
        };
        ALL_INSTANCES.push(instance);
        return instance;
    }
    function bind(target, options) {
        options = options || {};
        var targets = [];
        if (typeof target === "string") {
            targets = toArray(document.querySelectorAll(target));
        }
        else if (typeof target === "object" && typeof target.nodeName === "string") {
            targets = [target];
        }
        for (var i = 0, len = targets.length; i < len; i++) {
            (function () {
                var element = targets[i];
                if (typeof element.addEventListener === "function") {
                    var instance = create(element);
                    var timeout = -1;
                    element.addEventListener("click", function () {
                        instance.startAfter(1);
                        if (typeof options.timeout === "number") {
                            clearTimeout(timeout);
                            timeout = setTimeout(instance.stop, options.timeout);
                        }
                        if (typeof options.callback === "function") {
                            options.callback.apply(null, [instance]);
                        }
                    }, false);
                }
            })();
        }
    }
    function stopAll() {
        for (var i = 0, len = ALL_INSTANCES.length; i < len; i++) {
            ALL_INSTANCES[i].stop();
        }
    }
    function createSpinner(button) {
        var height = button.offsetHeight, spinnerColor;
        if (height > 32) {
            height *= .8;
        }
        if (button.hasAttribute("data-spinner-size")) {
            height = parseInt(button.getAttribute("data-spinner-size"), 10);
        }
        if (button.hasAttribute("data-spinner-color")) {
            spinnerColor = button.getAttribute("data-spinner-color");
        }
        var lines = 12, radius = height * .2, length = radius * .6, width = radius < 7 ? 2 : 3;
        return new Spinner({
            color: spinnerColor || "#fff",
            lines: lines,
            radius: radius,
            length: length,
            width: width,
            zIndex: "auto",
            top: "50%",
            left: "50%",
            className: ""
        });
    }
    function toArray(nodes) {
        var a = [];
        for (var i = 0; i < nodes.length; i++) {
            a.push(nodes[i]);
        }
        return a;
    }
    return {
        bind: bind,
        create: create,
        stopAll: stopAll
    };
});
//# sourceMappingURL=ladda.js.map 
//# sourceMappingURL=ladda.js.map 
//# sourceMappingURL=ladda.js.map 
//# sourceMappingURL=ladda.js.map 
//# sourceMappingURL=ladda.js.map 
//# sourceMappingURL=ladda.js.map 
//# sourceMappingURL=ladda.js.map 
//# sourceMappingURL=ladda.js.map;
/***************************************************************************************************
LoadingOverlay - A flexible loading overlay jQuery plugin
    Author          : Gaspare Sganga
    Version         : 1.4.0
    License         : MIT
    Documentation   : http://gasparesganga.com/labs/jquery-loading-overlay/
****************************************************************************************************/
(function ($, undefined) {
    var _defaults = {
        color: "rgba(255, 255, 255, 0.8)",
        custom: $('<div class="loader-container arc-rotate2 animated"><div class="loader black"><div class="arc"></div></div></div>'),
        fade: true,
        fontawesome: "",
        image: "",
        imagePosition: "center center",
        maxSize: "100px",
        minSize: "20px",
        resizeInterval: 0,
        size: "50%",
        zIndex: undefined
    };
    $.LoadingOverlaySetup = function (settings) {
        $.extend(true, _defaults, settings);
    };
    $.LoadingOverlay = function (action, options) {
        switch (action.toLowerCase()) {
            case "show":
                var settings = $.extend(true, {}, _defaults, options);
                _Show("body", settings);
                break;
            case "hide":
                _Hide("body", options);
                break;
        }
    };
    $.fn.LoadingOverlay = function (action, options) {
        switch (action.toLowerCase()) {
            case "show":
                var settings = $.extend(true, {}, _defaults, options);
                return this.each(function () {
                    _Show(this, settings);
                });
            case "hide":
                return this.each(function () {
                    _Hide(this, options);
                });
        }
    };
    function _Show(container, settings) {
        container = $(container);
        var fixed = container.is("body");
        var count = container.data("LoadingOverlayCount");
        if (count === undefined)
            count = 0;
        if (count == 0) {
            var overlay = $("<div>", {
                class: "loadingoverlay",
                css: {
                    "background-color": settings.color,
                    "display": "flex",
                    "flex-direction": "column",
                    "align-items": "center",
                    "justify-content": "center"
                }
            });
            if (settings.zIndex !== undefined)
                overlay.css("z-index", settings.zIndex);
            if (settings.image)
                overlay.css({
                    "background-image": "url(" + settings.image + ")",
                    "background-position": settings.imagePosition,
                    "background-repeat": "no-repeat"
                });
            if (settings.fontawesome)
                $("<div>", {
                    class: "loadingoverlay_fontawesome " + settings.fontawesome
                }).appendTo(overlay);
            if (settings.custom)
                $(settings.custom).appendTo(overlay);
            if (fixed) {
                overlay.css({
                    "position": "fixed",
                    "top": 0,
                    "left": 0,
                    "width": "100%",
                    "height": "100%"
                });
            }
            else {
                overlay.css({
                    "position": "absolute",
                    "top": 0,
                    "left": 0
                });
                if (container.css("position") == "static") {
                    overlay.css({
                        "top": container.position().top + parseInt(container.css("margin-top")) + parseInt(container.css("border-top-width")),
                        "left": container.position().left + parseInt(container.css("margin-left")) + parseInt(container.css("border-left-width"))
                    });
                }
            }
            _Resize(container, overlay, settings, fixed);
            if (settings.resizeInterval > 0) {
                var resizeIntervalId = setInterval(function () {
                    _Resize(container, overlay, settings, fixed);
                }, settings.resizeInterval);
                container.data("LoadingOverlayResizeIntervalId", resizeIntervalId);
            }
            if (!settings.fade) {
                settings.fade = [0, 0];
            }
            else if (settings.fade === true) {
                settings.fade = [400, 200];
            }
            else if (typeof settings.fade == "string" || typeof settings.fade == "number") {
                settings.fade = [settings.fade, settings.fade];
            }
            container.data("LoadingOverlayFadeOutDuration", settings.fade[1]);
            overlay.hide().appendTo(container).fadeIn(settings.fade[0]);
        }
        count++;
        container.data("LoadingOverlayCount", count);
    }
    function _Hide(container, force) {
        container = $(container);
        var count = container.data("LoadingOverlayCount");
        if (count === undefined)
            return;
        count--;
        if (force || count <= 0) {
            var resizeIntervalId = container.data("LoadingOverlayResizeIntervalId");
            if (resizeIntervalId)
                clearInterval(resizeIntervalId);
            container.children(".loadingoverlay").fadeOut(container.data("LoadingOverlayFadeOutDuration"), function () {
                $(this).remove();
            });
            container.removeData(["LoadingOverlayCount", "LoadingOverlayFadeOutDuration", "LoadingOverlayResizeIntervalId"]);
        }
        else {
            container.data("LoadingOverlayCount", count);
        }
    }
    function _Resize(container, overlay, settings, fixed) {
        if (!fixed)
            overlay.css({
                "width": container.innerWidth(),
                "height": container.innerHeight()
            });
        var size = "auto";
        if (settings.size && settings.size != "auto") {
            var c = fixed ? $(window) : container;
            size = Math.min(c.innerWidth(), c.innerHeight()) * parseFloat(settings.size) / 100;
            if (settings.maxSize && size > parseInt(settings.maxSize))
                size = parseInt(settings.maxSize) + "px";
            if (settings.minSize && size < parseInt(settings.minSize))
                size = parseInt(settings.minSize) + "px";
        }
        overlay.css("background-size", size);
        overlay.children(".loadingoverlay_fontawesome").css("font-size", size);
    }
}(jQuery));
//# sourceMappingURL=loadingoverlay.js.map 
//# sourceMappingURL=loadingoverlay.js.map 
//# sourceMappingURL=loadingoverlay.js.map 
//# sourceMappingURL=loadingoverlay.js.map 
//# sourceMappingURL=loadingoverlay.js.map 
//# sourceMappingURL=loadingoverlay.js.map 
//# sourceMappingURL=loadingoverlay.js.map;
// THIS FILE IS GENERATED - DO NOT EDIT!
/*!mobile-detect v1.3.3 2016-07-31*/
/*global module:false, define:false*/
/*!@license Copyright 2013, Heinrich Goebl, License: MIT, see https://github.com/hgoebl/mobile-detect.js*/
(function (define, undefined) {
    define(function () {
        'use strict';
        var impl = {};
        impl.mobileDetectRules = {
            "phones": {
                "iPhone": "\\biPhone\\b|\\biPod\\b",
                "BlackBerry": "BlackBerry|\\bBB10\\b|rim[0-9]+",
                "HTC": "HTC|HTC.*(Sensation|Evo|Vision|Explorer|6800|8100|8900|A7272|S510e|C110e|Legend|Desire|T8282)|APX515CKT|Qtek9090|APA9292KT|HD_mini|Sensation.*Z710e|PG86100|Z715e|Desire.*(A8181|HD)|ADR6200|ADR6400L|ADR6425|001HT|Inspire 4G|Android.*\\bEVO\\b|T-Mobile G1|Z520m",
                "Nexus": "Nexus One|Nexus S|Galaxy.*Nexus|Android.*Nexus.*Mobile|Nexus 4|Nexus 5|Nexus 6",
                "Dell": "Dell.*Streak|Dell.*Aero|Dell.*Venue|DELL.*Venue Pro|Dell Flash|Dell Smoke|Dell Mini 3iX|XCD28|XCD35|\\b001DL\\b|\\b101DL\\b|\\bGS01\\b",
                "Motorola": "Motorola|DROIDX|DROID BIONIC|\\bDroid\\b.*Build|Android.*Xoom|HRI39|MOT-|A1260|A1680|A555|A853|A855|A953|A955|A956|Motorola.*ELECTRIFY|Motorola.*i1|i867|i940|MB200|MB300|MB501|MB502|MB508|MB511|MB520|MB525|MB526|MB611|MB612|MB632|MB810|MB855|MB860|MB861|MB865|MB870|ME501|ME502|ME511|ME525|ME600|ME632|ME722|ME811|ME860|ME863|ME865|MT620|MT710|MT716|MT720|MT810|MT870|MT917|Motorola.*TITANIUM|WX435|WX445|XT300|XT301|XT311|XT316|XT317|XT319|XT320|XT390|XT502|XT530|XT531|XT532|XT535|XT603|XT610|XT611|XT615|XT681|XT701|XT702|XT711|XT720|XT800|XT806|XT860|XT862|XT875|XT882|XT883|XT894|XT901|XT907|XT909|XT910|XT912|XT928|XT926|XT915|XT919|XT925|XT1021|\\bMoto E\\b",
                "Samsung": "Samsung|SM-G9250|GT-19300|SGH-I337|BGT-S5230|GT-B2100|GT-B2700|GT-B2710|GT-B3210|GT-B3310|GT-B3410|GT-B3730|GT-B3740|GT-B5510|GT-B5512|GT-B5722|GT-B6520|GT-B7300|GT-B7320|GT-B7330|GT-B7350|GT-B7510|GT-B7722|GT-B7800|GT-C3010|GT-C3011|GT-C3060|GT-C3200|GT-C3212|GT-C3212I|GT-C3262|GT-C3222|GT-C3300|GT-C3300K|GT-C3303|GT-C3303K|GT-C3310|GT-C3322|GT-C3330|GT-C3350|GT-C3500|GT-C3510|GT-C3530|GT-C3630|GT-C3780|GT-C5010|GT-C5212|GT-C6620|GT-C6625|GT-C6712|GT-E1050|GT-E1070|GT-E1075|GT-E1080|GT-E1081|GT-E1085|GT-E1087|GT-E1100|GT-E1107|GT-E1110|GT-E1120|GT-E1125|GT-E1130|GT-E1160|GT-E1170|GT-E1175|GT-E1180|GT-E1182|GT-E1200|GT-E1210|GT-E1225|GT-E1230|GT-E1390|GT-E2100|GT-E2120|GT-E2121|GT-E2152|GT-E2220|GT-E2222|GT-E2230|GT-E2232|GT-E2250|GT-E2370|GT-E2550|GT-E2652|GT-E3210|GT-E3213|GT-I5500|GT-I5503|GT-I5700|GT-I5800|GT-I5801|GT-I6410|GT-I6420|GT-I7110|GT-I7410|GT-I7500|GT-I8000|GT-I8150|GT-I8160|GT-I8190|GT-I8320|GT-I8330|GT-I8350|GT-I8530|GT-I8700|GT-I8703|GT-I8910|GT-I9000|GT-I9001|GT-I9003|GT-I9010|GT-I9020|GT-I9023|GT-I9070|GT-I9082|GT-I9100|GT-I9103|GT-I9220|GT-I9250|GT-I9300|GT-I9305|GT-I9500|GT-I9505|GT-M3510|GT-M5650|GT-M7500|GT-M7600|GT-M7603|GT-M8800|GT-M8910|GT-N7000|GT-S3110|GT-S3310|GT-S3350|GT-S3353|GT-S3370|GT-S3650|GT-S3653|GT-S3770|GT-S3850|GT-S5210|GT-S5220|GT-S5229|GT-S5230|GT-S5233|GT-S5250|GT-S5253|GT-S5260|GT-S5263|GT-S5270|GT-S5300|GT-S5330|GT-S5350|GT-S5360|GT-S5363|GT-S5369|GT-S5380|GT-S5380D|GT-S5560|GT-S5570|GT-S5600|GT-S5603|GT-S5610|GT-S5620|GT-S5660|GT-S5670|GT-S5690|GT-S5750|GT-S5780|GT-S5830|GT-S5839|GT-S6102|GT-S6500|GT-S7070|GT-S7200|GT-S7220|GT-S7230|GT-S7233|GT-S7250|GT-S7500|GT-S7530|GT-S7550|GT-S7562|GT-S7710|GT-S8000|GT-S8003|GT-S8500|GT-S8530|GT-S8600|SCH-A310|SCH-A530|SCH-A570|SCH-A610|SCH-A630|SCH-A650|SCH-A790|SCH-A795|SCH-A850|SCH-A870|SCH-A890|SCH-A930|SCH-A950|SCH-A970|SCH-A990|SCH-I100|SCH-I110|SCH-I400|SCH-I405|SCH-I500|SCH-I510|SCH-I515|SCH-I600|SCH-I730|SCH-I760|SCH-I770|SCH-I830|SCH-I910|SCH-I920|SCH-I959|SCH-LC11|SCH-N150|SCH-N300|SCH-R100|SCH-R300|SCH-R351|SCH-R400|SCH-R410|SCH-T300|SCH-U310|SCH-U320|SCH-U350|SCH-U360|SCH-U365|SCH-U370|SCH-U380|SCH-U410|SCH-U430|SCH-U450|SCH-U460|SCH-U470|SCH-U490|SCH-U540|SCH-U550|SCH-U620|SCH-U640|SCH-U650|SCH-U660|SCH-U700|SCH-U740|SCH-U750|SCH-U810|SCH-U820|SCH-U900|SCH-U940|SCH-U960|SCS-26UC|SGH-A107|SGH-A117|SGH-A127|SGH-A137|SGH-A157|SGH-A167|SGH-A177|SGH-A187|SGH-A197|SGH-A227|SGH-A237|SGH-A257|SGH-A437|SGH-A517|SGH-A597|SGH-A637|SGH-A657|SGH-A667|SGH-A687|SGH-A697|SGH-A707|SGH-A717|SGH-A727|SGH-A737|SGH-A747|SGH-A767|SGH-A777|SGH-A797|SGH-A817|SGH-A827|SGH-A837|SGH-A847|SGH-A867|SGH-A877|SGH-A887|SGH-A897|SGH-A927|SGH-B100|SGH-B130|SGH-B200|SGH-B220|SGH-C100|SGH-C110|SGH-C120|SGH-C130|SGH-C140|SGH-C160|SGH-C170|SGH-C180|SGH-C200|SGH-C207|SGH-C210|SGH-C225|SGH-C230|SGH-C417|SGH-C450|SGH-D307|SGH-D347|SGH-D357|SGH-D407|SGH-D415|SGH-D780|SGH-D807|SGH-D980|SGH-E105|SGH-E200|SGH-E315|SGH-E316|SGH-E317|SGH-E335|SGH-E590|SGH-E635|SGH-E715|SGH-E890|SGH-F300|SGH-F480|SGH-I200|SGH-I300|SGH-I320|SGH-I550|SGH-I577|SGH-I600|SGH-I607|SGH-I617|SGH-I627|SGH-I637|SGH-I677|SGH-I700|SGH-I717|SGH-I727|SGH-i747M|SGH-I777|SGH-I780|SGH-I827|SGH-I847|SGH-I857|SGH-I896|SGH-I897|SGH-I900|SGH-I907|SGH-I917|SGH-I927|SGH-I937|SGH-I997|SGH-J150|SGH-J200|SGH-L170|SGH-L700|SGH-M110|SGH-M150|SGH-M200|SGH-N105|SGH-N500|SGH-N600|SGH-N620|SGH-N625|SGH-N700|SGH-N710|SGH-P107|SGH-P207|SGH-P300|SGH-P310|SGH-P520|SGH-P735|SGH-P777|SGH-Q105|SGH-R210|SGH-R220|SGH-R225|SGH-S105|SGH-S307|SGH-T109|SGH-T119|SGH-T139|SGH-T209|SGH-T219|SGH-T229|SGH-T239|SGH-T249|SGH-T259|SGH-T309|SGH-T319|SGH-T329|SGH-T339|SGH-T349|SGH-T359|SGH-T369|SGH-T379|SGH-T409|SGH-T429|SGH-T439|SGH-T459|SGH-T469|SGH-T479|SGH-T499|SGH-T509|SGH-T519|SGH-T539|SGH-T559|SGH-T589|SGH-T609|SGH-T619|SGH-T629|SGH-T639|SGH-T659|SGH-T669|SGH-T679|SGH-T709|SGH-T719|SGH-T729|SGH-T739|SGH-T746|SGH-T749|SGH-T759|SGH-T769|SGH-T809|SGH-T819|SGH-T839|SGH-T919|SGH-T929|SGH-T939|SGH-T959|SGH-T989|SGH-U100|SGH-U200|SGH-U800|SGH-V205|SGH-V206|SGH-X100|SGH-X105|SGH-X120|SGH-X140|SGH-X426|SGH-X427|SGH-X475|SGH-X495|SGH-X497|SGH-X507|SGH-X600|SGH-X610|SGH-X620|SGH-X630|SGH-X700|SGH-X820|SGH-X890|SGH-Z130|SGH-Z150|SGH-Z170|SGH-ZX10|SGH-ZX20|SHW-M110|SPH-A120|SPH-A400|SPH-A420|SPH-A460|SPH-A500|SPH-A560|SPH-A600|SPH-A620|SPH-A660|SPH-A700|SPH-A740|SPH-A760|SPH-A790|SPH-A800|SPH-A820|SPH-A840|SPH-A880|SPH-A900|SPH-A940|SPH-A960|SPH-D600|SPH-D700|SPH-D710|SPH-D720|SPH-I300|SPH-I325|SPH-I330|SPH-I350|SPH-I500|SPH-I600|SPH-I700|SPH-L700|SPH-M100|SPH-M220|SPH-M240|SPH-M300|SPH-M305|SPH-M320|SPH-M330|SPH-M350|SPH-M360|SPH-M370|SPH-M380|SPH-M510|SPH-M540|SPH-M550|SPH-M560|SPH-M570|SPH-M580|SPH-M610|SPH-M620|SPH-M630|SPH-M800|SPH-M810|SPH-M850|SPH-M900|SPH-M910|SPH-M920|SPH-M930|SPH-N100|SPH-N200|SPH-N240|SPH-N300|SPH-N400|SPH-Z400|SWC-E100|SCH-i909|GT-N7100|GT-N7105|SCH-I535|SM-N900A|SGH-I317|SGH-T999L|GT-S5360B|GT-I8262|GT-S6802|GT-S6312|GT-S6310|GT-S5312|GT-S5310|GT-I9105|GT-I8510|GT-S6790N|SM-G7105|SM-N9005|GT-S5301|GT-I9295|GT-I9195|SM-C101|GT-S7392|GT-S7560|GT-B7610|GT-I5510|GT-S7582|GT-S7530E|GT-I8750|SM-G9006V|SM-G9008V|SM-G9009D|SM-G900A|SM-G900D|SM-G900F|SM-G900H|SM-G900I|SM-G900J|SM-G900K|SM-G900L|SM-G900M|SM-G900P|SM-G900R4|SM-G900S|SM-G900T|SM-G900V|SM-G900W8|SHV-E160K|SCH-P709|SCH-P729|SM-T2558|GT-I9205|SM-G9350|SM-J120F",
                "LG": "\\bLG\\b;|LG[- ]?(C800|C900|E400|E610|E900|E-900|F160|F180K|F180L|F180S|730|855|L160|LS740|LS840|LS970|LU6200|MS690|MS695|MS770|MS840|MS870|MS910|P500|P700|P705|VM696|AS680|AS695|AX840|C729|E970|GS505|272|C395|E739BK|E960|L55C|L75C|LS696|LS860|P769BK|P350|P500|P509|P870|UN272|US730|VS840|VS950|LN272|LN510|LS670|LS855|LW690|MN270|MN510|P509|P769|P930|UN200|UN270|UN510|UN610|US670|US740|US760|UX265|UX840|VN271|VN530|VS660|VS700|VS740|VS750|VS910|VS920|VS930|VX9200|VX11000|AX840A|LW770|P506|P925|P999|E612|D955|D802|MS323)",
                "Sony": "SonyST|SonyLT|SonyEricsson|SonyEricssonLT15iv|LT18i|E10i|LT28h|LT26w|SonyEricssonMT27i|C5303|C6902|C6903|C6906|C6943|D2533",
                "Asus": "Asus.*Galaxy|PadFone.*Mobile",
                "NokiaLumia": "Lumia [0-9]{3,4}",
                "Micromax": "Micromax.*\\b(A210|A92|A88|A72|A111|A110Q|A115|A116|A110|A90S|A26|A51|A35|A54|A25|A27|A89|A68|A65|A57|A90)\\b",
                "Palm": "PalmSource|Palm",
                "Vertu": "Vertu|Vertu.*Ltd|Vertu.*Ascent|Vertu.*Ayxta|Vertu.*Constellation(F|Quest)?|Vertu.*Monika|Vertu.*Signature",
                "Pantech": "PANTECH|IM-A850S|IM-A840S|IM-A830L|IM-A830K|IM-A830S|IM-A820L|IM-A810K|IM-A810S|IM-A800S|IM-T100K|IM-A725L|IM-A780L|IM-A775C|IM-A770K|IM-A760S|IM-A750K|IM-A740S|IM-A730S|IM-A720L|IM-A710K|IM-A690L|IM-A690S|IM-A650S|IM-A630K|IM-A600S|VEGA PTL21|PT003|P8010|ADR910L|P6030|P6020|P9070|P4100|P9060|P5000|CDM8992|TXT8045|ADR8995|IS11PT|P2030|P6010|P8000|PT002|IS06|CDM8999|P9050|PT001|TXT8040|P2020|P9020|P2000|P7040|P7000|C790",
                "Fly": "IQ230|IQ444|IQ450|IQ440|IQ442|IQ441|IQ245|IQ256|IQ236|IQ255|IQ235|IQ245|IQ275|IQ240|IQ285|IQ280|IQ270|IQ260|IQ250",
                "Wiko": "KITE 4G|HIGHWAY|GETAWAY|STAIRWAY|DARKSIDE|DARKFULL|DARKNIGHT|DARKMOON|SLIDE|WAX 4G|RAINBOW|BLOOM|SUNSET|GOA(?!nna)|LENNY|BARRY|IGGY|OZZY|CINK FIVE|CINK PEAX|CINK PEAX 2|CINK SLIM|CINK SLIM 2|CINK +|CINK KING|CINK PEAX|CINK SLIM|SUBLIM",
                "iMobile": "i-mobile (IQ|i-STYLE|idea|ZAA|Hitz)",
                "SimValley": "\\b(SP-80|XT-930|SX-340|XT-930|SX-310|SP-360|SP60|SPT-800|SP-120|SPT-800|SP-140|SPX-5|SPX-8|SP-100|SPX-8|SPX-12)\\b",
                "Wolfgang": "AT-B24D|AT-AS50HD|AT-AS40W|AT-AS55HD|AT-AS45q2|AT-B26D|AT-AS50Q",
                "Alcatel": "Alcatel",
                "Nintendo": "Nintendo 3DS",
                "Amoi": "Amoi",
                "INQ": "INQ",
                "GenericPhone": "Tapatalk|PDA;|SAGEM|\\bmmp\\b|pocket|\\bpsp\\b|symbian|Smartphone|smartfon|treo|up.browser|up.link|vodafone|\\bwap\\b|nokia|Series40|Series60|S60|SonyEricsson|N900|MAUI.*WAP.*Browser"
            },
            "tablets": {
                "iPad": "iPad|iPad.*Mobile",
                "NexusTablet": "Android.*Nexus[\\s]+(7|9|10)",
                "SamsungTablet": "SAMSUNG.*Tablet|Galaxy.*Tab|SC-01C|GT-P1000|GT-P1003|GT-P1010|GT-P3105|GT-P6210|GT-P6800|GT-P6810|GT-P7100|GT-P7300|GT-P7310|GT-P7500|GT-P7510|SCH-I800|SCH-I815|SCH-I905|SGH-I957|SGH-I987|SGH-T849|SGH-T859|SGH-T869|SPH-P100|GT-P3100|GT-P3108|GT-P3110|GT-P5100|GT-P5110|GT-P6200|GT-P7320|GT-P7511|GT-N8000|GT-P8510|SGH-I497|SPH-P500|SGH-T779|SCH-I705|SCH-I915|GT-N8013|GT-P3113|GT-P5113|GT-P8110|GT-N8010|GT-N8005|GT-N8020|GT-P1013|GT-P6201|GT-P7501|GT-N5100|GT-N5105|GT-N5110|SHV-E140K|SHV-E140L|SHV-E140S|SHV-E150S|SHV-E230K|SHV-E230L|SHV-E230S|SHW-M180K|SHW-M180L|SHW-M180S|SHW-M180W|SHW-M300W|SHW-M305W|SHW-M380K|SHW-M380S|SHW-M380W|SHW-M430W|SHW-M480K|SHW-M480S|SHW-M480W|SHW-M485W|SHW-M486W|SHW-M500W|GT-I9228|SCH-P739|SCH-I925|GT-I9200|GT-P5200|GT-P5210|GT-P5210X|SM-T311|SM-T310|SM-T310X|SM-T210|SM-T210R|SM-T211|SM-P600|SM-P601|SM-P605|SM-P900|SM-P901|SM-T217|SM-T217A|SM-T217S|SM-P6000|SM-T3100|SGH-I467|XE500|SM-T110|GT-P5220|GT-I9200X|GT-N5110X|GT-N5120|SM-P905|SM-T111|SM-T2105|SM-T315|SM-T320|SM-T320X|SM-T321|SM-T520|SM-T525|SM-T530NU|SM-T230NU|SM-T330NU|SM-T900|XE500T1C|SM-P605V|SM-P905V|SM-T337V|SM-T537V|SM-T707V|SM-T807V|SM-P600X|SM-P900X|SM-T210X|SM-T230|SM-T230X|SM-T325|GT-P7503|SM-T531|SM-T330|SM-T530|SM-T705|SM-T705C|SM-T535|SM-T331|SM-T800|SM-T700|SM-T537|SM-T807|SM-P907A|SM-T337A|SM-T537A|SM-T707A|SM-T807A|SM-T237|SM-T807P|SM-P607T|SM-T217T|SM-T337T|SM-T807T|SM-T116NQ|SM-P550|SM-T350|SM-T550|SM-T9000|SM-P9000|SM-T705Y|SM-T805|GT-P3113|SM-T710|SM-T810|SM-T815|SM-T360|SM-T533|SM-T113|SM-T335|SM-T715|SM-T560|SM-T670|SM-T677|SM-T377|SM-T567|SM-T357T|SM-T555|SM-T561",
                "Kindle": "Kindle|Silk.*Accelerated|Android.*\\b(KFOT|KFTT|KFJWI|KFJWA|KFOTE|KFSOWI|KFTHWI|KFTHWA|KFAPWI|KFAPWA|WFJWAE|KFSAWA|KFSAWI|KFASWI|KFARWI)\\b",
                "SurfaceTablet": "Windows NT [0-9.]+; ARM;.*(Tablet|ARMBJS)",
                "HPTablet": "HP Slate (7|8|10)|HP ElitePad 900|hp-tablet|EliteBook.*Touch|HP 8|Slate 21|HP SlateBook 10",
                "AsusTablet": "^.*PadFone((?!Mobile).)*$|Transformer|TF101|TF101G|TF300T|TF300TG|TF300TL|TF700T|TF700KL|TF701T|TF810C|ME171|ME301T|ME302C|ME371MG|ME370T|ME372MG|ME172V|ME173X|ME400C|Slider SL101|\\bK00F\\b|\\bK00C\\b|\\bK00E\\b|\\bK00L\\b|TX201LA|ME176C|ME102A|\\bM80TA\\b|ME372CL|ME560CG|ME372CG|ME302KL| K010 | K017 |ME572C|ME103K|ME170C|ME171C|\\bME70C\\b|ME581C|ME581CL|ME8510C|ME181C|P01Y|PO1MA",
                "BlackBerryTablet": "PlayBook|RIM Tablet",
                "HTCtablet": "HTC_Flyer_P512|HTC Flyer|HTC Jetstream|HTC-P715a|HTC EVO View 4G|PG41200|PG09410",
                "MotorolaTablet": "xoom|sholest|MZ615|MZ605|MZ505|MZ601|MZ602|MZ603|MZ604|MZ606|MZ607|MZ608|MZ609|MZ615|MZ616|MZ617",
                "NookTablet": "Android.*Nook|NookColor|nook browser|BNRV200|BNRV200A|BNTV250|BNTV250A|BNTV400|BNTV600|LogicPD Zoom2",
                "AcerTablet": "Android.*; \\b(A100|A101|A110|A200|A210|A211|A500|A501|A510|A511|A700|A701|W500|W500P|W501|W501P|W510|W511|W700|G100|G100W|B1-A71|B1-710|B1-711|A1-810|A1-811|A1-830)\\b|W3-810|\\bA3-A10\\b|\\bA3-A11\\b|\\bA3-A20",
                "ToshibaTablet": "Android.*(AT100|AT105|AT200|AT205|AT270|AT275|AT300|AT305|AT1S5|AT500|AT570|AT700|AT830)|TOSHIBA.*FOLIO",
                "LGTablet": "\\bL-06C|LG-V909|LG-V900|LG-V700|LG-V510|LG-V500|LG-V410|LG-V400|LG-VK810\\b",
                "FujitsuTablet": "Android.*\\b(F-01D|F-02F|F-05E|F-10D|M532|Q572)\\b",
                "PrestigioTablet": "PMP3170B|PMP3270B|PMP3470B|PMP7170B|PMP3370B|PMP3570C|PMP5870C|PMP3670B|PMP5570C|PMP5770D|PMP3970B|PMP3870C|PMP5580C|PMP5880D|PMP5780D|PMP5588C|PMP7280C|PMP7280C3G|PMP7280|PMP7880D|PMP5597D|PMP5597|PMP7100D|PER3464|PER3274|PER3574|PER3884|PER5274|PER5474|PMP5097CPRO|PMP5097|PMP7380D|PMP5297C|PMP5297C_QUAD|PMP812E|PMP812E3G|PMP812F|PMP810E|PMP880TD|PMT3017|PMT3037|PMT3047|PMT3057|PMT7008|PMT5887|PMT5001|PMT5002",
                "LenovoTablet": "Lenovo TAB|Idea(Tab|Pad)( A1|A10| K1|)|ThinkPad([ ]+)?Tablet|YT3-X90L|YT3-X90F|YT3-X90X|Lenovo.*(S2109|S2110|S5000|S6000|K3011|A3000|A3500|A1000|A2107|A2109|A1107|A5500|A7600|B6000|B8000|B8080)(-|)(FL|F|HV|H|)",
                "DellTablet": "Venue 11|Venue 8|Venue 7|Dell Streak 10|Dell Streak 7",
                "YarvikTablet": "Android.*\\b(TAB210|TAB211|TAB224|TAB250|TAB260|TAB264|TAB310|TAB360|TAB364|TAB410|TAB411|TAB420|TAB424|TAB450|TAB460|TAB461|TAB464|TAB465|TAB467|TAB468|TAB07-100|TAB07-101|TAB07-150|TAB07-151|TAB07-152|TAB07-200|TAB07-201-3G|TAB07-210|TAB07-211|TAB07-212|TAB07-214|TAB07-220|TAB07-400|TAB07-485|TAB08-150|TAB08-200|TAB08-201-3G|TAB08-201-30|TAB09-100|TAB09-211|TAB09-410|TAB10-150|TAB10-201|TAB10-211|TAB10-400|TAB10-410|TAB13-201|TAB274EUK|TAB275EUK|TAB374EUK|TAB462EUK|TAB474EUK|TAB9-200)\\b",
                "MedionTablet": "Android.*\\bOYO\\b|LIFE.*(P9212|P9514|P9516|S9512)|LIFETAB",
                "ArnovaTablet": "AN10G2|AN7bG3|AN7fG3|AN8G3|AN8cG3|AN7G3|AN9G3|AN7dG3|AN7dG3ST|AN7dG3ChildPad|AN10bG3|AN10bG3DT|AN9G2",
                "IntensoTablet": "INM8002KP|INM1010FP|INM805ND|Intenso Tab|TAB1004",
                "IRUTablet": "M702pro",
                "MegafonTablet": "MegaFon V9|\\bZTE V9\\b|Android.*\\bMT7A\\b",
                "EbodaTablet": "E-Boda (Supreme|Impresspeed|Izzycomm|Essential)",
                "AllViewTablet": "Allview.*(Viva|Alldro|City|Speed|All TV|Frenzy|Quasar|Shine|TX1|AX1|AX2)",
                "ArchosTablet": "\\b(101G9|80G9|A101IT)\\b|Qilive 97R|Archos5|\\bARCHOS (70|79|80|90|97|101|FAMILYPAD|)(b|)(G10| Cobalt| TITANIUM(HD|)| Xenon| Neon|XSK| 2| XS 2| PLATINUM| CARBON|GAMEPAD)\\b",
                "AinolTablet": "NOVO7|NOVO8|NOVO10|Novo7Aurora|Novo7Basic|NOVO7PALADIN|novo9-Spark",
                "NokiaLumiaTablet": "Lumia 2520",
                "SonyTablet": "Sony.*Tablet|Xperia Tablet|Sony Tablet S|SO-03E|SGPT12|SGPT13|SGPT114|SGPT121|SGPT122|SGPT123|SGPT111|SGPT112|SGPT113|SGPT131|SGPT132|SGPT133|SGPT211|SGPT212|SGPT213|SGP311|SGP312|SGP321|EBRD1101|EBRD1102|EBRD1201|SGP351|SGP341|SGP511|SGP512|SGP521|SGP541|SGP551|SGP621|SGP612|SOT31",
                "PhilipsTablet": "\\b(PI2010|PI3000|PI3100|PI3105|PI3110|PI3205|PI3210|PI3900|PI4010|PI7000|PI7100)\\b",
                "CubeTablet": "Android.*(K8GT|U9GT|U10GT|U16GT|U17GT|U18GT|U19GT|U20GT|U23GT|U30GT)|CUBE U8GT",
                "CobyTablet": "MID1042|MID1045|MID1125|MID1126|MID7012|MID7014|MID7015|MID7034|MID7035|MID7036|MID7042|MID7048|MID7127|MID8042|MID8048|MID8127|MID9042|MID9740|MID9742|MID7022|MID7010",
                "MIDTablet": "M9701|M9000|M9100|M806|M1052|M806|T703|MID701|MID713|MID710|MID727|MID760|MID830|MID728|MID933|MID125|MID810|MID732|MID120|MID930|MID800|MID731|MID900|MID100|MID820|MID735|MID980|MID130|MID833|MID737|MID960|MID135|MID860|MID736|MID140|MID930|MID835|MID733|MID4X10",
                "MSITablet": "MSI \\b(Primo 73K|Primo 73L|Primo 81L|Primo 77|Primo 93|Primo 75|Primo 76|Primo 73|Primo 81|Primo 91|Primo 90|Enjoy 71|Enjoy 7|Enjoy 10)\\b",
                "SMiTTablet": "Android.*(\\bMID\\b|MID-560|MTV-T1200|MTV-PND531|MTV-P1101|MTV-PND530)",
                "RockChipTablet": "Android.*(RK2818|RK2808A|RK2918|RK3066)|RK2738|RK2808A",
                "FlyTablet": "IQ310|Fly Vision",
                "bqTablet": "Android.*(bq)?.*(Elcano|Curie|Edison|Maxwell|Kepler|Pascal|Tesla|Hypatia|Platon|Newton|Livingstone|Cervantes|Avant|Aquaris E10)|Maxwell.*Lite|Maxwell.*Plus",
                "HuaweiTablet": "MediaPad|MediaPad 7 Youth|IDEOS S7|S7-201c|S7-202u|S7-101|S7-103|S7-104|S7-105|S7-106|S7-201|S7-Slim",
                "NecTablet": "\\bN-06D|\\bN-08D",
                "PantechTablet": "Pantech.*P4100",
                "BronchoTablet": "Broncho.*(N701|N708|N802|a710)",
                "VersusTablet": "TOUCHPAD.*[78910]|\\bTOUCHTAB\\b",
                "ZyncTablet": "z1000|Z99 2G|z99|z930|z999|z990|z909|Z919|z900",
                "PositivoTablet": "TB07STA|TB10STA|TB07FTA|TB10FTA",
                "NabiTablet": "Android.*\\bNabi",
                "KoboTablet": "Kobo Touch|\\bK080\\b|\\bVox\\b Build|\\bArc\\b Build",
                "DanewTablet": "DSlide.*\\b(700|701R|702|703R|704|802|970|971|972|973|974|1010|1012)\\b",
                "TexetTablet": "NaviPad|TB-772A|TM-7045|TM-7055|TM-9750|TM-7016|TM-7024|TM-7026|TM-7041|TM-7043|TM-7047|TM-8041|TM-9741|TM-9747|TM-9748|TM-9751|TM-7022|TM-7021|TM-7020|TM-7011|TM-7010|TM-7023|TM-7025|TM-7037W|TM-7038W|TM-7027W|TM-9720|TM-9725|TM-9737W|TM-1020|TM-9738W|TM-9740|TM-9743W|TB-807A|TB-771A|TB-727A|TB-725A|TB-719A|TB-823A|TB-805A|TB-723A|TB-715A|TB-707A|TB-705A|TB-709A|TB-711A|TB-890HD|TB-880HD|TB-790HD|TB-780HD|TB-770HD|TB-721HD|TB-710HD|TB-434HD|TB-860HD|TB-840HD|TB-760HD|TB-750HD|TB-740HD|TB-730HD|TB-722HD|TB-720HD|TB-700HD|TB-500HD|TB-470HD|TB-431HD|TB-430HD|TB-506|TB-504|TB-446|TB-436|TB-416|TB-146SE|TB-126SE",
                "PlaystationTablet": "Playstation.*(Portable|Vita)",
                "TrekstorTablet": "ST10416-1|VT10416-1|ST70408-1|ST702xx-1|ST702xx-2|ST80208|ST97216|ST70104-2|VT10416-2|ST10216-2A|SurfTab",
                "PyleAudioTablet": "\\b(PTBL10CEU|PTBL10C|PTBL72BC|PTBL72BCEU|PTBL7CEU|PTBL7C|PTBL92BC|PTBL92BCEU|PTBL9CEU|PTBL9CUK|PTBL9C)\\b",
                "AdvanTablet": "Android.* \\b(E3A|T3X|T5C|T5B|T3E|T3C|T3B|T1J|T1F|T2A|T1H|T1i|E1C|T1-E|T5-A|T4|E1-B|T2Ci|T1-B|T1-D|O1-A|E1-A|T1-A|T3A|T4i)\\b ",
                "DanyTechTablet": "Genius Tab G3|Genius Tab S2|Genius Tab Q3|Genius Tab G4|Genius Tab Q4|Genius Tab G-II|Genius TAB GII|Genius TAB GIII|Genius Tab S1",
                "GalapadTablet": "Android.*\\bG1\\b",
                "MicromaxTablet": "Funbook|Micromax.*\\b(P250|P560|P360|P362|P600|P300|P350|P500|P275)\\b",
                "KarbonnTablet": "Android.*\\b(A39|A37|A34|ST8|ST10|ST7|Smart Tab3|Smart Tab2)\\b",
                "AllFineTablet": "Fine7 Genius|Fine7 Shine|Fine7 Air|Fine8 Style|Fine9 More|Fine10 Joy|Fine11 Wide",
                "PROSCANTablet": "\\b(PEM63|PLT1023G|PLT1041|PLT1044|PLT1044G|PLT1091|PLT4311|PLT4311PL|PLT4315|PLT7030|PLT7033|PLT7033D|PLT7035|PLT7035D|PLT7044K|PLT7045K|PLT7045KB|PLT7071KG|PLT7072|PLT7223G|PLT7225G|PLT7777G|PLT7810K|PLT7849G|PLT7851G|PLT7852G|PLT8015|PLT8031|PLT8034|PLT8036|PLT8080K|PLT8082|PLT8088|PLT8223G|PLT8234G|PLT8235G|PLT8816K|PLT9011|PLT9045K|PLT9233G|PLT9735|PLT9760G|PLT9770G)\\b",
                "YONESTablet": "BQ1078|BC1003|BC1077|RK9702|BC9730|BC9001|IT9001|BC7008|BC7010|BC708|BC728|BC7012|BC7030|BC7027|BC7026",
                "ChangJiaTablet": "TPC7102|TPC7103|TPC7105|TPC7106|TPC7107|TPC7201|TPC7203|TPC7205|TPC7210|TPC7708|TPC7709|TPC7712|TPC7110|TPC8101|TPC8103|TPC8105|TPC8106|TPC8203|TPC8205|TPC8503|TPC9106|TPC9701|TPC97101|TPC97103|TPC97105|TPC97106|TPC97111|TPC97113|TPC97203|TPC97603|TPC97809|TPC97205|TPC10101|TPC10103|TPC10106|TPC10111|TPC10203|TPC10205|TPC10503",
                "GUTablet": "TX-A1301|TX-M9002|Q702|kf026",
                "PointOfViewTablet": "TAB-P506|TAB-navi-7-3G-M|TAB-P517|TAB-P-527|TAB-P701|TAB-P703|TAB-P721|TAB-P731N|TAB-P741|TAB-P825|TAB-P905|TAB-P925|TAB-PR945|TAB-PL1015|TAB-P1025|TAB-PI1045|TAB-P1325|TAB-PROTAB[0-9]+|TAB-PROTAB25|TAB-PROTAB26|TAB-PROTAB27|TAB-PROTAB26XL|TAB-PROTAB2-IPS9|TAB-PROTAB30-IPS9|TAB-PROTAB25XXL|TAB-PROTAB26-IPS10|TAB-PROTAB30-IPS10",
                "OvermaxTablet": "OV-(SteelCore|NewBase|Basecore|Baseone|Exellen|Quattor|EduTab|Solution|ACTION|BasicTab|TeddyTab|MagicTab|Stream|TB-08|TB-09)",
                "HCLTablet": "HCL.*Tablet|Connect-3G-2.0|Connect-2G-2.0|ME Tablet U1|ME Tablet U2|ME Tablet G1|ME Tablet X1|ME Tablet Y2|ME Tablet Sync",
                "DPSTablet": "DPS Dream 9|DPS Dual 7",
                "VistureTablet": "V97 HD|i75 3G|Visture V4( HD)?|Visture V5( HD)?|Visture V10",
                "CrestaTablet": "CTP(-)?810|CTP(-)?818|CTP(-)?828|CTP(-)?838|CTP(-)?888|CTP(-)?978|CTP(-)?980|CTP(-)?987|CTP(-)?988|CTP(-)?989",
                "MediatekTablet": "\\bMT8125|MT8389|MT8135|MT8377\\b",
                "ConcordeTablet": "Concorde([ ]+)?Tab|ConCorde ReadMan",
                "GoCleverTablet": "GOCLEVER TAB|A7GOCLEVER|M1042|M7841|M742|R1042BK|R1041|TAB A975|TAB A7842|TAB A741|TAB A741L|TAB M723G|TAB M721|TAB A1021|TAB I921|TAB R721|TAB I720|TAB T76|TAB R70|TAB R76.2|TAB R106|TAB R83.2|TAB M813G|TAB I721|GCTA722|TAB I70|TAB I71|TAB S73|TAB R73|TAB R74|TAB R93|TAB R75|TAB R76.1|TAB A73|TAB A93|TAB A93.2|TAB T72|TAB R83|TAB R974|TAB R973|TAB A101|TAB A103|TAB A104|TAB A104.2|R105BK|M713G|A972BK|TAB A971|TAB R974.2|TAB R104|TAB R83.3|TAB A1042",
                "ModecomTablet": "FreeTAB 9000|FreeTAB 7.4|FreeTAB 7004|FreeTAB 7800|FreeTAB 2096|FreeTAB 7.5|FreeTAB 1014|FreeTAB 1001 |FreeTAB 8001|FreeTAB 9706|FreeTAB 9702|FreeTAB 7003|FreeTAB 7002|FreeTAB 1002|FreeTAB 7801|FreeTAB 1331|FreeTAB 1004|FreeTAB 8002|FreeTAB 8014|FreeTAB 9704|FreeTAB 1003",
                "VoninoTablet": "\\b(Argus[ _]?S|Diamond[ _]?79HD|Emerald[ _]?78E|Luna[ _]?70C|Onyx[ _]?S|Onyx[ _]?Z|Orin[ _]?HD|Orin[ _]?S|Otis[ _]?S|SpeedStar[ _]?S|Magnet[ _]?M9|Primus[ _]?94[ _]?3G|Primus[ _]?94HD|Primus[ _]?QS|Android.*\\bQ8\\b|Sirius[ _]?EVO[ _]?QS|Sirius[ _]?QS|Spirit[ _]?S)\\b",
                "ECSTablet": "V07OT2|TM105A|S10OT1|TR10CS1",
                "StorexTablet": "eZee[_']?(Tab|Go)[0-9]+|TabLC7|Looney Tunes Tab",
                "VodafoneTablet": "SmartTab([ ]+)?[0-9]+|SmartTabII10|SmartTabII7|VF-1497",
                "EssentielBTablet": "Smart[ ']?TAB[ ]+?[0-9]+|Family[ ']?TAB2",
                "RossMoorTablet": "RM-790|RM-997|RMD-878G|RMD-974R|RMT-705A|RMT-701|RME-601|RMT-501|RMT-711",
                "iMobileTablet": "i-mobile i-note",
                "TolinoTablet": "tolino tab [0-9.]+|tolino shine",
                "AudioSonicTablet": "\\bC-22Q|T7-QC|T-17B|T-17P\\b",
                "AMPETablet": "Android.* A78 ",
                "SkkTablet": "Android.* (SKYPAD|PHOENIX|CYCLOPS)",
                "TecnoTablet": "TECNO P9",
                "JXDTablet": "Android.* \\b(F3000|A3300|JXD5000|JXD3000|JXD2000|JXD300B|JXD300|S5800|S7800|S602b|S5110b|S7300|S5300|S602|S603|S5100|S5110|S601|S7100a|P3000F|P3000s|P101|P200s|P1000m|P200m|P9100|P1000s|S6600b|S908|P1000|P300|S18|S6600|S9100)\\b",
                "iJoyTablet": "Tablet (Spirit 7|Essentia|Galatea|Fusion|Onix 7|Landa|Titan|Scooby|Deox|Stella|Themis|Argon|Unique 7|Sygnus|Hexen|Finity 7|Cream|Cream X2|Jade|Neon 7|Neron 7|Kandy|Scape|Saphyr 7|Rebel|Biox|Rebel|Rebel 8GB|Myst|Draco 7|Myst|Tab7-004|Myst|Tadeo Jones|Tablet Boing|Arrow|Draco Dual Cam|Aurix|Mint|Amity|Revolution|Finity 9|Neon 9|T9w|Amity 4GB Dual Cam|Stone 4GB|Stone 8GB|Andromeda|Silken|X2|Andromeda II|Halley|Flame|Saphyr 9,7|Touch 8|Planet|Triton|Unique 10|Hexen 10|Memphis 4GB|Memphis 8GB|Onix 10)",
                "FX2Tablet": "FX2 PAD7|FX2 PAD10",
                "XoroTablet": "KidsPAD 701|PAD[ ]?712|PAD[ ]?714|PAD[ ]?716|PAD[ ]?717|PAD[ ]?718|PAD[ ]?720|PAD[ ]?721|PAD[ ]?722|PAD[ ]?790|PAD[ ]?792|PAD[ ]?900|PAD[ ]?9715D|PAD[ ]?9716DR|PAD[ ]?9718DR|PAD[ ]?9719QR|PAD[ ]?9720QR|TelePAD1030|Telepad1032|TelePAD730|TelePAD731|TelePAD732|TelePAD735Q|TelePAD830|TelePAD9730|TelePAD795|MegaPAD 1331|MegaPAD 1851|MegaPAD 2151",
                "ViewsonicTablet": "ViewPad 10pi|ViewPad 10e|ViewPad 10s|ViewPad E72|ViewPad7|ViewPad E100|ViewPad 7e|ViewSonic VB733|VB100a",
                "OdysTablet": "LOOX|XENO10|ODYS[ -](Space|EVO|Xpress|NOON)|\\bXELIO\\b|Xelio10Pro|XELIO7PHONETAB|XELIO10EXTREME|XELIOPT2|NEO_QUAD10",
                "CaptivaTablet": "CAPTIVA PAD",
                "IconbitTablet": "NetTAB|NT-3702|NT-3702S|NT-3702S|NT-3603P|NT-3603P|NT-0704S|NT-0704S|NT-3805C|NT-3805C|NT-0806C|NT-0806C|NT-0909T|NT-0909T|NT-0907S|NT-0907S|NT-0902S|NT-0902S",
                "TeclastTablet": "T98 4G|\\bP80\\b|\\bX90HD\\b|X98 Air|X98 Air 3G|\\bX89\\b|P80 3G|\\bX80h\\b|P98 Air|\\bX89HD\\b|P98 3G|\\bP90HD\\b|P89 3G|X98 3G|\\bP70h\\b|P79HD 3G|G18d 3G|\\bP79HD\\b|\\bP89s\\b|\\bA88\\b|\\bP10HD\\b|\\bP19HD\\b|G18 3G|\\bP78HD\\b|\\bA78\\b|\\bP75\\b|G17s 3G|G17h 3G|\\bP85t\\b|\\bP90\\b|\\bP11\\b|\\bP98t\\b|\\bP98HD\\b|\\bG18d\\b|\\bP85s\\b|\\bP11HD\\b|\\bP88s\\b|\\bA80HD\\b|\\bA80se\\b|\\bA10h\\b|\\bP89\\b|\\bP78s\\b|\\bG18\\b|\\bP85\\b|\\bA70h\\b|\\bA70\\b|\\bG17\\b|\\bP18\\b|\\bA80s\\b|\\bA11s\\b|\\bP88HD\\b|\\bA80h\\b|\\bP76s\\b|\\bP76h\\b|\\bP98\\b|\\bA10HD\\b|\\bP78\\b|\\bP88\\b|\\bA11\\b|\\bA10t\\b|\\bP76a\\b|\\bP76t\\b|\\bP76e\\b|\\bP85HD\\b|\\bP85a\\b|\\bP86\\b|\\bP75HD\\b|\\bP76v\\b|\\bA12\\b|\\bP75a\\b|\\bA15\\b|\\bP76Ti\\b|\\bP81HD\\b|\\bA10\\b|\\bT760VE\\b|\\bT720HD\\b|\\bP76\\b|\\bP73\\b|\\bP71\\b|\\bP72\\b|\\bT720SE\\b|\\bC520Ti\\b|\\bT760\\b|\\bT720VE\\b|T720-3GE|T720-WiFi",
                "OndaTablet": "\\b(V975i|Vi30|VX530|V701|Vi60|V701s|Vi50|V801s|V719|Vx610w|VX610W|V819i|Vi10|VX580W|Vi10|V711s|V813|V811|V820w|V820|Vi20|V711|VI30W|V712|V891w|V972|V819w|V820w|Vi60|V820w|V711|V813s|V801|V819|V975s|V801|V819|V819|V818|V811|V712|V975m|V101w|V961w|V812|V818|V971|V971s|V919|V989|V116w|V102w|V973|Vi40)\\b[\\s]+",
                "JaytechTablet": "TPC-PA762",
                "BlaupunktTablet": "Endeavour 800NG|Endeavour 1010",
                "DigmaTablet": "\\b(iDx10|iDx9|iDx8|iDx7|iDxD7|iDxD8|iDsQ8|iDsQ7|iDsQ8|iDsD10|iDnD7|3TS804H|iDsQ11|iDj7|iDs10)\\b",
                "EvolioTablet": "ARIA_Mini_wifi|Aria[ _]Mini|Evolio X10|Evolio X7|Evolio X8|\\bEvotab\\b|\\bNeura\\b",
                "LavaTablet": "QPAD E704|\\bIvoryS\\b|E-TAB IVORY|\\bE-TAB\\b",
                "AocTablet": "MW0811|MW0812|MW0922|MTK8382|MW1031|MW0831|MW0821|MW0931|MW0712",
                "MpmanTablet": "MP11 OCTA|MP10 OCTA|MPQC1114|MPQC1004|MPQC994|MPQC974|MPQC973|MPQC804|MPQC784|MPQC780|\\bMPG7\\b|MPDCG75|MPDCG71|MPDC1006|MP101DC|MPDC9000|MPDC905|MPDC706HD|MPDC706|MPDC705|MPDC110|MPDC100|MPDC99|MPDC97|MPDC88|MPDC8|MPDC77|MP709|MID701|MID711|MID170|MPDC703|MPQC1010",
                "CelkonTablet": "CT695|CT888|CT[\\s]?910|CT7 Tab|CT9 Tab|CT3 Tab|CT2 Tab|CT1 Tab|C820|C720|\\bCT-1\\b",
                "WolderTablet": "miTab \\b(DIAMOND|SPACE|BROOKLYN|NEO|FLY|MANHATTAN|FUNK|EVOLUTION|SKY|GOCAR|IRON|GENIUS|POP|MINT|EPSILON|BROADWAY|JUMP|HOP|LEGEND|NEW AGE|LINE|ADVANCE|FEEL|FOLLOW|LIKE|LINK|LIVE|THINK|FREEDOM|CHICAGO|CLEVELAND|BALTIMORE-GH|IOWA|BOSTON|SEATTLE|PHOENIX|DALLAS|IN 101|MasterChef)\\b",
                "MiTablet": "\\bMI PAD\\b|\\bHM NOTE 1W\\b",
                "NibiruTablet": "Nibiru M1|Nibiru Jupiter One",
                "NexoTablet": "NEXO NOVA|NEXO 10|NEXO AVIO|NEXO FREE|NEXO GO|NEXO EVO|NEXO 3G|NEXO SMART|NEXO KIDDO|NEXO MOBI",
                "LeaderTablet": "TBLT10Q|TBLT10I|TBL-10WDKB|TBL-10WDKBO2013|TBL-W230V2|TBL-W450|TBL-W500|SV572|TBLT7I|TBA-AC7-8G|TBLT79|TBL-8W16|TBL-10W32|TBL-10WKB|TBL-W100",
                "UbislateTablet": "UbiSlate[\\s]?7C",
                "PocketBookTablet": "Pocketbook",
                "KocasoTablet": "\\b(TB-1207)\\b",
                "Hudl": "Hudl HT7S3|Hudl 2",
                "TelstraTablet": "T-Hub2",
                "GenericTablet": "Android.*\\b97D\\b|Tablet(?!.*PC)|BNTV250A|MID-WCDMA|LogicPD Zoom2|\\bA7EB\\b|CatNova8|A1_07|CT704|CT1002|\\bM721\\b|rk30sdk|\\bEVOTAB\\b|M758A|ET904|ALUMIUM10|Smartfren Tab|Endeavour 1010|Tablet-PC-4|Tagi Tab|\\bM6pro\\b|CT1020W|arc 10HD|\\bJolla\\b|\\bTP750\\b"
            },
            "oss": {
                "AndroidOS": "Android",
                "BlackBerryOS": "blackberry|\\bBB10\\b|rim tablet os",
                "PalmOS": "PalmOS|avantgo|blazer|elaine|hiptop|palm|plucker|xiino",
                "SymbianOS": "Symbian|SymbOS|Series60|Series40|SYB-[0-9]+|\\bS60\\b",
                "WindowsMobileOS": "Windows CE.*(PPC|Smartphone|Mobile|[0-9]{3}x[0-9]{3})|Window Mobile|Windows Phone [0-9.]+|WCE;",
                "WindowsPhoneOS": "Windows Phone 10.0|Windows Phone 8.1|Windows Phone 8.0|Windows Phone OS|XBLWP7|ZuneWP7|Windows NT 6.[23]; ARM;",
                "iOS": "\\biPhone.*Mobile|\\biPod|\\biPad",
                "MeeGoOS": "MeeGo",
                "MaemoOS": "Maemo",
                "JavaOS": "J2ME\/|\\bMIDP\\b|\\bCLDC\\b",
                "webOS": "webOS|hpwOS",
                "badaOS": "\\bBada\\b",
                "BREWOS": "BREW"
            },
            "uas": {
                "Vivaldi": "Vivaldi",
                "Chrome": "\\bCrMo\\b|CriOS|Android.*Chrome\/[.0-9]* (Mobile)?",
                "Dolfin": "\\bDolfin\\b",
                "Opera": "Opera.*Mini|Opera.*Mobi|Android.*Opera|Mobile.*OPR\/[0-9.]+|Coast\/[0-9.]+",
                "Skyfire": "Skyfire",
                "Edge": "Mobile Safari\/[.0-9]* Edge",
                "IE": "IEMobile|MSIEMobile",
                "Firefox": "fennec|firefox.*maemo|(Mobile|Tablet).*Firefox|Firefox.*Mobile",
                "Bolt": "bolt",
                "TeaShark": "teashark",
                "Blazer": "Blazer",
                "Safari": "Version.*Mobile.*Safari|Safari.*Mobile|MobileSafari",
                "Tizen": "Tizen",
                "UCBrowser": "UC.*Browser|UCWEB",
                "baiduboxapp": "baiduboxapp",
                "baidubrowser": "baidubrowser",
                "DiigoBrowser": "DiigoBrowser",
                "Puffin": "Puffin",
                "Mercury": "\\bMercury\\b",
                "ObigoBrowser": "Obigo",
                "NetFront": "NF-Browser",
                "GenericBrowser": "NokiaBrowser|OviBrowser|OneBrowser|TwonkyBeamBrowser|SEMC.*Browser|FlyFlow|Minimo|NetFront|Novarra-Vision|MQQBrowser|MicroMessenger",
                "PaleMoon": "Android.*PaleMoon|Mobile.*PaleMoon"
            },
            "props": {
                "Mobile": "Mobile\/[VER]",
                "Build": "Build\/[VER]",
                "Version": "Version\/[VER]",
                "VendorID": "VendorID\/[VER]",
                "iPad": "iPad.*CPU[a-z ]+[VER]",
                "iPhone": "iPhone.*CPU[a-z ]+[VER]",
                "iPod": "iPod.*CPU[a-z ]+[VER]",
                "Kindle": "Kindle\/[VER]",
                "Chrome": [
                    "Chrome\/[VER]",
                    "CriOS\/[VER]",
                    "CrMo\/[VER]"
                ],
                "Coast": [
                    "Coast\/[VER]"
                ],
                "Dolfin": "Dolfin\/[VER]",
                "Firefox": "Firefox\/[VER]",
                "Fennec": "Fennec\/[VER]",
                "Edge": "Edge\/[VER]",
                "IE": [
                    "IEMobile\/[VER];",
                    "IEMobile [VER]",
                    "MSIE [VER];",
                    "Trident\/[0-9.]+;.*rv:[VER]"
                ],
                "NetFront": "NetFront\/[VER]",
                "NokiaBrowser": "NokiaBrowser\/[VER]",
                "Opera": [
                    " OPR\/[VER]",
                    "Opera Mini\/[VER]",
                    "Version\/[VER]"
                ],
                "Opera Mini": "Opera Mini\/[VER]",
                "Opera Mobi": "Version\/[VER]",
                "UC Browser": "UC Browser[VER]",
                "MQQBrowser": "MQQBrowser\/[VER]",
                "MicroMessenger": "MicroMessenger\/[VER]",
                "baiduboxapp": "baiduboxapp\/[VER]",
                "baidubrowser": "baidubrowser\/[VER]",
                "Iron": "Iron\/[VER]",
                "Safari": [
                    "Version\/[VER]",
                    "Safari\/[VER]"
                ],
                "Skyfire": "Skyfire\/[VER]",
                "Tizen": "Tizen\/[VER]",
                "Webkit": "webkit[ \/][VER]",
                "PaleMoon": "PaleMoon\/[VER]",
                "Gecko": "Gecko\/[VER]",
                "Trident": "Trident\/[VER]",
                "Presto": "Presto\/[VER]",
                "Goanna": "Goanna\/[VER]",
                "iOS": " \\bi?OS\\b [VER][ ;]{1}",
                "Android": "Android [VER]",
                "BlackBerry": [
                    "BlackBerry[\\w]+\/[VER]",
                    "BlackBerry.*Version\/[VER]",
                    "Version\/[VER]"
                ],
                "BREW": "BREW [VER]",
                "Java": "Java\/[VER]",
                "Windows Phone OS": [
                    "Windows Phone OS [VER]",
                    "Windows Phone [VER]"
                ],
                "Windows Phone": "Windows Phone [VER]",
                "Windows CE": "Windows CE\/[VER]",
                "Windows NT": "Windows NT [VER]",
                "Symbian": [
                    "SymbianOS\/[VER]",
                    "Symbian\/[VER]"
                ],
                "webOS": [
                    "webOS\/[VER]",
                    "hpwOS\/[VER];"
                ]
            },
            "utils": {
                "Bot": "Googlebot|facebookexternalhit|AdsBot-Google|Google Keyword Suggestion|Facebot|YandexBot|bingbot|ia_archiver|AhrefsBot|Ezooms|GSLFbot|WBSearchBot|Twitterbot|TweetmemeBot|Twikle|PaperLiBot|Wotbox|UnwindFetchor|Exabot|MJ12bot|YandexImages|TurnitinBot|Pingdom",
                "MobileBot": "Googlebot-Mobile|AdsBot-Google-Mobile|YahooSeeker\/M1A1-R2D2",
                "DesktopMode": "WPDesktop",
                "TV": "SonyDTV|HbbTV",
                "WebKit": "(webkit)[ \/]([\\w.]+)",
                "Console": "\\b(Nintendo|Nintendo WiiU|Nintendo 3DS|PLAYSTATION|Xbox)\\b",
                "Watch": "SM-V700"
            }
        };
        // following patterns come from http://detectmobilebrowsers.com/
        impl.detectMobileBrowsers = {
            fullPattern: /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i,
            shortPattern: /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i,
            tabletPattern: /android|ipad|playbook|silk/i
        };
        var hasOwnProp = Object.prototype.hasOwnProperty, isArray;
        impl.FALLBACK_PHONE = 'UnknownPhone';
        impl.FALLBACK_TABLET = 'UnknownTablet';
        impl.FALLBACK_MOBILE = 'UnknownMobile';
        isArray = ('isArray' in Array) ?
            Array.isArray : function (value) { return Object.prototype.toString.call(value) === '[object Array]'; };
        function equalIC(a, b) {
            return a != null && b != null && a.toLowerCase() === b.toLowerCase();
        }
        function containsIC(array, value) {
            var valueLC, i, len = array.length;
            if (!len || !value) {
                return false;
            }
            valueLC = value.toLowerCase();
            for (i = 0; i < len; ++i) {
                if (valueLC === array[i].toLowerCase()) {
                    return true;
                }
            }
            return false;
        }
        function convertPropsToRegExp(object) {
            for (var key in object) {
                if (hasOwnProp.call(object, key)) {
                    object[key] = new RegExp(object[key], 'i');
                }
            }
        }
        (function init() {
            var key, values, value, i, len, verPos, mobileDetectRules = impl.mobileDetectRules;
            for (key in mobileDetectRules.props) {
                if (hasOwnProp.call(mobileDetectRules.props, key)) {
                    values = mobileDetectRules.props[key];
                    if (!isArray(values)) {
                        values = [values];
                    }
                    len = values.length;
                    for (i = 0; i < len; ++i) {
                        value = values[i];
                        verPos = value.indexOf('[VER]');
                        if (verPos >= 0) {
                            value = value.substring(0, verPos) + '([\\w._\\+]+)' + value.substring(verPos + 5);
                        }
                        values[i] = new RegExp(value, 'i');
                    }
                    mobileDetectRules.props[key] = values;
                }
            }
            convertPropsToRegExp(mobileDetectRules.oss);
            convertPropsToRegExp(mobileDetectRules.phones);
            convertPropsToRegExp(mobileDetectRules.tablets);
            convertPropsToRegExp(mobileDetectRules.uas);
            convertPropsToRegExp(mobileDetectRules.utils);
            // copy some patterns to oss0 which are tested first (see issue#15)
            mobileDetectRules.oss0 = {
                WindowsPhoneOS: mobileDetectRules.oss.WindowsPhoneOS,
                WindowsMobileOS: mobileDetectRules.oss.WindowsMobileOS
            };
        }());
        /**
         * Test userAgent string against a set of rules and find the first matched key.
         * @param {Object} rules (key is String, value is RegExp)
         * @param {String} userAgent the navigator.userAgent (or HTTP-Header 'User-Agent').
         * @returns {String|null} the matched key if found, otherwise <tt>null</tt>
         * @private
         */
        impl.findMatch = function (rules, userAgent) {
            for (var key in rules) {
                if (hasOwnProp.call(rules, key)) {
                    if (rules[key].test(userAgent)) {
                        return key;
                    }
                }
            }
            return null;
        };
        /**
         * Test userAgent string against a set of rules and return an array of matched keys.
         * @param {Object} rules (key is String, value is RegExp)
         * @param {String} userAgent the navigator.userAgent (or HTTP-Header 'User-Agent').
         * @returns {Array} an array of matched keys, may be empty when there is no match, but not <tt>null</tt>
         * @private
         */
        impl.findMatches = function (rules, userAgent) {
            var result = [];
            for (var key in rules) {
                if (hasOwnProp.call(rules, key)) {
                    if (rules[key].test(userAgent)) {
                        result.push(key);
                    }
                }
            }
            return result;
        };
        /**
         * Check the version of the given property in the User-Agent.
         *
         * @param {String} propertyName
         * @param {String} userAgent
         * @return {String} version or <tt>null</tt> if version not found
         * @private
         */
        impl.getVersionStr = function (propertyName, userAgent) {
            var props = impl.mobileDetectRules.props, patterns, i, len, match;
            if (hasOwnProp.call(props, propertyName)) {
                patterns = props[propertyName];
                len = patterns.length;
                for (i = 0; i < len; ++i) {
                    match = patterns[i].exec(userAgent);
                    if (match !== null) {
                        return match[1];
                    }
                }
            }
            return null;
        };
        /**
         * Check the version of the given property in the User-Agent.
         * Will return a float number. (eg. 2_0 will return 2.0, 4.3.1 will return 4.31)
         *
         * @param {String} propertyName
         * @param {String} userAgent
         * @return {Number} version or <tt>NaN</tt> if version not found
         * @private
         */
        impl.getVersion = function (propertyName, userAgent) {
            var version = impl.getVersionStr(propertyName, userAgent);
            return version ? impl.prepareVersionNo(version) : NaN;
        };
        /**
         * Prepare the version number.
         *
         * @param {String} version
         * @return {Number} the version number as a floating number
         * @private
         */
        impl.prepareVersionNo = function (version) {
            var numbers;
            numbers = version.split(/[a-z._ \/\-]/i);
            if (numbers.length === 1) {
                version = numbers[0];
            }
            if (numbers.length > 1) {
                version = numbers[0] + '.';
                numbers.shift();
                version += numbers.join('');
            }
            return Number(version);
        };
        impl.isMobileFallback = function (userAgent) {
            return impl.detectMobileBrowsers.fullPattern.test(userAgent) ||
                impl.detectMobileBrowsers.shortPattern.test(userAgent.substr(0, 4));
        };
        impl.isTabletFallback = function (userAgent) {
            return impl.detectMobileBrowsers.tabletPattern.test(userAgent);
        };
        impl.prepareDetectionCache = function (cache, userAgent, maxPhoneWidth) {
            if (cache.mobile !== undefined) {
                return;
            }
            var phone, tablet, phoneSized;
            // first check for stronger tablet rules, then phone (see issue#5)
            tablet = impl.findMatch(impl.mobileDetectRules.tablets, userAgent);
            if (tablet) {
                cache.mobile = cache.tablet = tablet;
                cache.phone = null;
                return; // unambiguously identified as tablet
            }
            phone = impl.findMatch(impl.mobileDetectRules.phones, userAgent);
            if (phone) {
                cache.mobile = cache.phone = phone;
                cache.tablet = null;
                return; // unambiguously identified as phone
            }
            // our rules haven't found a match -> try more general fallback rules
            if (impl.isMobileFallback(userAgent)) {
                phoneSized = MobileDetect.isPhoneSized(maxPhoneWidth);
                if (phoneSized === undefined) {
                    cache.mobile = impl.FALLBACK_MOBILE;
                    cache.tablet = cache.phone = null;
                }
                else if (phoneSized) {
                    cache.mobile = cache.phone = impl.FALLBACK_PHONE;
                    cache.tablet = null;
                }
                else {
                    cache.mobile = cache.tablet = impl.FALLBACK_TABLET;
                    cache.phone = null;
                }
            }
            else if (impl.isTabletFallback(userAgent)) {
                cache.mobile = cache.tablet = impl.FALLBACK_TABLET;
                cache.phone = null;
            }
            else {
                // not mobile at all!
                cache.mobile = cache.tablet = cache.phone = null;
            }
        };
        // t is a reference to a MobileDetect instance
        impl.mobileGrade = function (t) {
            // impl note:
            // To keep in sync w/ Mobile_Detect.php easily, the following code is tightly aligned to the PHP version.
            // When changes are made in Mobile_Detect.php, copy this method and replace:
            //     $this-> / t.
            //     self::MOBILE_GRADE_(.) / '$1'
            //     , self::VERSION_TYPE_FLOAT / (nothing)
            //     isIOS() / os('iOS')
            //     [reg] / (nothing)   <-- jsdelivr complaining about unescaped unicode character U+00AE
            var $isMobile = t.mobile() !== null;
            if (
            // Apple iOS 3.2-5.1 - Tested on the original iPad (4.3 / 5.0), iPad 2 (4.3), iPad 3 (5.1), original iPhone (3.1), iPhone 3 (3.2), 3GS (4.3), 4 (4.3 / 5.0), and 4S (5.1)
            t.os('iOS') && t.version('iPad') >= 4.3 ||
                t.os('iOS') && t.version('iPhone') >= 3.1 ||
                t.os('iOS') && t.version('iPod') >= 3.1 ||
                // Android 2.1-2.3 - Tested on the HTC Incredible (2.2), original Droid (2.2), HTC Aria (2.1), Google Nexus S (2.3). Functional on 1.5 & 1.6 but performance may be sluggish, tested on Google G1 (1.5)
                // Android 3.1 (Honeycomb)  - Tested on the Samsung Galaxy Tab 10.1 and Motorola XOOM
                // Android 4.0 (ICS)  - Tested on a Galaxy Nexus. Note: transition performance can be poor on upgraded devices
                // Android 4.1 (Jelly Bean)  - Tested on a Galaxy Nexus and Galaxy 7
                (t.version('Android') > 2.1 && t.is('Webkit')) ||
                // Windows Phone 7-7.5 - Tested on the HTC Surround (7.0) HTC Trophy (7.5), LG-E900 (7.5), Nokia Lumia 800
                t.version('Windows Phone OS') >= 7.0 ||
                // Blackberry 7 - Tested on BlackBerry Torch 9810
                // Blackberry 6.0 - Tested on the Torch 9800 and Style 9670
                t.is('BlackBerry') && t.version('BlackBerry') >= 6.0 ||
                // Blackberry Playbook (1.0-2.0) - Tested on PlayBook
                t.match('Playbook.*Tablet') ||
                // Palm WebOS (1.4-2.0) - Tested on the Palm Pixi (1.4), Pre (1.4), Pre 2 (2.0)
                (t.version('webOS') >= 1.4 && t.match('Palm|Pre|Pixi')) ||
                // Palm WebOS 3.0  - Tested on HP TouchPad
                t.match('hp.*TouchPad') ||
                // Firefox Mobile (12 Beta) - Tested on Android 2.3 device
                (t.is('Firefox') && t.version('Firefox') >= 12) ||
                // Chrome for Android - Tested on Android 4.0, 4.1 device
                (t.is('Chrome') && t.is('AndroidOS') && t.version('Android') >= 4.0) ||
                // Skyfire 4.1 - Tested on Android 2.3 device
                (t.is('Skyfire') && t.version('Skyfire') >= 4.1 && t.is('AndroidOS') && t.version('Android') >= 2.3) ||
                // Opera Mobile 11.5-12: Tested on Android 2.3
                (t.is('Opera') && t.version('Opera Mobi') > 11 && t.is('AndroidOS')) ||
                // Meego 1.2 - Tested on Nokia 950 and N9
                t.is('MeeGoOS') ||
                // Tizen (pre-release) - Tested on early hardware
                t.is('Tizen') ||
                // Samsung Bada 2.0 - Tested on a Samsung Wave 3, Dolphin browser
                // @todo: more tests here!
                t.is('Dolfin') && t.version('Bada') >= 2.0 ||
                // UC Browser - Tested on Android 2.3 device
                ((t.is('UC Browser') || t.is('Dolfin')) && t.version('Android') >= 2.3) ||
                // Kindle 3 and Fire  - Tested on the built-in WebKit browser for each
                (t.match('Kindle Fire') ||
                    t.is('Kindle') && t.version('Kindle') >= 3.0) ||
                // Nook Color 1.4.1 - Tested on original Nook Color, not Nook Tablet
                t.is('AndroidOS') && t.is('NookTablet') ||
                // Chrome Desktop 11-21 - Tested on OS X 10.7 and Windows 7
                t.version('Chrome') >= 11 && !$isMobile ||
                // Safari Desktop 4-5 - Tested on OS X 10.7 and Windows 7
                t.version('Safari') >= 5.0 && !$isMobile ||
                // Firefox Desktop 4-13 - Tested on OS X 10.7 and Windows 7
                t.version('Firefox') >= 4.0 && !$isMobile ||
                // Internet Explorer 7-9 - Tested on Windows XP, Vista and 7
                t.version('MSIE') >= 7.0 && !$isMobile ||
                // Opera Desktop 10-12 - Tested on OS X 10.7 and Windows 7
                // @reference: http://my.opera.com/community/openweb/idopera/
                t.version('Opera') >= 10 && !$isMobile) {
                return 'A';
            }
            if (t.os('iOS') && t.version('iPad') < 4.3 ||
                t.os('iOS') && t.version('iPhone') < 3.1 ||
                t.os('iOS') && t.version('iPod') < 3.1 ||
                // Blackberry 5.0: Tested on the Storm 2 9550, Bold 9770
                t.is('Blackberry') && t.version('BlackBerry') >= 5 && t.version('BlackBerry') < 6 ||
                //Opera Mini (5.0-6.5) - Tested on iOS 3.2/4.3 and Android 2.3
                (t.version('Opera Mini') >= 5.0 && t.version('Opera Mini') <= 6.5 &&
                    (t.version('Android') >= 2.3 || t.is('iOS'))) ||
                // Nokia Symbian^3 - Tested on Nokia N8 (Symbian^3), C7 (Symbian^3), also works on N97 (Symbian^1)
                t.match('NokiaN8|NokiaC7|N97.*Series60|Symbian/3') ||
                // @todo: report this (tested on Nokia N71)
                t.version('Opera Mobi') >= 11 && t.is('SymbianOS')) {
                return 'B';
            }
            if (
            // Blackberry 4.x - Tested on the Curve 8330
            t.version('BlackBerry') < 5.0 ||
                // Windows Mobile - Tested on the HTC Leo (WinMo 5.2)
                t.match('MSIEMobile|Windows CE.*Mobile') || t.version('Windows Mobile') <= 5.2) {
                return 'C';
            }
            //All older smartphone platforms and featurephones - Any device that doesn't support media queries
            //will receive the basic, C grade experience.
            return 'C';
        };
        impl.detectOS = function (ua) {
            return impl.findMatch(impl.mobileDetectRules.oss0, ua) ||
                impl.findMatch(impl.mobileDetectRules.oss, ua);
        };
        impl.getDeviceSmallerSide = function () {
            return window.screen.width < window.screen.height ?
                window.screen.width :
                window.screen.height;
        };
        /**
         * Constructor for MobileDetect object.
         * <br>
         * Such an object will keep a reference to the given user-agent string and cache most of the detect queries.<br>
         * <div style="background-color: #d9edf7; border: 1px solid #bce8f1; color: #3a87ad; padding: 14px; border-radius: 2px; margin-top: 20px">
         *     <strong>Find information how to download and install:</strong>
         *     <a href="https://github.com/hgoebl/mobile-detect.js/">github.com/hgoebl/mobile-detect.js/</a>
         * </div>
         *
         * @example <pre>
         *     var md = new MobileDetect(window.navigator.userAgent);
         *     if (md.mobile()) {
         *         location.href = (md.mobileGrade() === 'A') ? '/mobile/' : '/lynx/';
         *     }
         * </pre>
         *
         * @param {string} userAgent typically taken from window.navigator.userAgent or http_header['User-Agent']
         * @param {number} [maxPhoneWidth=600] <strong>only for browsers</strong> specify a value for the maximum
         *        width of smallest device side (in logical "CSS" pixels) until a device detected as mobile will be handled
         *        as phone.
         *        This is only used in cases where the device cannot be classified as phone or tablet.<br>
         *        See <a href="http://developer.android.com/guide/practices/screens_support.html">Declaring Tablet Layouts
         *        for Android</a>.<br>
         *        If you provide a value < 0, then this "fuzzy" check is disabled.
         * @constructor
         * @global
         */
        function MobileDetect(userAgent, maxPhoneWidth) {
            this.ua = userAgent || '';
            this._cache = {};
            //600dp is typical 7" tablet minimum width
            this.maxPhoneWidth = maxPhoneWidth || 600;
        }
        MobileDetect.prototype = {
            constructor: MobileDetect,
            /**
             * Returns the detected phone or tablet type or <tt>null</tt> if it is not a mobile device.
             * <br>
             * For a list of possible return values see {@link MobileDetect#phone} and {@link MobileDetect#tablet}.<br>
             * <br>
             * If the device is not detected by the regular expressions from Mobile-Detect, a test is made against
             * the patterns of <a href="http://detectmobilebrowsers.com/">detectmobilebrowsers.com</a>. If this test
             * is positive, a value of <code>UnknownPhone</code>, <code>UnknownTablet</code> or
             * <code>UnknownMobile</code> is returned.<br>
             * When used in browser, the decision whether phone or tablet is made based on <code>screen.width/height</code>.<br>
             * <br>
             * When used server-side (node.js), there is no way to tell the difference between <code>UnknownTablet</code>
             * and <code>UnknownMobile</code>, so you will get <code>UnknownMobile</code> here.<br>
             * Be aware that since v1.0.0 in this special case you will get <code>UnknownMobile</code> only for:
             * {@link MobileDetect#mobile}, not for {@link MobileDetect#phone} and {@link MobileDetect#tablet}.
             * In versions before v1.0.0 all 3 methods returned <code>UnknownMobile</code> which was tedious to use.
             * <br>
             * In most cases you will use the return value just as a boolean.
             *
             * @returns {String} the key for the phone family or tablet family, e.g. "Nexus".
             * @function MobileDetect#mobile
             */
            mobile: function () {
                impl.prepareDetectionCache(this._cache, this.ua, this.maxPhoneWidth);
                return this._cache.mobile;
            },
            /**
             * Returns the detected phone type/family string or <tt>null</tt>.
             * <br>
             * The returned tablet (family or producer) is one of following keys:<br>
             * <br><tt>iPhone, BlackBerry, HTC, Nexus, Dell, Motorola, Samsung, LG, Sony, Asus,
             * NokiaLumia, Micromax, Palm, Vertu, Pantech, Fly, Wiko, iMobile, SimValley,
             * Wolfgang, Alcatel, Nintendo, Amoi, INQ, GenericPhone</tt><br>
             * <br>
             * If the device is not detected by the regular expressions from Mobile-Detect, a test is made against
             * the patterns of <a href="http://detectmobilebrowsers.com/">detectmobilebrowsers.com</a>. If this test
             * is positive, a value of <code>UnknownPhone</code> or <code>UnknownMobile</code> is returned.<br>
             * When used in browser, the decision whether phone or tablet is made based on <code>screen.width/height</code>.<br>
             * <br>
             * When used server-side (node.js), there is no way to tell the difference between <code>UnknownTablet</code>
             * and <code>UnknownMobile</code>, so you will get <code>null</code> here, while {@link MobileDetect#mobile}
             * will return <code>UnknownMobile</code>.<br>
             * Be aware that since v1.0.0 in this special case you will get <code>UnknownMobile</code> only for:
             * {@link MobileDetect#mobile}, not for {@link MobileDetect#phone} and {@link MobileDetect#tablet}.
             * In versions before v1.0.0 all 3 methods returned <code>UnknownMobile</code> which was tedious to use.
             * <br>
             * In most cases you will use the return value just as a boolean.
             *
             * @returns {String} the key of the phone family or producer, e.g. "iPhone"
             * @function MobileDetect#phone
             */
            phone: function () {
                impl.prepareDetectionCache(this._cache, this.ua, this.maxPhoneWidth);
                return this._cache.phone;
            },
            /**
             * Returns the detected tablet type/family string or <tt>null</tt>.
             * <br>
             * The returned tablet (family or producer) is one of following keys:<br>
             * <br><tt>iPad, NexusTablet, SamsungTablet, Kindle, SurfaceTablet, HPTablet, AsusTablet,
             * BlackBerryTablet, HTCtablet, MotorolaTablet, NookTablet, AcerTablet,
             * ToshibaTablet, LGTablet, FujitsuTablet, PrestigioTablet, LenovoTablet,
             * DellTablet, YarvikTablet, MedionTablet, ArnovaTablet, IntensoTablet, IRUTablet,
             * MegafonTablet, EbodaTablet, AllViewTablet, ArchosTablet, AinolTablet,
             * NokiaLumiaTablet, SonyTablet, PhilipsTablet, CubeTablet, CobyTablet, MIDTablet,
             * MSITablet, SMiTTablet, RockChipTablet, FlyTablet, bqTablet, HuaweiTablet,
             * NecTablet, PantechTablet, BronchoTablet, VersusTablet, ZyncTablet,
             * PositivoTablet, NabiTablet, KoboTablet, DanewTablet, TexetTablet,
             * PlaystationTablet, TrekstorTablet, PyleAudioTablet, AdvanTablet,
             * DanyTechTablet, GalapadTablet, MicromaxTablet, KarbonnTablet, AllFineTablet,
             * PROSCANTablet, YONESTablet, ChangJiaTablet, GUTablet, PointOfViewTablet,
             * OvermaxTablet, HCLTablet, DPSTablet, VistureTablet, CrestaTablet,
             * MediatekTablet, ConcordeTablet, GoCleverTablet, ModecomTablet, VoninoTablet,
             * ECSTablet, StorexTablet, VodafoneTablet, EssentielBTablet, RossMoorTablet,
             * iMobileTablet, TolinoTablet, AudioSonicTablet, AMPETablet, SkkTablet,
             * TecnoTablet, JXDTablet, iJoyTablet, FX2Tablet, XoroTablet, ViewsonicTablet,
             * OdysTablet, CaptivaTablet, IconbitTablet, TeclastTablet, OndaTablet,
             * JaytechTablet, BlaupunktTablet, DigmaTablet, EvolioTablet, LavaTablet,
             * AocTablet, MpmanTablet, CelkonTablet, WolderTablet, MiTablet, NibiruTablet,
             * NexoTablet, LeaderTablet, UbislateTablet, PocketBookTablet, KocasoTablet, Hudl,
             * TelstraTablet, GenericTablet</tt><br>
             * <br>
             * If the device is not detected by the regular expressions from Mobile-Detect, a test is made against
             * the patterns of <a href="http://detectmobilebrowsers.com/">detectmobilebrowsers.com</a>. If this test
             * is positive, a value of <code>UnknownTablet</code> or <code>UnknownMobile</code> is returned.<br>
             * When used in browser, the decision whether phone or tablet is made based on <code>screen.width/height</code>.<br>
             * <br>
             * When used server-side (node.js), there is no way to tell the difference between <code>UnknownTablet</code>
             * and <code>UnknownMobile</code>, so you will get <code>null</code> here, while {@link MobileDetect#mobile}
             * will return <code>UnknownMobile</code>.<br>
             * Be aware that since v1.0.0 in this special case you will get <code>UnknownMobile</code> only for:
             * {@link MobileDetect#mobile}, not for {@link MobileDetect#phone} and {@link MobileDetect#tablet}.
             * In versions before v1.0.0 all 3 methods returned <code>UnknownMobile</code> which was tedious to use.
             * <br>
             * In most cases you will use the return value just as a boolean.
             *
             * @returns {String} the key of the tablet family or producer, e.g. "SamsungTablet"
             * @function MobileDetect#tablet
             */
            tablet: function () {
                impl.prepareDetectionCache(this._cache, this.ua, this.maxPhoneWidth);
                return this._cache.tablet;
            },
            /**
             * Returns the (first) detected user-agent string or <tt>null</tt>.
             * <br>
             * The returned user-agent is one of following keys:<br>
             * <br><tt>Vivaldi, Chrome, Dolfin, Opera, Skyfire, Edge, IE, Firefox, Bolt, TeaShark,
             * Blazer, Safari, Tizen, UCBrowser, baiduboxapp, baidubrowser, DiigoBrowser,
             * Puffin, Mercury, ObigoBrowser, NetFront, GenericBrowser, PaleMoon</tt><br>
             * <br>
             * In most cases calling {@link MobileDetect#userAgent} will be sufficient. But there are rare
             * cases where a mobile device pretends to be more than one particular browser. You can get the
             * list of all matches with {@link MobileDetect#userAgents} or check for a particular value by
             * providing one of the defined keys as first argument to {@link MobileDetect#is}.
             *
             * @returns {String} the key for the detected user-agent or <tt>null</tt>
             * @function MobileDetect#userAgent
             */
            userAgent: function () {
                if (this._cache.userAgent === undefined) {
                    this._cache.userAgent = impl.findMatch(impl.mobileDetectRules.uas, this.ua);
                }
                return this._cache.userAgent;
            },
            /**
             * Returns all detected user-agent strings.
             * <br>
             * The array is empty or contains one or more of following keys:<br>
             * <br><tt>Vivaldi, Chrome, Dolfin, Opera, Skyfire, Edge, IE, Firefox, Bolt, TeaShark,
             * Blazer, Safari, Tizen, UCBrowser, baiduboxapp, baidubrowser, DiigoBrowser,
             * Puffin, Mercury, ObigoBrowser, NetFront, GenericBrowser, PaleMoon</tt><br>
             * <br>
             * In most cases calling {@link MobileDetect#userAgent} will be sufficient. But there are rare
             * cases where a mobile device pretends to be more than one particular browser. You can get the
             * list of all matches with {@link MobileDetect#userAgents} or check for a particular value by
             * providing one of the defined keys as first argument to {@link MobileDetect#is}.
             *
             * @returns {Array} the array of detected user-agent keys or <tt>[]</tt>
             * @function MobileDetect#userAgents
             */
            userAgents: function () {
                if (this._cache.userAgents === undefined) {
                    this._cache.userAgents = impl.findMatches(impl.mobileDetectRules.uas, this.ua);
                }
                return this._cache.userAgents;
            },
            /**
             * Returns the detected operating system string or <tt>null</tt>.
             * <br>
             * The operating system is one of following keys:<br>
             * <br><tt>AndroidOS, BlackBerryOS, PalmOS, SymbianOS, WindowsMobileOS, WindowsPhoneOS,
             * iOS, MeeGoOS, MaemoOS, JavaOS, webOS, badaOS, BREWOS</tt><br>
             *
             * @returns {String} the key for the detected operating system.
             * @function MobileDetect#os
             */
            os: function () {
                if (this._cache.os === undefined) {
                    this._cache.os = impl.detectOS(this.ua);
                }
                return this._cache.os;
            },
            /**
             * Get the version (as Number) of the given property in the User-Agent.
             * <br>
             * Will return a float number. (eg. 2_0 will return 2.0, 4.3.1 will return 4.31)
             *
             * @param {String} key a key defining a thing which has a version.<br>
             *        You can use one of following keys:<br>
             * <br><tt>Mobile, Build, Version, VendorID, iPad, iPhone, iPod, Kindle, Chrome, Coast,
             * Dolfin, Firefox, Fennec, Edge, IE, NetFront, NokiaBrowser, Opera, Opera Mini,
             * Opera Mobi, UC Browser, MQQBrowser, MicroMessenger, baiduboxapp, baidubrowser,
             * Iron, Safari, Skyfire, Tizen, Webkit, PaleMoon, Gecko, Trident, Presto, Goanna,
             * iOS, Android, BlackBerry, BREW, Java, Windows Phone OS, Windows Phone, Windows
             * CE, Windows NT, Symbian, webOS</tt><br>
             *
             * @returns {Number} the version as float or <tt>NaN</tt> if User-Agent doesn't contain this version.
             *          Be careful when comparing this value with '==' operator!
             * @function MobileDetect#version
             */
            version: function (key) {
                return impl.getVersion(key, this.ua);
            },
            /**
             * Get the version (as String) of the given property in the User-Agent.
             * <br>
             *
             * @param {String} key a key defining a thing which has a version.<br>
             *        You can use one of following keys:<br>
             * <br><tt>Mobile, Build, Version, VendorID, iPad, iPhone, iPod, Kindle, Chrome, Coast,
             * Dolfin, Firefox, Fennec, Edge, IE, NetFront, NokiaBrowser, Opera, Opera Mini,
             * Opera Mobi, UC Browser, MQQBrowser, MicroMessenger, baiduboxapp, baidubrowser,
             * Iron, Safari, Skyfire, Tizen, Webkit, PaleMoon, Gecko, Trident, Presto, Goanna,
             * iOS, Android, BlackBerry, BREW, Java, Windows Phone OS, Windows Phone, Windows
             * CE, Windows NT, Symbian, webOS</tt><br>
             *
             * @returns {String} the "raw" version as String or <tt>null</tt> if User-Agent doesn't contain this version.
             *
             * @function MobileDetect#versionStr
             */
            versionStr: function (key) {
                return impl.getVersionStr(key, this.ua);
            },
            /**
             * Global test key against userAgent, os, phone, tablet and some other properties of userAgent string.
             *
             * @param {String} key the key (case-insensitive) of a userAgent, an operating system, phone or
             *        tablet family.<br>
             *        For a complete list of possible values, see {@link MobileDetect#userAgent},
             *        {@link MobileDetect#os}, {@link MobileDetect#phone}, {@link MobileDetect#tablet}.<br>
             *        Additionally you have following keys:<br>
             * <br><tt>Bot, MobileBot, DesktopMode, TV, WebKit, Console, Watch</tt><br>
             *
             * @returns {boolean} <tt>true</tt> when the given key is one of the defined keys of userAgent, os, phone,
             *                    tablet or one of the listed additional keys, otherwise <tt>false</tt>
             * @function MobileDetect#is
             */
            is: function (key) {
                return containsIC(this.userAgents(), key) ||
                    equalIC(key, this.os()) ||
                    equalIC(key, this.phone()) ||
                    equalIC(key, this.tablet()) ||
                    containsIC(impl.findMatches(impl.mobileDetectRules.utils, this.ua), key);
            },
            /**
             * Do a quick test against navigator::userAgent.
             *
             * @param {String|RegExp} pattern the pattern, either as String or RegExp
             *                        (a string will be converted to a case-insensitive RegExp).
             * @returns {boolean} <tt>true</tt> when the pattern matches, otherwise <tt>false</tt>
             * @function MobileDetect#match
             */
            match: function (pattern) {
                if (!(pattern instanceof RegExp)) {
                    pattern = new RegExp(pattern, 'i');
                }
                return pattern.test(this.ua);
            },
            /**
             * Checks whether the mobile device can be considered as phone regarding <code>screen.width</code>.
             * <br>
             * Obviously this method makes sense in browser environments only (not for Node.js)!
             * @param {number} [maxPhoneWidth] the maximum logical pixels (aka. CSS-pixels) to be considered as phone.<br>
             *        The argument is optional and if not present or falsy, the value of the constructor is taken.
             * @returns {boolean|undefined} <code>undefined</code> if screen size wasn't detectable, else <code>true</code>
             *          when screen.width is less or equal to maxPhoneWidth, otherwise <code>false</code>.<br>
             *          Will always return <code>undefined</code> server-side.
             */
            isPhoneSized: function (maxPhoneWidth) {
                return MobileDetect.isPhoneSized(maxPhoneWidth || this.maxPhoneWidth);
            },
            /**
             * Returns the mobile grade ('A', 'B', 'C').
             *
             * @returns {String} one of the mobile grades ('A', 'B', 'C').
             * @function MobileDetect#mobileGrade
             */
            mobileGrade: function () {
                if (this._cache.grade === undefined) {
                    this._cache.grade = impl.mobileGrade(this);
                }
                return this._cache.grade;
            }
        };
        // environment-dependent
        if (typeof window !== 'undefined' && window.screen) {
            MobileDetect.isPhoneSized = function (maxPhoneWidth) {
                return maxPhoneWidth < 0 ? undefined : impl.getDeviceSmallerSide() <= maxPhoneWidth;
            };
        }
        else {
            MobileDetect.isPhoneSized = function () { };
        }
        // should not be replaced by a completely new object - just overwrite existing methods
        MobileDetect._impl = impl;
        MobileDetect.version = '1.3.3 2016-07-31';
        return MobileDetect;
    }); // end of call of define()
})((function (undefined) {
    if (typeof module !== 'undefined' && module.exports) {
        return function (factory) { module.exports = factory(); };
    }
    else if (typeof define === 'function' && define.amd) {
        return define;
    }
    else if (typeof window !== 'undefined') {
        return function (factory) { window.MobileDetect = factory(); };
    }
    else {
        // please file a bug if you get this error!
        throw new Error('unknown environment');
    }
})());
//# sourceMappingURL=mobile-detect.js.map 
//# sourceMappingURL=mobile-detect.js.map 
//# sourceMappingURL=mobile-detect.js.map 
//# sourceMappingURL=mobile-detect.js.map 
//# sourceMappingURL=mobile-detect.js.map;
/*

notie - a clean and simple notification suite for javascript, with no dependencies

Copyright (c) 2016 Jared Reich

Licensed under the MIT license:
http://www.opensource.org/licenses/mit-license.php

Project demo:
https://jaredreich.com/projects/notie

*/
var notie = function () {
    // Default options
    var options = {
        colorSuccess: '',
        colorWarning: '',
        colorError: '',
        colorInfo: '',
        colorNeutral: '',
        colorText: '',
        dateMonths: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
        animationDelay: 300,
        backgroundClickDismiss: true
    };
    function setOptions(customOptions) {
        // Custom options
        for (var key in customOptions) {
            options[key] = customOptions[key];
        }
    }
    // alert
    // **************
    // create alert container
    var alertOuter = document.createElement('div');
    alertOuter.id = 'notie-alert-outer';
    // Hide alert on click
    alertOuter.onclick = function () {
        alertHide();
    };
    // add alert to body
    document.body.appendChild(alertOuter);
    // create alert inner container
    var alertInner = document.createElement('div');
    alertInner.id = 'notie-alert-inner';
    alertOuter.appendChild(alertInner);
    // create alert content container
    var alertContent = document.createElement('div');
    alertContent.id = 'notie-alert-content';
    alertInner.appendChild(alertContent);
    // Initialize alert text
    var alertText = document.createElement('span');
    alertText.id = 'notie-alert-text';
    alertContent.appendChild(alertText);
    // alert helper variables
    var alertIsShowing = false;
    var alertTimeout1;
    var alertTimeout2;
    var wasClickedCounter = 0;
    function alert(type, message, seconds) {
        if (options.colorText.length > 0)
            alertText.style.color = options.colorText;
        blur();
        wasClickedCounter++;
        setTimeout(function () {
            wasClickedCounter--;
        }, (options.animationDelay + 10));
        if (wasClickedCounter === 1) {
            if (alertIsShowing) {
                alertHide(function () {
                    alertShow(type, message, seconds);
                });
            }
            else {
                alertShow(type, message, seconds);
            }
        }
    }
    function alertShow(type, message, seconds) {
        alertIsShowing = true;
        var duration = 0;
        if (typeof seconds === 'undefined' || seconds === 0) {
            duration = 86400000;
        }
        else if (seconds > 0 && seconds < 1) {
            duration = 1000;
        }
        else {
            duration = seconds * 1000;
        }
        // Remove all color classes first
        removeClass(alertOuter, 'notie-background-success');
        removeClass(alertOuter, 'notie-background-warning');
        removeClass(alertOuter, 'notie-background-error');
        removeClass(alertOuter, 'notie-background-info');
        // Set notie type (background color)
        switch (type) {
            case 1:
            case 'success':
                if (options.colorSuccess.length > 0)
                    alertOuter.style.backgroundColor = options.colorSuccess;
                else
                    addClass(alertOuter, 'notie-background-success');
                break;
            case 2:
            case 'warning':
                if (options.colorWarning.length > 0)
                    alertOuter.style.backgroundColor = options.colorWarning;
                else
                    addClass(alertOuter, 'notie-background-warning');
                break;
            case 3:
            case 'error':
                if (options.colorError.length > 0)
                    alertOuter.style.backgroundColor = options.colorError;
                else
                    addClass(alertOuter, 'notie-background-error');
                break;
            case 4:
            case 'info':
                if (options.colorInfo.length > 0)
                    alertOuter.style.backgroundColor = options.colorInfo;
                else
                    addClass(alertOuter, 'notie-background-info');
                break;
        }
        // Set notie text
        alertText.innerHTML = message;
        alertOuter.style.top = '-10000px';
        alertOuter.style.display = 'table';
        alertOuter.style.top = '-' + alertOuter.offsetHeight - 5 + 'px';
        alertTimeout1 = setTimeout(function () {
            addClass(alertOuter, 'notie-transition');
            alertOuter.style.top = 0;
            alertTimeout2 = setTimeout(function () {
                alertHide(function () {
                    // Nothing
                });
            }, duration);
        }, 20);
    }
    function alertHide(callback) {
        clearTimeout(alertTimeout1);
        clearTimeout(alertTimeout2);
        alertOuter.style.top = '-' + alertOuter.offsetHeight - 5 + 'px';
        setTimeout(function () {
            removeClass(alertOuter, 'notie-transition');
            alertOuter.style.top = '-10000px';
            alertIsShowing = false;
            if (callback)
                callback();
        }, (options.animationDelay + 10));
    }
    // force
    // **************
    var forceOuter = document.createElement('div');
    forceOuter.id = 'notie-force-outer';
    var forceInner = document.createElement('div');
    forceInner.id = 'notie-force-inner';
    forceOuter.appendChild(forceInner);
    var forceText = document.createElement('span');
    forceText.id = 'notie-force-text';
    forceInner.appendChild(forceText);
    var forceButton = document.createElement('div');
    forceButton.id = 'notie-force-button';
    forceOuter.appendChild(forceButton);
    var forceBackground = document.createElement('div');
    forceBackground.id = 'notie-force-background';
    addClass(forceBackground, 'notie-transition');
    // Attach force elements to the body element
    document.body.appendChild(forceOuter);
    document.body.appendChild(forceBackground);
    // force helper variables
    var forceIsShowing = false;
    function force(type, message, buttonText, callback) {
        if (options.colorText.length > 0) {
            forceText.style.color = options.colorText;
            forceButton.style.color = options.colorText;
        }
        blur();
        if (alertIsShowing) {
            // Hide notie.alert
            alertHide(function () {
                forceShow(type, message, buttonText, callback);
            });
        }
        else {
            forceShow(type, message, buttonText, callback);
        }
    }
    function forceShow(type, message, buttonText, callback) {
        scrollDisable();
        // Callback function
        forceButton.onclick = function () {
            forceHide();
            if (callback) {
                setTimeout(function () {
                    callback();
                }, (options.animationDelay + 10));
            }
        };
        // Remove all color classes first
        removeClass(forceOuter, 'notie-background-success');
        removeClass(forceOuter, 'notie-background-warning');
        removeClass(forceOuter, 'notie-background-error');
        removeClass(forceOuter, 'notie-background-info');
        // Set notie type (background color)
        switch (type) {
            case 1:
            case 'success':
                if (options.colorSuccess.length > 0)
                    forceOuter.style.backgroundColor = options.colorSuccess;
                else
                    addClass(forceOuter, 'notie-background-success');
                break;
            case 2:
            case 'warning':
                if (options.colorWarning.length > 0)
                    forceOuter.style.backgroundColor = options.colorWarning;
                else
                    addClass(forceOuter, 'notie-background-warning');
                break;
            case 3:
            case 'error':
                if (options.colorError.length > 0)
                    forceOuter.style.backgroundColor = options.colorError;
                else
                    addClass(forceOuter, 'notie-background-error');
                break;
            case 4:
            case 'info':
                if (options.colorInfo.length > 0)
                    forceOuter.style.backgroundColor = options.colorInfo;
                else
                    addClass(forceOuter, 'notie-background-info');
                break;
        }
        function forceShowInner() {
            // Set force text
            forceText.innerHTML = message;
            forceButton.innerHTML = buttonText;
            // Get force's height
            forceOuter.style.top = '-10000px';
            forceOuter.style.display = 'table';
            forceOuter.style.top = '-' + forceOuter.offsetHeight - 5 + 'px';
            forceBackground.style.display = 'block';
            setTimeout(function () {
                addClass(forceOuter, 'notie-transition');
                forceOuter.style.top = 0;
                forceBackground.style.opacity = '0.75';
                setTimeout(function () {
                    forceIsShowing = true;
                }, (options.animationDelay + 10));
            }, 20);
        }
        if (forceIsShowing) {
            forceHide();
            setTimeout(function () {
                forceShowInner();
            }, (options.animationDelay + 10));
        }
        else {
            forceShowInner();
        }
    }
    function forceHide() {
        forceOuter.style.top = '-' + forceOuter.offsetHeight - 5 + 'px';
        forceBackground.style.opacity = '0';
        setTimeout(function () {
            removeClass(forceOuter, 'notie-transition');
            forceOuter.style.top = '-10000px';
            forceBackground.style.display = 'none';
            scrollEnable();
            forceIsShowing = false;
        }, (options.animationDelay + 10));
    }
    // confirm
    // **************
    var confirmOuter = document.createElement('div');
    confirmOuter.id = 'notie-confirm-outer';
    var confirmInner = document.createElement('div');
    confirmInner.id = 'notie-confirm-inner';
    confirmOuter.appendChild(confirmInner);
    var confirmText = document.createElement('span');
    confirmText.id = 'notie-confirm-text';
    confirmInner.appendChild(confirmText);
    var confirmYes = document.createElement('div');
    confirmYes.id = 'notie-confirm-yes';
    confirmOuter.appendChild(confirmYes);
    var confirmNo = document.createElement('div');
    confirmNo.id = 'notie-confirm-no';
    confirmOuter.appendChild(confirmNo);
    var confirmTextYes = document.createElement('span');
    confirmTextYes.id = 'notie-confirm-text-yes';
    confirmYes.appendChild(confirmTextYes);
    var confirmTextNo = document.createElement('span');
    confirmTextNo.id = 'notie-confirm-text-no';
    confirmNo.appendChild(confirmTextNo);
    var confirmBackground = document.createElement('div');
    confirmBackground.id = 'notie-confirm-background';
    addClass(confirmBackground, 'notie-transition');
    // Hide notie.confirm on no click and background click
    confirmBackground.onclick = function () {
        if (options.backgroundClickDismiss) {
            confirmHide();
        }
    };
    // Attach confirm elements to the body element
    document.body.appendChild(confirmOuter);
    document.body.appendChild(confirmBackground);
    // confirm helper variables
    var confirmIsShowing = false;
    function confirm(title, yesText, noText, yesCallback, noCallback) {
        if (options.colorInfo.length > 0)
            confirmInner.style.backgroundColor = options.colorInfo;
        if (options.colorSuccess.length > 0)
            confirmYes.style.backgroundColor = options.colorSuccess;
        if (options.colorError.length > 0)
            confirmNo.style.backgroundColor = options.colorError;
        if (options.colorText.length > 0) {
            confirmText.style.color = options.colorText;
            confirmTextYes.style.color = options.colorText;
            confirmTextNo.style.color = options.colorText;
        }
        blur();
        if (alertIsShowing) {
            // Hide notie.alert
            alertHide(function () {
                confirmShow(title, yesText, noText, yesCallback, noCallback);
            });
        }
        else {
            confirmShow(title, yesText, noText, yesCallback, noCallback);
        }
    }
    function confirmShow(title, yesText, noText, yesCallback, noCallback) {
        scrollDisable();
        // Yes callback function
        confirmYes.onclick = function () {
            confirmHide();
            if (yesCallback) {
                setTimeout(function () {
                    yesCallback();
                }, (options.animationDelay + 10));
            }
        };
        // No callback function
        confirmNo.onclick = function () {
            confirmHide();
            if (noCallback) {
                setTimeout(function () {
                    noCallback();
                }, (options.animationDelay + 10));
            }
        };
        function confirmShowInner() {
            // Set confirm text
            confirmText.innerHTML = title;
            confirmTextYes.innerHTML = yesText;
            confirmTextNo.innerHTML = noText;
            // Get confirm's height
            confirmOuter.style.top = '-10000px';
            confirmOuter.style.display = 'table';
            confirmOuter.style.top = '-' + confirmOuter.offsetHeight - 5 + 'px';
            confirmBackground.style.display = 'block';
            setTimeout(function () {
                addClass(confirmOuter, 'notie-transition');
                confirmOuter.style.top = 0;
                confirmBackground.style.opacity = '0.75';
                setTimeout(function () {
                    confirmIsShowing = true;
                }, (options.animationDelay + 10));
            }, 20);
        }
        if (confirmIsShowing) {
            confirmHide();
            setTimeout(function () {
                confirmShowInner();
            }, (options.animationDelay + 10));
        }
        else {
            confirmShowInner();
        }
    }
    function confirmHide() {
        confirmOuter.style.top = '-' + confirmOuter.offsetHeight - 5 + 'px';
        confirmBackground.style.opacity = '0';
        setTimeout(function () {
            removeClass(confirmOuter, 'notie-transition');
            confirmOuter.style.top = '-10000px';
            confirmBackground.style.display = 'none';
            scrollEnable();
            confirmIsShowing = false;
        }, (options.animationDelay + 10));
    }
    // input
    // **********
    var inputOuter = document.createElement('div');
    inputOuter.id = 'notie-input-outer';
    var inputBackground = document.createElement('div');
    inputBackground.id = 'notie-input-background';
    addClass(inputBackground, 'notie-transition');
    var inputInner = document.createElement('div');
    inputInner.id = 'notie-input-inner';
    inputOuter.appendChild(inputInner);
    var inputField = document.createElement('input');
    inputField.id = 'notie-input-field';
    inputOuter.appendChild(inputField);
    var inputYes = document.createElement('div');
    inputYes.id = 'notie-input-yes';
    inputOuter.appendChild(inputYes);
    var inputNo = document.createElement('div');
    inputNo.id = 'notie-input-no';
    inputOuter.appendChild(inputNo);
    var inputText = document.createElement('span');
    inputText.id = 'notie-input-text';
    inputInner.appendChild(inputText);
    var inputTextYes = document.createElement('span');
    inputTextYes.id = 'notie-input-text-yes';
    inputYes.appendChild(inputTextYes);
    var inputTextNo = document.createElement('span');
    inputTextNo.id = 'notie-input-text-no';
    inputNo.appendChild(inputTextNo);
    // Attach input elements to the body element
    document.body.appendChild(inputOuter);
    document.body.appendChild(inputBackground);
    // Hide input on no click and background click
    inputBackground.onclick = function () {
        if (options.backgroundClickDismiss) {
            inputHide();
        }
    };
    // input helper variables
    var inputIsShowing = false;
    function input(settings, title, submitText, cancelText, submitCallback, cancelCallback) {
        if (options.colorInfo.length > 0)
            inputInner.style.backgroundColor = options.colorInfo;
        if (options.colorSuccess.length > 0)
            inputYes.style.backgroundColor = options.colorSuccess;
        if (options.colorError.length > 0)
            inputNo.style.backgroundColor = options.colorError;
        if (options.colorText.length > 0) {
            inputText.style.color = options.colorText;
            inputTextYes.style.color = options.colorText;
            inputTextNo.style.color = options.colorText;
        }
        blur();
        inputField.setAttribute('autocapitalize', settings.autocapitalize || 'none');
        inputField.setAttribute('autocomplete', settings.autocomplete || 'off');
        inputField.setAttribute('autocorrect', settings.autocorrect || 'off');
        inputField.setAttribute('autofocus', settings.autofocus || 'true');
        inputField.setAttribute('inputmode', settings.inputmode || 'verbatim');
        inputField.setAttribute('max', settings.max || '');
        inputField.setAttribute('maxlength', settings.maxlength || '');
        inputField.setAttribute('min', settings.min || '');
        inputField.setAttribute('minlength', settings.minlength || '');
        inputField.setAttribute('placeholder', settings.placeholder || '');
        inputField.setAttribute('spellcheck', settings.spellcheck || 'default');
        inputField.setAttribute('step', settings.step || 'any');
        inputField.setAttribute('type', settings.type || 'text');
        inputField.value = settings.prefilledValue || '';
        // As-you-type input restrictions
        if (settings.allowed) {
            inputField.oninput = function () {
                if (Array.isArray(settings.allowed)) {
                    var regexString = '';
                    var allowed = settings.allowed;
                    for (var i = 0; i < allowed.length; i++) {
                        if (allowed[i] === 'an') {
                            regexString += '0-9a-zA-Z';
                        }
                        else if (allowed[i] === 'a') {
                            regexString += 'a-zA-Z';
                        }
                        else if (allowed[i] === 'n') {
                            regexString += '0-9';
                        }
                        if (allowed[i] === 'sp') {
                            regexString += ' ';
                        }
                    }
                    var regex = new RegExp('[^' + regexString + ']', 'g');
                }
                else if (typeof settings.allowed === 'object') {
                    regex = settings.allowed;
                }
                inputField.value = inputField.value.replace(regex, '');
            };
        }
        else {
            inputField.oninput = function () {
                return true;
            };
        }
        if (alertIsShowing) {
            // Hide alert
            alertHide(function () {
                inputShow(title, submitText, cancelText, submitCallback, cancelCallback);
            });
        }
        else {
            inputShow(title, submitText, cancelText, submitCallback, cancelCallback);
        }
    }
    function inputShow(title, submitText, cancelText, submitCallback, cancelCallback) {
        scrollDisable();
        // Yes callback function
        inputYes.onclick = function () {
            inputHide();
            if (submitCallback) {
                setTimeout(function () {
                    submitCallback(inputField.value);
                }, (options.animationDelay + 10));
            }
        };
        // No callback function
        inputNo.onclick = function () {
            inputHide();
            if (cancelCallback) {
                setTimeout(function () {
                    cancelCallback(inputField.value);
                }, (options.animationDelay + 10));
            }
        };
        function inputShowInner() {
            // Set input text
            inputText.innerHTML = title;
            inputTextYes.innerHTML = submitText;
            inputTextNo.innerHTML = cancelText;
            // Get input's height
            inputOuter.style.top = '-10000px';
            inputOuter.style.display = 'table';
            inputOuter.style.top = '-' + inputOuter.offsetHeight - 5 + 'px';
            inputBackground.style.display = 'block';
            setTimeout(function () {
                addClass(inputOuter, 'notie-transition');
                inputOuter.style.top = 0;
                inputBackground.style.opacity = '0.75';
                setTimeout(function () {
                    inputIsShowing = true;
                    // put focus on input field
                    inputField.focus();
                }, (options.animationDelay + 10));
            }, 20);
        }
        if (inputIsShowing) {
            inputHide();
            setTimeout(function () {
                inputShowInner();
            }, (options.animationDelay + 10));
        }
        else {
            inputShowInner();
        }
    }
    function inputHide() {
        inputOuter.style.top = '-' + inputOuter.offsetHeight - 5 + 'px';
        inputBackground.style.opacity = '0';
        setTimeout(function () {
            removeClass(inputOuter, 'notie-transition');
            inputBackground.style.display = 'none';
            inputOuter.style.top = '-10000px';
            scrollEnable();
            inputIsShowing = false;
        }, (options.animationDelay + 10));
    }
    // select
    // **************
    var selectOuter = document.createElement('div');
    selectOuter.id = 'notie-select-outer';
    var selectInner = document.createElement('div');
    selectInner.id = 'notie-select-inner';
    selectOuter.appendChild(selectInner);
    var selectText = document.createElement('span');
    selectText.id = 'notie-select-text';
    selectInner.appendChild(selectText);
    var selectBackground = document.createElement('div');
    selectBackground.id = 'notie-select-background';
    addClass(selectBackground, 'notie-transition');
    var selectChoices = document.createElement('div');
    selectChoices.id = 'notie-select-choices';
    selectOuter.appendChild(selectChoices);
    var selectCancel = document.createElement('div');
    selectCancel.id = 'notie-select-cancel';
    selectOuter.appendChild(selectCancel);
    // Attach select elements to the body element
    document.body.appendChild(selectOuter);
    document.body.appendChild(selectBackground);
    // Hide input on no click and background click
    selectBackground.onclick = function () {
        if (options.backgroundClickDismiss) {
            selectHide();
        }
    };
    selectCancel.onclick = function () {
        selectHide();
    };
    // select helper variables
    var selectIsShowing = false;
    function select(title, cancelText, choices) {
        if (options.colorInfo.length > 0)
            selectInner.style.backgroundColor = options.colorInfo;
        if (options.colorNeutral.length > 0)
            selectCancel.style.backgroundColor = options.colorNeutral;
        if (options.colorText.length > 0) {
            selectText.style.color = options.colorText;
            selectCancel.style.color = options.colorText;
        }
        blur();
        if (alertIsShowing) {
            // Hide notie.alert
            alertHide(function () {
                selectShow(title, cancelText, choices);
            });
        }
        else {
            selectShow(title, cancelText, choices);
        }
    }
    function selectShow(title, cancelText, choices) {
        scrollDisable();
        document.getElementById('notie-select-choices').innerHTML = '';
        selectCancel.innerHTML = cancelText;
        var selectChoicePrevious;
        for (var i = 0; i < choices.length; i++) {
            var selectChoice = document.createElement('div');
            selectChoice.innerHTML = choices[i].title;
            addClass(selectChoice, 'notie-select-choice');
            selectChoices.appendChild(selectChoice);
            if (options.colorText.length > 0)
                selectChoice.style.color = options.colorText;
            if (choices[i].type) {
                switch (choices[i].type) {
                    case 1:
                        if (options.colorSuccess.length > 0)
                            selectChoice.style.backgroundColor = options.colorSuccess;
                        else
                            addClass(selectChoice, 'notie-background-success');
                        break;
                    case 2:
                        if (options.colorWarning.length > 0)
                            selectChoice.style.backgroundColor = options.colorWarning;
                        else
                            addClass(selectChoice, 'notie-background-warning');
                        break;
                    case 3:
                        if (options.colorError.length > 0)
                            selectChoice.style.backgroundColor = options.colorError;
                        else
                            addClass(selectChoice, 'notie-background-error');
                        break;
                    case 4:
                        if (options.colorInfo.length > 0)
                            selectChoice.style.backgroundColor = options.colorInfo;
                        else
                            addClass(selectChoice, 'notie-background-info');
                        break;
                }
            }
            else if (choices[i].color) {
                selectChoice.style.backgroundColor = choices[i].color;
            }
            selectChoice.style.backgroundColor = window.getComputedStyle(selectChoice).backgroundColor;
            if (i > 0 && selectChoice.style.backgroundColor === selectChoicePrevious.style.backgroundColor) {
                addClass(selectChoicePrevious, 'notie-select-choice-bottom-border');
            }
            // onclick for this choice
            if (choices[i].handler) {
                selectChoice.onclick = (function (i) {
                    return function () {
                        selectHide();
                        setTimeout(function () {
                            choices[i].handler();
                        }, (options.animationDelay + 10));
                    };
                })(i);
            }
            else {
                throw new Error('notie.select choice "' + selectChoice.title + '" must have a handler');
            }
            selectChoicePrevious = selectChoice;
        }
        function selectShowInner(title) {
            // Set select text
            selectText.innerHTML = title;
            // Get select's height
            selectOuter.style.bottom = '-10000px';
            selectOuter.style.display = 'table';
            selectOuter.style.bottom = '-' + selectOuter.offsetHeight - 5 + 'px';
            selectBackground.style.display = 'block';
            setTimeout(function () {
                addClass(selectOuter, 'notie-transition');
                selectOuter.style.bottom = 0;
                selectBackground.style.opacity = '0.75';
                setTimeout(function () {
                    selectIsShowing = true;
                }, (options.animationDelay + 10));
            }, 20);
        }
        if (selectIsShowing) {
            selectHide();
            setTimeout(function () {
                selectShowInner(title);
            }, (options.animationDelay + 10));
        }
        else {
            selectShowInner(title);
        }
    }
    function selectHide() {
        selectOuter.style.bottom = '-' + selectOuter.offsetHeight - 5 + 'px';
        selectBackground.style.opacity = '0';
        setTimeout(function () {
            removeClass(selectOuter, 'notie-transition');
            selectOuter.style.bottom = '-10000px';
            selectBackground.style.display = 'none';
            scrollEnable();
            selectIsShowing = false;
        }, (options.animationDelay + 10));
    }
    function isShowing() {
        return alertIsShowing || confirmIsShowing || inputIsShowing || selectIsShowing || dateIsShowing;
    }
    // date
    // **************
    var dateOuter = document.createElement('div');
    dateOuter.id = 'notie-date-outer';
    var dateSelector = document.createElement('div');
    dateSelector.id = 'notie-date-selector';
    dateOuter.appendChild(dateSelector);
    var dateInner = document.createElement('div');
    dateInner.id = 'notie-date-inner';
    dateOuter.appendChild(dateInner);
    var dateUpArrow = '<div class="notie-date-arrow-up"></div>';
    var dateDownArrow = '<div class="notie-date-arrow-down"></div>';
    var dateUpMonth = document.createElement('div');
    dateUpMonth.className = 'notie-date-up';
    dateUpMonth.innerHTML = dateUpArrow;
    dateSelector.appendChild(dateUpMonth);
    dateUpMonth.onclick = dateUpMonthClick;
    var dateUpDay = document.createElement('div');
    dateUpDay.className = 'notie-date-up';
    dateUpDay.innerHTML = dateUpArrow;
    dateSelector.appendChild(dateUpDay);
    dateUpDay.onclick = dateUpDayClick;
    var dateUpYear = document.createElement('div');
    dateUpYear.className = 'notie-date-up';
    dateUpYear.innerHTML = dateUpArrow;
    dateSelector.appendChild(dateUpYear);
    dateUpYear.onclick = dateUpYearClick;
    var dateMonth = document.createElement('div');
    dateMonth.className = 'notie-date-text';
    dateSelector.appendChild(dateMonth);
    var dateDay = document.createElement('div');
    dateDay.className = 'notie-date-text';
    dateSelector.appendChild(dateDay);
    var dateYear = document.createElement('div');
    dateYear.className = 'notie-date-text';
    dateSelector.appendChild(dateYear);
    var dateDownMonth = document.createElement('div');
    dateDownMonth.className = 'notie-date-down';
    dateDownMonth.innerHTML = dateDownArrow;
    dateSelector.appendChild(dateDownMonth);
    dateDownMonth.onclick = dateDownMonthClick;
    var dateDownDay = document.createElement('div');
    dateDownDay.className = 'notie-date-down';
    dateDownDay.innerHTML = dateDownArrow;
    dateSelector.appendChild(dateDownDay);
    dateDownDay.onclick = dateDownDayClick;
    var dateDownYear = document.createElement('div');
    dateDownYear.className = 'notie-date-down';
    dateDownYear.innerHTML = dateDownArrow;
    dateSelector.appendChild(dateDownYear);
    dateDownYear.onclick = dateDownYearClick;
    var dateYes = document.createElement('div');
    dateYes.id = 'notie-date-yes';
    dateInner.appendChild(dateYes);
    var dateNo = document.createElement('div');
    dateNo.id = 'notie-date-no';
    dateInner.appendChild(dateNo);
    var dateBackground = document.createElement('div');
    dateBackground.id = 'notie-date-background';
    addClass(dateBackground, 'notie-transition');
    // Hide notie.date on no click and background click
    dateBackground.onclick = function () {
        if (options.backgroundClickDismiss) {
            dateHide();
        }
    };
    // Attach date elements to the body element
    document.body.appendChild(dateOuter);
    document.body.appendChild(dateBackground);
    // date helper variables
    var dateIsShowing = false;
    var dateSelected;
    function date(dateOptions) {
        if (options.colorInfo.length > 0) {
            dateInner.style.backgroundColor = options.colorInfo;
        }
        if (options.colorSuccess.length > 0)
            dateYes.style.backgroundColor = options.colorSuccess;
        if (options.colorError.length > 0)
            dateNo.style.backgroundColor = options.colorError;
        if (options.colorText.length > 0)
            dateInner.style.color = options.colorText;
        blur();
        if (alertIsShowing) {
            // Hide notie.alert
            alertHide(function () {
                dateShow(dateOptions);
            });
        }
        else {
            dateShow(dateOptions);
        }
    }
    function dateShow(dateOptions) {
        scrollDisable();
        // Yes callback function
        dateYes.onclick = function () {
            dateHide();
            if (dateOptions.yesCallback) {
                setTimeout(function () {
                    dateOptions.yesCallback(dateSelected);
                }, (options.animationDelay + 10));
            }
        };
        // No callback function
        dateNo.onclick = function () {
            dateHide();
            if (dateOptions.noCallback) {
                setTimeout(function () {
                    dateOptions.noCallback(dateSelected);
                }, (options.animationDelay + 10));
            }
        };
        function dateShowInner() {
            dateSelected = dateOptions.initial || new Date();
            dateSet(dateSelected);
            dateYes.innerHTML = dateOptions.yesText || 'OK';
            dateNo.innerHTML = dateOptions.noText || 'Cancel';
            // Get dates's height
            dateOuter.style.top = '-10000px';
            dateOuter.style.display = 'table';
            dateOuter.style.top = '-' + dateOuter.offsetHeight - 5 + 'px';
            dateBackground.style.display = 'block';
            setTimeout(function () {
                addClass(dateOuter, 'notie-transition');
                dateOuter.style.top = 0;
                dateBackground.style.opacity = '0.75';
                setTimeout(function () {
                    dateIsShowing = true;
                }, (options.animationDelay + 10));
            }, 20);
        }
        if (dateIsShowing) {
            dateHide();
            setTimeout(function () {
                dateShowInner();
            }, (options.animationDelay + 10));
        }
        else {
            dateShowInner();
        }
    }
    function dateSet(date) {
        dateMonth.innerHTML = options.dateMonths[date.getMonth()];
        dateDay.innerHTML = date.getDate();
        dateYear.innerHTML = date.getFullYear();
    }
    function dateUpMonthClick() {
        dateSelected.setMonth(dateSelected.getMonth() - 1);
        dateSet(dateSelected);
    }
    function dateDownMonthClick() {
        dateSelected.setMonth(dateSelected.getMonth() + 1);
        dateSet(dateSelected);
    }
    function dateUpDayClick() {
        dateSelected.setDate(dateSelected.getDate() - 1);
        dateSet(dateSelected);
    }
    function dateDownDayClick() {
        dateSelected.setDate(dateSelected.getDate() + 1);
        dateSet(dateSelected);
    }
    function dateUpYearClick() {
        dateSelected.setFullYear(dateSelected.getFullYear() - 1);
        dateSet(dateSelected);
    }
    function dateDownYearClick() {
        dateSelected.setFullYear(dateSelected.getFullYear() + 1);
        dateSet(dateSelected);
    }
    function dateHide() {
        dateOuter.style.top = '-' + dateOuter.offsetHeight - 5 + 'px';
        dateBackground.style.opacity = '0';
        setTimeout(function () {
            removeClass(dateOuter, 'notie-transition');
            dateOuter.style.top = '-10000px';
            dateBackground.style.display = 'none';
            scrollEnable();
            dateIsShowing = false;
        }, (options.animationDelay + 10));
    }
    // Internal helper functions
    // #################
    function addClass(element, className) {
        if (element.classList) {
            element.classList.add(className);
        }
        else {
            element.className += ' ' + className;
        }
    }
    function removeClass(element, className) {
        if (element.classList) {
            element.classList.remove(className);
        }
        else {
            element.className = element.className.replace(new RegExp('(^|\\b)' + className.split(' ').join('|') + '(\\b|$)', 'gi'), ' ');
        }
    }
    function blur() {
        document.activeElement && document.activeElement.blur();
    }
    var originalBodyHeight, originalBodyOverflow;
    function scrollDisable() {
        originalBodyHeight = document.body.style.height;
        originalBodyOverflow = document.body.style.overflow;
        document.body.style.height = '100%';
        document.body.style.overflow = 'hidden';
    }
    function scrollEnable() {
        document.body.style.height = originalBodyHeight;
        document.body.style.overflow = originalBodyOverflow;
    }
    // Event listener for keydown enter and escape keys
    window.addEventListener('keydown', function (event) {
        var enterClicked = (event.which === 13 || event.keyCode === 13);
        var escapeClicked = (event.which === 27 || event.keyCode === 27);
        if (alertIsShowing) {
            if (enterClicked || escapeClicked) {
                alertHide();
            }
        }
        else if (confirmIsShowing) {
            if (enterClicked) {
                confirmYes.click();
            }
            else if (escapeClicked) {
                confirmHide();
            }
        }
        else if (inputIsShowing) {
            if (enterClicked) {
                inputYes.click();
            }
            else if (escapeClicked) {
                inputHide();
            }
        }
        else if (selectIsShowing) {
            if (escapeClicked) {
                selectHide();
            }
        }
        else if (dateIsShowing) {
            if (enterClicked) {
                dateYes.click();
            }
            else if (escapeClicked) {
                dateHide();
            }
        }
    });
    return {
        setOptions: setOptions,
        alert: alert,
        alertHide: alertHide,
        force: force,
        confirm: confirm,
        input: input,
        select: select,
        date: date,
        isShowing: isShowing
    };
};
// Export
if (typeof window !== 'undefined' && window) {
    if (typeof module === 'object' && module.exports) {
        // Node.js
        module.exports = notie();
    }
    else {
        // Browser
        window.notie = notie();
    }
}
//# sourceMappingURL=notie.js.map 
//# sourceMappingURL=notie.js.map 
//# sourceMappingURL=notie.js.map 
//# sourceMappingURL=notie.js.map 
//# sourceMappingURL=notie.js.map 
//# sourceMappingURL=notie.js.map 
//# sourceMappingURL=notie.js.map 
//# sourceMappingURL=notie.js.map;
(function($) {
  var $notiny, appendToContainer, closeAction, containers, createNotification, defaults, detectCSSFeature, prepareNotification, showAction, themedefaults;
  $notiny = $('<div class="notiny" />').appendTo($('body'));
  defaults = {
    image: void 0,
    position: 'right-bottom',
    theme: 'dark',
    template: '<div class="notiny-base"><img class="notiny-img" /><div class="notiny-text"></div></div>',
    width: '300',
    text: '',
    background: true,
    autohide: true,
    clickhide: true,
    delay: 3000,
    animate: true,
    animation_show: 'notiny-animation-show 0.4s forwards',
    animation_hide: 'notiny-animation-hide 0.5s forwards'
  };
  themedefaults = {

    /*
     * Blocks order:
     * | container
     * | - base
     * | -- image
     * | -- text
     * | - base
     * | -- image
     * | -- text
     * | ...
     */
    container_class: '',
    notification_class: '',
    image_class: '',
    text_class: ''
  };

  /*
   * List of possible containers
   */
  containers = {
    'left-top': $('<div />', {
      "class": 'notiny-container',
      css: {
        top: 10,
        left: 10
      }
    }).appendTo($notiny),
    'left-bottom': $('<div />', {
      "class": 'notiny-container',
      css: {
        bottom: 10,
        left: 10
      }
    }).appendTo($notiny),
    'right-top': $('<div />', {
      "class": 'notiny-container',
      css: {
        top: 10,
        right: 10
      }
    }).appendTo($notiny),
    'right-bottom': $('<div />', {
      "class": 'notiny-container',
      css: {
        bottom: 10,
        right: 10
      }
    }).appendTo($notiny),
    'fluid-top': $('<div />', {
      "class": 'notiny-container notiny-container-fluid-top',
      css: {
        top: 0,
        left: 0,
        right: 0
      }
    }).appendTo($notiny),
    'fluid-bottom': $('<div />', {
      "class": 'notiny-container notiny-container-fluid-bottom',
      css: {
        bottom: 0,
        left: 0,
        right: 0
      }
    }).appendTo($notiny)
  };
  detectCSSFeature = function(featurename) {
    var domPrefixes, elm, feature, featurenameCapital, i;
    feature = false;
    domPrefixes = 'Webkit Moz ms O'.split(' ');
    elm = document.createElement('div');
    featurenameCapital = null;
    featurename = featurename.toLowerCase();
    if (elm.style[featurename] !== void 0) {
      feature = true;
    }
    if (feature === false) {
      featurenameCapital = featurename.charAt(0).toUpperCase() + featurename.substr(1);
      i = 0;
      while (i < domPrefixes.length) {
        if (elm.style[domPrefixes[i] + featurenameCapital] !== void 0) {
          feature = true;
          break;
        }
        i++;
      }
    }
    return feature;
  };
  closeAction = function($notification, settings) {
      if (settings && settings.animate) {
      if (!settings._state_closing) {
        settings._state_closing = true;
        if (detectCSSFeature('animation') && detectCSSFeature('transform')) {
          $notification.css('animation', settings.animation_hide);
          setTimeout((function() {
            $notification.remove();
          }), 550);
        } else {
          $notification.fadeOut(400, function() {
            $notification.remove();
          });
        }
      }
    } else {
      $notification.remove();
    }
  };
  showAction = function($notification, settings) {
    if (settings.animate) {
      if (detectCSSFeature('animation') && detectCSSFeature('transform')) {
        $notification.css('animation', settings.animation_show);
      } else {
        $notification.hide();
        $notification.fadeIn(500);
      }
    }
  };
  prepareNotification = function(options) {
    return createNotification($.extend({}, defaults, options));
  };
  createNotification = function(settings) {
    var $img, $notification, $ptext;
    $notification = $(settings.template);
    settings.theme = $.notiny.themes[settings.theme];
    $notification.addClass(settings.theme.notification_class);
    $ptext = $notification.find('.notiny-text');
    $ptext.addClass(settings.theme.text_class);
    $ptext.html(settings.text);
    $img = $notification.find('.notiny-img');
    if (settings.image !== void 0) {
      $notification.addClass('notiny-with-img');
      $img.css('display', 'block');
      $img.addClass(settings.theme.image_class);
      $img.attr('src', settings.image);
    } else {
      $img.hide();
      $notification.addClass('notiny-without-img');
    }
    if (settings.position.indexOf('fluid') === -1) {
      $notification.css('width', settings.width);
    }
    $notification.data('settings', settings);
    appendToContainer($notification, settings);
    return $notification;
  };
  appendToContainer = function($notification, settings) {
    var $container, floatclear;
    $container = containers[settings.position];
    $container.addClass(settings.theme.container_class);
    if (settings.position.slice(-3) === 'top') {
      $container.prepend($notification);
    } else {
      $container.append($notification);
    }
    floatclear = settings.position.split('-')[0];
    $notification.css('float', floatclear);
    $notification.css('clear', floatclear);
    settings._state_closing = false;
    if (settings.clickhide) {
      $notification.css('cursor', 'pointer');
      $notification.on('click', function() {
        closeAction($notification, settings);
        return false;
      });
    }
    if (settings.autohide) {
      setTimeout((function() {
        closeAction($notification, settings);
      }), settings.delay + 500);
    }
    showAction($notification, settings);
  };
  $.notiny = function(options) {
    return prepareNotification(options);
  };
  $.notiny.addTheme = function(name, options) {
    var settings;
    settings = $.extend({}, themedefaults, options);
    (this.themes = this.themes || {})[name] = settings;
  };
  $.notiny.close = function($notiny) {
    closeAction($notiny, $notiny.data('settings'));
  };
  $.notiny.addTheme('dark', {
    notification_class: 'notiny-theme-dark notiny-default-vars'
  });
  $.notiny.addTheme('light', {
    notification_class: 'notiny-theme-light notiny-default-vars'
  });
})(jQuery);
;
/**
 * Owl Carousel v2.2.0
 * Copyright 2013-2016 David Deutsch
 * Licensed under MIT (https://github.com/OwlCarousel2/OwlCarousel2/blob/master/LICENSE)
 */
/**
 * Owl carousel
 * @version 2.1.6
 * @author Bartosz Wojciechowski
 * @author David Deutsch
 * @license The MIT License (MIT)
 * @todo Lazy Load Icon
 * @todo prevent animationend bubling
 * @todo itemsScaleUp
 * @todo Test Zepto
 * @todo stagePadding calculate wrong active classes
 */
;
(function ($, window, document, undefined) {
    /**
     * Creates a carousel.
     * @class The Owl Carousel.
     * @public
     * @param {HTMLElement|jQuery} element - The element to create the carousel for.
     * @param {Object} [options] - The options
     */
    function Owl(element, options) {
        /**
         * Current settings for the carousel.
         * @public
         */
        this.settings = null;
        /**
         * Current options set by the caller including defaults.
         * @public
         */
        this.options = $.extend({}, Owl.Defaults, options);
        /**
         * Plugin element.
         * @public
         */
        this.$element = $(element);
        /**
         * Proxied event handlers.
         * @protected
         */
        this._handlers = {};
        /**
         * References to the running plugins of this carousel.
         * @protected
         */
        this._plugins = {};
        /**
         * Currently suppressed events to prevent them from beeing retriggered.
         * @protected
         */
        this._supress = {};
        /**
         * Absolute current position.
         * @protected
         */
        this._current = null;
        /**
         * Animation speed in milliseconds.
         * @protected
         */
        this._speed = null;
        /**
         * Coordinates of all items in pixel.
         * @todo The name of this member is missleading.
         * @protected
         */
        this._coordinates = [];
        /**
         * Current breakpoint.
         * @todo Real media queries would be nice.
         * @protected
         */
        this._breakpoint = null;
        /**
         * Current width of the plugin element.
         */
        this._width = null;
        /**
         * All real items.
         * @protected
         */
        this._items = [];
        /**
         * All cloned items.
         * @protected
         */
        this._clones = [];
        /**
         * Merge values of all items.
         * @todo Maybe this could be part of a plugin.
         * @protected
         */
        this._mergers = [];
        /**
         * Widths of all items.
         */
        this._widths = [];
        /**
         * Invalidated parts within the update process.
         * @protected
         */
        this._invalidated = {};
        /**
         * Ordered list of workers for the update process.
         * @protected
         */
        this._pipe = [];
        /**
         * Current state information for the drag operation.
         * @todo #261
         * @protected
         */
        this._drag = {
            time: null,
            target: null,
            pointer: null,
            stage: {
                start: null,
                current: null
            },
            direction: null
        };
        /**
         * Current state information and their tags.
         * @type {Object}
         * @protected
         */
        this._states = {
            current: {},
            tags: {
                'initializing': ['busy'],
                'animating': ['busy'],
                'dragging': ['interacting']
            }
        };
        $.each(['onResize', 'onThrottledResize'], $.proxy(function (i, handler) {
            this._handlers[handler] = $.proxy(this[handler], this);
        }, this));
        $.each(Owl.Plugins, $.proxy(function (key, plugin) {
            this._plugins[key.charAt(0).toLowerCase() + key.slice(1)]
                = new plugin(this);
        }, this));
        $.each(Owl.Workers, $.proxy(function (priority, worker) {
            this._pipe.push({
                'filter': worker.filter,
                'run': $.proxy(worker.run, this)
            });
        }, this));
        this.setup();
        this.initialize();
    }
    /**
     * Default options for the carousel.
     * @public
     */
    Owl.Defaults = {
        items: 3,
        loop: false,
        center: false,
        rewind: false,
        mouseDrag: true,
        touchDrag: true,
        pullDrag: true,
        freeDrag: false,
        margin: 0,
        stagePadding: 0,
        merge: false,
        mergeFit: true,
        autoWidth: false,
        startPosition: 0,
        rtl: false,
        smartSpeed: 250,
        fluidSpeed: false,
        dragEndSpeed: false,
        responsive: {},
        responsiveRefreshRate: 200,
        responsiveBaseElement: window,
        fallbackEasing: 'swing',
        info: false,
        nestedItemSelector: false,
        itemElement: 'div',
        stageElement: 'div',
        refreshClass: 'owl-refresh',
        loadedClass: 'owl-loaded',
        loadingClass: 'owl-loading',
        rtlClass: 'owl-rtl',
        responsiveClass: 'owl-responsive',
        dragClass: 'owl-drag',
        itemClass: 'owl-item',
        stageClass: 'owl-stage',
        stageOuterClass: 'owl-stage-outer',
        grabClass: 'owl-grab'
    };
    /**
     * Enumeration for width.
     * @public
     * @readonly
     * @enum {String}
     */
    Owl.Width = {
        Default: 'default',
        Inner: 'inner',
        Outer: 'outer'
    };
    /**
     * Enumeration for types.
     * @public
     * @readonly
     * @enum {String}
     */
    Owl.Type = {
        Event: 'event',
        State: 'state'
    };
    /**
     * Contains all registered plugins.
     * @public
     */
    Owl.Plugins = {};
    /**
     * List of workers involved in the update process.
     */
    Owl.Workers = [{
            filter: ['width', 'settings'],
            run: function () {
                this._width = this.$element.width();
            }
        }, {
            filter: ['width', 'items', 'settings'],
            run: function (cache) {
                cache.current = this._items && this._items[this.relative(this._current)];
            }
        }, {
            filter: ['items', 'settings'],
            run: function () {
                this.$stage.children('.cloned').remove();
            }
        }, {
            filter: ['width', 'items', 'settings'],
            run: function (cache) {
                var margin = this.settings.margin || '', grid = !this.settings.autoWidth, rtl = this.settings.rtl, css = {
                    'width': 'auto',
                    'margin-left': rtl ? margin : '',
                    'margin-right': rtl ? '' : margin
                };
                !grid && this.$stage.children().css(css);
                cache.css = css;
            }
        }, {
            filter: ['width', 'items', 'settings'],
            run: function (cache) {
                var width = (this.width() / this.settings.items).toFixed(3) - this.settings.margin, merge = null, iterator = this._items.length, grid = !this.settings.autoWidth, widths = [];
                cache.items = {
                    merge: false,
                    width: width
                };
                while (iterator--) {
                    merge = this._mergers[iterator];
                    merge = this.settings.mergeFit && Math.min(merge, this.settings.items) || merge;
                    cache.items.merge = merge > 1 || cache.items.merge;
                    widths[iterator] = !grid ? this._items[iterator].width() : width * merge;
                }
                this._widths = widths;
            }
        }, {
            filter: ['items', 'settings'],
            run: function () {
                var clones = [], items = this._items, settings = this.settings, view = Math.max(settings.items * 2, 4), size = Math.ceil(items.length / 2) * 2, repeat = settings.loop && items.length ? settings.rewind ? view : Math.max(view, size) : 0, append = '', prepend = '';
                repeat /= 2;
                while (repeat--) {
                    clones.push(this.normalize(clones.length / 2, true));
                    append = append + items[clones[clones.length - 1]][0].outerHTML;
                    clones.push(this.normalize(items.length - 1 - (clones.length - 1) / 2, true));
                    prepend = items[clones[clones.length - 1]][0].outerHTML + prepend;
                }
                this._clones = clones;
                $(append).addClass('cloned').appendTo(this.$stage);
                $(prepend).addClass('cloned').prependTo(this.$stage);
            }
        }, {
            filter: ['width', 'items', 'settings'],
            run: function () {
                var rtl = this.settings.rtl ? 1 : -1, size = this._clones.length + this._items.length, iterator = -1, previous = 0, current = 0, coordinates = [];
                while (++iterator < size) {
                    previous = coordinates[iterator - 1] || 0;
                    current = this._widths[this.relative(iterator)] + this.settings.margin;
                    coordinates.push(previous + current * rtl);
                }
                this._coordinates = coordinates;
            }
        }, {
            filter: ['width', 'items', 'settings'],
            run: function () {
                var padding = this.settings.stagePadding, coordinates = this._coordinates, css = {
                    'width': Math.ceil(Math.abs(coordinates[coordinates.length - 1])) + padding * 2,
                    'padding-left': padding || '',
                    'padding-right': padding || ''
                };
                this.$stage.css(css);
            }
        }, {
            filter: ['width', 'items', 'settings'],
            run: function (cache) {
                var iterator = this._coordinates.length, grid = !this.settings.autoWidth, items = this.$stage.children();
                if (grid && cache.items.merge) {
                    while (iterator--) {
                        cache.css.width = this._widths[this.relative(iterator)];
                        items.eq(iterator).css(cache.css);
                    }
                }
                else if (grid) {
                    cache.css.width = cache.items.width;
                    items.css(cache.css);
                }
            }
        }, {
            filter: ['items'],
            run: function () {
                this._coordinates.length < 1 && this.$stage.removeAttr('style');
            }
        }, {
            filter: ['width', 'items', 'settings'],
            run: function (cache) {
                cache.current = cache.current ? this.$stage.children().index(cache.current) : 0;
                cache.current = Math.max(this.minimum(), Math.min(this.maximum(), cache.current));
                this.reset(cache.current);
            }
        }, {
            filter: ['position'],
            run: function () {
                this.animate(this.coordinates(this._current));
            }
        }, {
            filter: ['width', 'position', 'items', 'settings'],
            run: function () {
                var rtl = this.settings.rtl ? 1 : -1, padding = this.settings.stagePadding * 2, begin = this.coordinates(this.current()) + padding, end = begin + this.width() * rtl, inner, outer, matches = [], i, n;
                for (i = 0, n = this._coordinates.length; i < n; i++) {
                    inner = this._coordinates[i - 1] || 0;
                    outer = Math.abs(this._coordinates[i]) + padding * rtl;
                    if ((this.op(inner, '<=', begin) && (this.op(inner, '>', end)))
                        || (this.op(outer, '<', begin) && this.op(outer, '>', end))) {
                        matches.push(i);
                    }
                }
                this.$stage.children('.active').removeClass('active');
                this.$stage.children(':eq(' + matches.join('), :eq(') + ')').addClass('active');
                if (this.settings.center) {
                    this.$stage.children('.center').removeClass('center');
                    this.$stage.children().eq(this.current()).addClass('center');
                }
            }
        }];
    /**
     * Initializes the carousel.
     * @protected
     */
    Owl.prototype.initialize = function () {
        this.enter('initializing');
        this.trigger('initialize');
        this.$element.toggleClass(this.settings.rtlClass, this.settings.rtl);
        if (this.settings.autoWidth && !this.is('pre-loading')) {
            var imgs, nestedSelector, width;
            imgs = this.$element.find('img');
            nestedSelector = this.settings.nestedItemSelector ? '.' + this.settings.nestedItemSelector : undefined;
            width = this.$element.children(nestedSelector).width();
            if (imgs.length && width <= 0) {
                this.preloadAutoWidthImages(imgs);
            }
        }
        this.$element.addClass(this.options.loadingClass);
        // create stage
        this.$stage = $('<' + this.settings.stageElement + ' class="' + this.settings.stageClass + '"/>')
            .wrap('<div class="' + this.settings.stageOuterClass + '"/>');
        // append stage
        this.$element.append(this.$stage.parent());
        // append content
        this.replace(this.$element.children().not(this.$stage.parent()));
        // check visibility
        if (this.$element.is(':visible')) {
            // update view
            this.refresh();
        }
        else {
            // invalidate width
            this.invalidate('width');
        }
        this.$element
            .removeClass(this.options.loadingClass)
            .addClass(this.options.loadedClass);
        // register event handlers
        this.registerEventHandlers();
        this.leave('initializing');
        this.trigger('initialized');
    };
    /**
     * Setups the current settings.
     * @todo Remove responsive classes. Why should adaptive designs be brought into IE8?
     * @todo Support for media queries by using `matchMedia` would be nice.
     * @public
     */
    Owl.prototype.setup = function () {
        var viewport = this.viewport(), overwrites = this.options.responsive, match = -1, settings = null;
        if (!overwrites) {
            settings = $.extend({}, this.options);
        }
        else {
            $.each(overwrites, function (breakpoint) {
                if (breakpoint <= viewport && breakpoint > match) {
                    match = Number(breakpoint);
                }
            });
            settings = $.extend({}, this.options, overwrites[match]);
            if (typeof settings.stagePadding === 'function') {
                settings.stagePadding = settings.stagePadding();
            }
            delete settings.responsive;
            // responsive class
            if (settings.responsiveClass) {
                this.$element.attr('class', this.$element.attr('class').replace(new RegExp('(' + this.options.responsiveClass + '-)\\S+\\s', 'g'), '$1' + match));
            }
        }
        this.trigger('change', { property: { name: 'settings', value: settings } });
        this._breakpoint = match;
        this.settings = settings;
        this.invalidate('settings');
        this.trigger('changed', { property: { name: 'settings', value: this.settings } });
    };
    /**
     * Updates option logic if necessery.
     * @protected
     */
    Owl.prototype.optionsLogic = function () {
        if (this.settings.autoWidth) {
            this.settings.stagePadding = false;
            this.settings.merge = false;
        }
    };
    /**
     * Prepares an item before add.
     * @todo Rename event parameter `content` to `item`.
     * @protected
     * @returns {jQuery|HTMLElement} - The item container.
     */
    Owl.prototype.prepare = function (item) {
        var event = this.trigger('prepare', { content: item });
        if (!event.data) {
            event.data = $('<' + this.settings.itemElement + '/>')
                .addClass(this.options.itemClass).append(item);
        }
        this.trigger('prepared', { content: event.data });
        return event.data;
    };
    /**
     * Updates the view.
     * @public
     */
    Owl.prototype.update = function () {
        var i = 0, n = this._pipe.length, filter = $.proxy(function (p) { return this[p]; }, this._invalidated), cache = {};
        while (i < n) {
            if (this._invalidated.all || $.grep(this._pipe[i].filter, filter).length > 0) {
                this._pipe[i].run(cache);
            }
            i++;
        }
        this._invalidated = {};
        !this.is('valid') && this.enter('valid');
    };
    /**
     * Gets the width of the view.
     * @public
     * @param {Owl.Width} [dimension=Owl.Width.Default] - The dimension to return.
     * @returns {Number} - The width of the view in pixel.
     */
    Owl.prototype.width = function (dimension) {
        dimension = dimension || Owl.Width.Default;
        switch (dimension) {
            case Owl.Width.Inner:
            case Owl.Width.Outer:
                return this._width;
            default:
                return this._width - this.settings.stagePadding * 2 + this.settings.margin;
        }
    };
    /**
     * Refreshes the carousel primarily for adaptive purposes.
     * @public
     */
    Owl.prototype.refresh = function () {
        this.enter('refreshing');
        this.trigger('refresh');
        this.setup();
        this.optionsLogic();
        this.$element.addClass(this.options.refreshClass);
        this.update();
        this.$element.removeClass(this.options.refreshClass);
        this.leave('refreshing');
        this.trigger('refreshed');
    };
    /**
     * Checks window `resize` event.
     * @protected
     */
    Owl.prototype.onThrottledResize = function () {
        window.clearTimeout(this.resizeTimer);
        this.resizeTimer = window.setTimeout(this._handlers.onResize, this.settings.responsiveRefreshRate);
    };
    /**
     * Checks window `resize` event.
     * @protected
     */
    Owl.prototype.onResize = function () {
        if (!this._items.length) {
            return false;
        }
        if (this._width === this.$element.width()) {
            return false;
        }
        if (!this.$element.is(':visible')) {
            return false;
        }
        this.enter('resizing');
        if (this.trigger('resize').isDefaultPrevented()) {
            this.leave('resizing');
            return false;
        }
        this.invalidate('width');
        this.refresh();
        this.leave('resizing');
        this.trigger('resized');
    };
    /**
     * Registers event handlers.
     * @todo Check `msPointerEnabled`
     * @todo #261
     * @protected
     */
    Owl.prototype.registerEventHandlers = function () {
        if ($.support.transition) {
            this.$stage.on($.support.transition.end + '.owl.core', $.proxy(this.onTransitionEnd, this));
        }
        if (this.settings.responsive !== false) {
            this.on(window, 'resize', this._handlers.onThrottledResize);
        }
        if (this.settings.mouseDrag) {
            this.$element.addClass(this.options.dragClass);
            this.$stage.on('mousedown.owl.core', $.proxy(this.onDragStart, this));
            this.$stage.on('dragstart.owl.core selectstart.owl.core', function () { return false; });
        }
        if (this.settings.touchDrag) {
            this.$stage.on('touchstart.owl.core', $.proxy(this.onDragStart, this));
            this.$stage.on('touchcancel.owl.core', $.proxy(this.onDragEnd, this));
        }
    };
    /**
     * Handles `touchstart` and `mousedown` events.
     * @todo Horizontal swipe threshold as option
     * @todo #261
     * @protected
     * @param {Event} event - The event arguments.
     */
    Owl.prototype.onDragStart = function (event) {
        var stage = null;
        if (event.which === 3) {
            return;
        }
        if ($.support.transform) {
            stage = this.$stage.css('transform').replace(/.*\(|\)| /g, '').split(',');
            stage = {
                x: stage[stage.length === 16 ? 12 : 4],
                y: stage[stage.length === 16 ? 13 : 5]
            };
        }
        else {
            stage = this.$stage.position();
            stage = {
                x: this.settings.rtl ?
                    stage.left + this.$stage.width() - this.width() + this.settings.margin :
                    stage.left,
                y: stage.top
            };
        }
        if (this.is('animating')) {
            $.support.transform ? this.animate(stage.x) : this.$stage.stop();
            this.invalidate('position');
        }
        this.$element.toggleClass(this.options.grabClass, event.type === 'mousedown');
        this.speed(0);
        this._drag.time = new Date().getTime();
        this._drag.target = $(event.target);
        this._drag.stage.start = stage;
        this._drag.stage.current = stage;
        this._drag.pointer = this.pointer(event);
        $(document).on('mouseup.owl.core touchend.owl.core', $.proxy(this.onDragEnd, this));
        $(document).one('mousemove.owl.core touchmove.owl.core', $.proxy(function (event) {
            var delta = this.difference(this._drag.pointer, this.pointer(event));
            $(document).on('mousemove.owl.core touchmove.owl.core', $.proxy(this.onDragMove, this));
            if (Math.abs(delta.x) < Math.abs(delta.y) && this.is('valid')) {
                return;
            }
            event.preventDefault();
            this.enter('dragging');
            this.trigger('drag');
        }, this));
    };
    /**
     * Handles the `touchmove` and `mousemove` events.
     * @todo #261
     * @protected
     * @param {Event} event - The event arguments.
     */
    Owl.prototype.onDragMove = function (event) {
        var minimum = null, maximum = null, pull = null, delta = this.difference(this._drag.pointer, this.pointer(event)), stage = this.difference(this._drag.stage.start, delta);
        if (!this.is('dragging')) {
            return;
        }
        event.preventDefault();
        if (this.settings.loop) {
            minimum = this.coordinates(this.minimum());
            maximum = this.coordinates(this.maximum() + 1) - minimum;
            stage.x = (((stage.x - minimum) % maximum + maximum) % maximum) + minimum;
        }
        else {
            minimum = this.settings.rtl ? this.coordinates(this.maximum()) : this.coordinates(this.minimum());
            maximum = this.settings.rtl ? this.coordinates(this.minimum()) : this.coordinates(this.maximum());
            pull = this.settings.pullDrag ? -1 * delta.x / 5 : 0;
            stage.x = Math.max(Math.min(stage.x, minimum + pull), maximum + pull);
        }
        this._drag.stage.current = stage;
        this.animate(stage.x);
    };
    /**
     * Handles the `touchend` and `mouseup` events.
     * @todo #261
     * @todo Threshold for click event
     * @protected
     * @param {Event} event - The event arguments.
     */
    Owl.prototype.onDragEnd = function (event) {
        var delta = this.difference(this._drag.pointer, this.pointer(event)), stage = this._drag.stage.current, direction = delta.x > 0 ^ this.settings.rtl ? 'left' : 'right';
        $(document).off('.owl.core');
        this.$element.removeClass(this.options.grabClass);
        if (delta.x !== 0 && this.is('dragging') || !this.is('valid')) {
            this.speed(this.settings.dragEndSpeed || this.settings.smartSpeed);
            this.current(this.closest(stage.x, delta.x !== 0 ? direction : this._drag.direction));
            this.invalidate('position');
            this.update();
            this._drag.direction = direction;
            if (Math.abs(delta.x) > 3 || new Date().getTime() - this._drag.time > 300) {
                this._drag.target.one('click.owl.core', function () { return false; });
            }
        }
        if (!this.is('dragging')) {
            return;
        }
        this.leave('dragging');
        this.trigger('dragged');
    };
    /**
     * Gets absolute position of the closest item for a coordinate.
     * @todo Setting `freeDrag` makes `closest` not reusable. See #165.
     * @protected
     * @param {Number} coordinate - The coordinate in pixel.
     * @param {String} direction - The direction to check for the closest item. Ether `left` or `right`.
     * @return {Number} - The absolute position of the closest item.
     */
    Owl.prototype.closest = function (coordinate, direction) {
        var position = -1, pull = 30, width = this.width(), coordinates = this.coordinates();
        if (!this.settings.freeDrag) {
            // check closest item
            $.each(coordinates, $.proxy(function (index, value) {
                // on a left pull, check on current index
                if (direction === 'left' && coordinate > value - pull && coordinate < value + pull) {
                    position = index;
                }
                else if (direction === 'right' && coordinate > value - width - pull && coordinate < value - width + pull) {
                    position = index + 1;
                }
                else if (this.op(coordinate, '<', value)
                    && this.op(coordinate, '>', coordinates[index + 1] || value - width)) {
                    position = direction === 'left' ? index + 1 : index;
                }
                return position === -1;
            }, this));
        }
        if (!this.settings.loop) {
            // non loop boundries
            if (this.op(coordinate, '>', coordinates[this.minimum()])) {
                position = coordinate = this.minimum();
            }
            else if (this.op(coordinate, '<', coordinates[this.maximum()])) {
                position = coordinate = this.maximum();
            }
        }
        return position;
    };
    /**
     * Animates the stage.
     * @todo #270
     * @public
     * @param {Number} coordinate - The coordinate in pixels.
     */
    Owl.prototype.animate = function (coordinate) {
        var animate = this.speed() > 0;
        this.is('animating') && this.onTransitionEnd();
        if (animate) {
            this.enter('animating');
            this.trigger('translate');
        }
        if ($.support.transform3d && $.support.transition) {
            this.$stage.css({
                transform: 'translate3d(' + coordinate + 'px,0px,0px)',
                transition: (this.speed() / 1000) + 's'
            });
        }
        else if (animate) {
            this.$stage.animate({
                left: coordinate + 'px'
            }, this.speed(), this.settings.fallbackEasing, $.proxy(this.onTransitionEnd, this));
        }
        else {
            this.$stage.css({
                left: coordinate + 'px'
            });
        }
    };
    /**
     * Checks whether the carousel is in a specific state or not.
     * @param {String} state - The state to check.
     * @returns {Boolean} - The flag which indicates if the carousel is busy.
     */
    Owl.prototype.is = function (state) {
        return this._states.current[state] && this._states.current[state] > 0;
    };
    /**
     * Sets the absolute position of the current item.
     * @public
     * @param {Number} [position] - The new absolute position or nothing to leave it unchanged.
     * @returns {Number} - The absolute position of the current item.
     */
    Owl.prototype.current = function (position) {
        if (position === undefined) {
            return this._current;
        }
        if (this._items.length === 0) {
            return undefined;
        }
        position = this.normalize(position);
        if (this._current !== position) {
            var event = this.trigger('change', { property: { name: 'position', value: position } });
            if (event.data !== undefined) {
                position = this.normalize(event.data);
            }
            this._current = position;
            this.invalidate('position');
            this.trigger('changed', { property: { name: 'position', value: this._current } });
        }
        return this._current;
    };
    /**
     * Invalidates the given part of the update routine.
     * @param {String} [part] - The part to invalidate.
     * @returns {Array.<String>} - The invalidated parts.
     */
    Owl.prototype.invalidate = function (part) {
        if ($.type(part) === 'string') {
            this._invalidated[part] = true;
            this.is('valid') && this.leave('valid');
        }
        return $.map(this._invalidated, function (v, i) { return i; });
    };
    /**
     * Resets the absolute position of the current item.
     * @public
     * @param {Number} position - The absolute position of the new item.
     */
    Owl.prototype.reset = function (position) {
        position = this.normalize(position);
        if (position === undefined) {
            return;
        }
        this._speed = 0;
        this._current = position;
        this.suppress(['translate', 'translated']);
        this.animate(this.coordinates(position));
        this.release(['translate', 'translated']);
    };
    /**
     * Normalizes an absolute or a relative position of an item.
     * @public
     * @param {Number} position - The absolute or relative position to normalize.
     * @param {Boolean} [relative=false] - Whether the given position is relative or not.
     * @returns {Number} - The normalized position.
     */
    Owl.prototype.normalize = function (position, relative) {
        var n = this._items.length, m = relative ? 0 : this._clones.length;
        if (!this.isNumeric(position) || n < 1) {
            position = undefined;
        }
        else if (position < 0 || position >= n + m) {
            position = ((position - m / 2) % n + n) % n + m / 2;
        }
        return position;
    };
    /**
     * Converts an absolute position of an item into a relative one.
     * @public
     * @param {Number} position - The absolute position to convert.
     * @returns {Number} - The converted position.
     */
    Owl.prototype.relative = function (position) {
        position -= this._clones.length / 2;
        return this.normalize(position, true);
    };
    /**
     * Gets the maximum position for the current item.
     * @public
     * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position.
     * @returns {Number}
     */
    Owl.prototype.maximum = function (relative) {
        var settings = this.settings, maximum = this._coordinates.length, iterator, reciprocalItemsWidth, elementWidth;
        if (settings.loop) {
            maximum = this._clones.length / 2 + this._items.length - 1;
        }
        else if (settings.autoWidth || settings.merge) {
            iterator = this._items.length;
            reciprocalItemsWidth = this._items[--iterator].width();
            elementWidth = this.$element.width();
            while (iterator--) {
                reciprocalItemsWidth += this._items[iterator].width() + this.settings.margin;
                if (reciprocalItemsWidth > elementWidth) {
                    break;
                }
            }
            maximum = iterator + 1;
        }
        else if (settings.center) {
            maximum = this._items.length - 1;
        }
        else {
            maximum = this._items.length - settings.items;
        }
        if (relative) {
            maximum -= this._clones.length / 2;
        }
        return Math.max(maximum, 0);
    };
    /**
     * Gets the minimum position for the current item.
     * @public
     * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position.
     * @returns {Number}
     */
    Owl.prototype.minimum = function (relative) {
        return relative ? 0 : this._clones.length / 2;
    };
    /**
     * Gets an item at the specified relative position.
     * @public
     * @param {Number} [position] - The relative position of the item.
     * @return {jQuery|Array.<jQuery>} - The item at the given position or all items if no position was given.
     */
    Owl.prototype.items = function (position) {
        if (position === undefined) {
            return this._items.slice();
        }
        position = this.normalize(position, true);
        return this._items[position];
    };
    /**
     * Gets an item at the specified relative position.
     * @public
     * @param {Number} [position] - The relative position of the item.
     * @return {jQuery|Array.<jQuery>} - The item at the given position or all items if no position was given.
     */
    Owl.prototype.mergers = function (position) {
        if (position === undefined) {
            return this._mergers.slice();
        }
        position = this.normalize(position, true);
        return this._mergers[position];
    };
    /**
     * Gets the absolute positions of clones for an item.
     * @public
     * @param {Number} [position] - The relative position of the item.
     * @returns {Array.<Number>} - The absolute positions of clones for the item or all if no position was given.
     */
    Owl.prototype.clones = function (position) {
        var odd = this._clones.length / 2, even = odd + this._items.length, map = function (index) { return index % 2 === 0 ? even + index / 2 : odd - (index + 1) / 2; };
        if (position === undefined) {
            return $.map(this._clones, function (v, i) { return map(i); });
        }
        return $.map(this._clones, function (v, i) { return v === position ? map(i) : null; });
    };
    /**
     * Sets the current animation speed.
     * @public
     * @param {Number} [speed] - The animation speed in milliseconds or nothing to leave it unchanged.
     * @returns {Number} - The current animation speed in milliseconds.
     */
    Owl.prototype.speed = function (speed) {
        if (speed !== undefined) {
            this._speed = speed;
        }
        return this._speed;
    };
    /**
     * Gets the coordinate of an item.
     * @todo The name of this method is missleanding.
     * @public
     * @param {Number} position - The absolute position of the item within `minimum()` and `maximum()`.
     * @returns {Number|Array.<Number>} - The coordinate of the item in pixel or all coordinates.
     */
    Owl.prototype.coordinates = function (position) {
        var multiplier = 1, newPosition = position - 1, coordinate;
        if (position === undefined) {
            return $.map(this._coordinates, $.proxy(function (coordinate, index) {
                return this.coordinates(index);
            }, this));
        }
        if (this.settings.center) {
            if (this.settings.rtl) {
                multiplier = -1;
                newPosition = position + 1;
            }
            coordinate = this._coordinates[position];
            coordinate += (this.width() - coordinate + (this._coordinates[newPosition] || 0)) / 2 * multiplier;
        }
        else {
            coordinate = this._coordinates[newPosition] || 0;
        }
        coordinate = Math.ceil(coordinate);
        return coordinate;
    };
    /**
     * Calculates the speed for a translation.
     * @protected
     * @param {Number} from - The absolute position of the start item.
     * @param {Number} to - The absolute position of the target item.
     * @param {Number} [factor=undefined] - The time factor in milliseconds.
     * @returns {Number} - The time in milliseconds for the translation.
     */
    Owl.prototype.duration = function (from, to, factor) {
        if (factor === 0) {
            return 0;
        }
        return Math.min(Math.max(Math.abs(to - from), 1), 6) * Math.abs((factor || this.settings.smartSpeed));
    };
    /**
     * Slides to the specified item.
     * @public
     * @param {Number} position - The position of the item.
     * @param {Number} [speed] - The time in milliseconds for the transition.
     */
    Owl.prototype.to = function (position, speed) {
        var current = this.current(), revert = null, distance = position - this.relative(current), direction = (distance > 0) - (distance < 0), items = this._items.length, minimum = this.minimum(), maximum = this.maximum();
        if (this.settings.loop) {
            if (!this.settings.rewind && Math.abs(distance) > items / 2) {
                distance += direction * -1 * items;
            }
            position = current + distance;
            revert = ((position - minimum) % items + items) % items + minimum;
            if (revert !== position && revert - distance <= maximum && revert - distance > 0) {
                current = revert - distance;
                position = revert;
                this.reset(current);
            }
        }
        else if (this.settings.rewind) {
            maximum += 1;
            position = (position % maximum + maximum) % maximum;
        }
        else {
            position = Math.max(minimum, Math.min(maximum, position));
        }
        this.speed(this.duration(current, position, speed));
        this.current(position);
        if (this.$element.is(':visible')) {
            this.update();
        }
    };
    /**
     * Slides to the next item.
     * @public
     * @param {Number} [speed] - The time in milliseconds for the transition.
     */
    Owl.prototype.next = function (speed) {
        speed = speed || false;
        this.to(this.relative(this.current()) + 1, speed);
    };
    /**
     * Slides to the previous item.
     * @public
     * @param {Number} [speed] - The time in milliseconds for the transition.
     */
    Owl.prototype.prev = function (speed) {
        speed = speed || false;
        this.to(this.relative(this.current()) - 1, speed);
    };
    /**
     * Handles the end of an animation.
     * @protected
     * @param {Event} event - The event arguments.
     */
    Owl.prototype.onTransitionEnd = function (event) {
        // if css2 animation then event object is undefined
        if (event !== undefined) {
            event.stopPropagation();
            // Catch only owl-stage transitionEnd event
            if ((event.target || event.srcElement || event.originalTarget) !== this.$stage.get(0)) {
                return false;
            }
        }
        this.leave('animating');
        this.trigger('translated');
    };
    /**
     * Gets viewport width.
     * @protected
     * @return {Number} - The width in pixel.
     */
    Owl.prototype.viewport = function () {
        var width;
        if (this.options.responsiveBaseElement !== window) {
            width = $(this.options.responsiveBaseElement).width();
        }
        else if (window.innerWidth) {
            width = window.innerWidth;
        }
        else if (document.documentElement && document.documentElement.clientWidth) {
            width = document.documentElement.clientWidth;
        }
        else {
            throw 'Can not detect viewport width.';
        }
        return width;
    };
    /**
     * Replaces the current content.
     * @public
     * @param {HTMLElement|jQuery|String} content - The new content.
     */
    Owl.prototype.replace = function (content) {
        this.$stage.empty();
        this._items = [];
        if (content) {
            content = (content instanceof jQuery) ? content : $(content);
        }
        if (this.settings.nestedItemSelector) {
            content = content.find('.' + this.settings.nestedItemSelector);
        }
        content.filter(function () {
            return this.nodeType === 1;
        }).each($.proxy(function (index, item) {
            item = this.prepare(item);
            this.$stage.append(item);
            this._items.push(item);
            this._mergers.push(item.find('[data-merge]').addBack('[data-merge]').attr('data-merge') * 1 || 1);
        }, this));
        this.reset(this.isNumeric(this.settings.startPosition) ? this.settings.startPosition : 0);
        this.invalidate('items');
    };
    /**
     * Adds an item.
     * @todo Use `item` instead of `content` for the event arguments.
     * @public
     * @param {HTMLElement|jQuery|String} content - The item content to add.
     * @param {Number} [position] - The relative position at which to insert the item otherwise the item will be added to the end.
     */
    Owl.prototype.add = function (content, position) {
        var current = this.relative(this._current);
        position = position === undefined ? this._items.length : this.normalize(position, true);
        content = content instanceof jQuery ? content : $(content);
        this.trigger('add', { content: content, position: position });
        content = this.prepare(content);
        if (this._items.length === 0 || position === this._items.length) {
            this._items.length === 0 && this.$stage.append(content);
            this._items.length !== 0 && this._items[position - 1].after(content);
            this._items.push(content);
            this._mergers.push(content.find('[data-merge]').addBack('[data-merge]').attr('data-merge') * 1 || 1);
        }
        else {
            this._items[position].before(content);
            this._items.splice(position, 0, content);
            this._mergers.splice(position, 0, content.find('[data-merge]').addBack('[data-merge]').attr('data-merge') * 1 || 1);
        }
        this._items[current] && this.reset(this._items[current].index());
        this.invalidate('items');
        this.trigger('added', { content: content, position: position });
    };
    /**
     * Removes an item by its position.
     * @todo Use `item` instead of `content` for the event arguments.
     * @public
     * @param {Number} position - The relative position of the item to remove.
     */
    Owl.prototype.remove = function (position) {
        position = this.normalize(position, true);
        if (position === undefined) {
            return;
        }
        this.trigger('remove', { content: this._items[position], position: position });
        this._items[position].remove();
        this._items.splice(position, 1);
        this._mergers.splice(position, 1);
        this.invalidate('items');
        this.trigger('removed', { content: null, position: position });
    };
    /**
     * Preloads images with auto width.
     * @todo Replace by a more generic approach
     * @protected
     */
    Owl.prototype.preloadAutoWidthImages = function (images) {
        images.each($.proxy(function (i, element) {
            this.enter('pre-loading');
            element = $(element);
            $(new Image()).one('load', $.proxy(function (e) {
                element.attr('src', e.target.src);
                element.css('opacity', 1);
                this.leave('pre-loading');
                !this.is('pre-loading') && !this.is('initializing') && this.refresh();
            }, this)).attr('src', element.attr('src') || element.attr('data-src') || element.attr('data-src-retina'));
        }, this));
    };
    /**
     * Destroys the carousel.
     * @public
     */
    Owl.prototype.destroy = function () {
        this.$element.off('.owl.core');
        this.$stage.off('.owl.core');
        $(document).off('.owl.core');
        if (this.settings.responsive !== false) {
            window.clearTimeout(this.resizeTimer);
            this.off(window, 'resize', this._handlers.onThrottledResize);
        }
        for (var i in this._plugins) {
            this._plugins[i].destroy();
        }
        this.$stage.children('.cloned').remove();
        this.$stage.unwrap();
        this.$stage.children().contents().unwrap();
        this.$stage.children().unwrap();
        this.$element
            .removeClass(this.options.refreshClass)
            .removeClass(this.options.loadingClass)
            .removeClass(this.options.loadedClass)
            .removeClass(this.options.rtlClass)
            .removeClass(this.options.dragClass)
            .removeClass(this.options.grabClass)
            .attr('class', this.$element.attr('class').replace(new RegExp(this.options.responsiveClass + '-\\S+\\s', 'g'), ''))
            .removeData('owl.carousel');
    };
    /**
     * Operators to calculate right-to-left and left-to-right.
     * @protected
     * @param {Number} [a] - The left side operand.
     * @param {String} [o] - The operator.
     * @param {Number} [b] - The right side operand.
     */
    Owl.prototype.op = function (a, o, b) {
        var rtl = this.settings.rtl;
        switch (o) {
            case '<':
                return rtl ? a > b : a < b;
            case '>':
                return rtl ? a < b : a > b;
            case '>=':
                return rtl ? a <= b : a >= b;
            case '<=':
                return rtl ? a >= b : a <= b;
            default:
                break;
        }
    };
    /**
     * Attaches to an internal event.
     * @protected
     * @param {HTMLElement} element - The event source.
     * @param {String} event - The event name.
     * @param {Function} listener - The event handler to attach.
     * @param {Boolean} capture - Wether the event should be handled at the capturing phase or not.
     */
    Owl.prototype.on = function (element, event, listener, capture) {
        if (element.addEventListener) {
            element.addEventListener(event, listener, capture);
        }
        else if (element.attachEvent) {
            element.attachEvent('on' + event, listener);
        }
    };
    /**
     * Detaches from an internal event.
     * @protected
     * @param {HTMLElement} element - The event source.
     * @param {String} event - The event name.
     * @param {Function} listener - The attached event handler to detach.
     * @param {Boolean} capture - Wether the attached event handler was registered as a capturing listener or not.
     */
    Owl.prototype.off = function (element, event, listener, capture) {
        if (element.removeEventListener) {
            element.removeEventListener(event, listener, capture);
        }
        else if (element.detachEvent) {
            element.detachEvent('on' + event, listener);
        }
    };
    /**
     * Triggers a public event.
     * @todo Remove `status`, `relatedTarget` should be used instead.
     * @protected
     * @param {String} name - The event name.
     * @param {*} [data=null] - The event data.
     * @param {String} [namespace=carousel] - The event namespace.
     * @param {String} [state] - The state which is associated with the event.
     * @param {Boolean} [enter=false] - Indicates if the call enters the specified state or not.
     * @returns {Event} - The event arguments.
     */
    Owl.prototype.trigger = function (name, data, namespace, state, enter) {
        var status = {
            item: { count: this._items.length, index: this.current() }
        }, handler = $.camelCase($.grep(['on', name, namespace], function (v) { return v; })
            .join('-').toLowerCase()), event = $.Event([name, 'owl', namespace || 'carousel'].join('.').toLowerCase(), $.extend({ relatedTarget: this }, status, data));
        if (!this._supress[name]) {
            $.each(this._plugins, function (name, plugin) {
                if (plugin.onTrigger) {
                    plugin.onTrigger(event);
                }
            });
            this.register({ type: Owl.Type.Event, name: name });
            this.$element.trigger(event);
            if (this.settings && typeof this.settings[handler] === 'function') {
                this.settings[handler].call(this, event);
            }
        }
        return event;
    };
    /**
     * Enters a state.
     * @param name - The state name.
     */
    Owl.prototype.enter = function (name) {
        $.each([name].concat(this._states.tags[name] || []), $.proxy(function (i, name) {
            if (this._states.current[name] === undefined) {
                this._states.current[name] = 0;
            }
            this._states.current[name]++;
        }, this));
    };
    /**
     * Leaves a state.
     * @param name - The state name.
     */
    Owl.prototype.leave = function (name) {
        $.each([name].concat(this._states.tags[name] || []), $.proxy(function (i, name) {
            this._states.current[name]--;
        }, this));
    };
    /**
     * Registers an event or state.
     * @public
     * @param {Object} object - The event or state to register.
     */
    Owl.prototype.register = function (object) {
        if (object.type === Owl.Type.Event) {
            if (!$.event.special[object.name]) {
                $.event.special[object.name] = {};
            }
            if (!$.event.special[object.name].owl) {
                var _default = $.event.special[object.name]._default;
                $.event.special[object.name]._default = function (e) {
                    if (_default && _default.apply && (!e.namespace || e.namespace.indexOf('owl') === -1)) {
                        return _default.apply(this, arguments);
                    }
                    return e.namespace && e.namespace.indexOf('owl') > -1;
                };
                $.event.special[object.name].owl = true;
            }
        }
        else if (object.type === Owl.Type.State) {
            if (!this._states.tags[object.name]) {
                this._states.tags[object.name] = object.tags;
            }
            else {
                this._states.tags[object.name] = this._states.tags[object.name].concat(object.tags);
            }
            this._states.tags[object.name] = $.grep(this._states.tags[object.name], $.proxy(function (tag, i) {
                return $.inArray(tag, this._states.tags[object.name]) === i;
            }, this));
        }
    };
    /**
     * Suppresses events.
     * @protected
     * @param {Array.<String>} events - The events to suppress.
     */
    Owl.prototype.suppress = function (events) {
        $.each(events, $.proxy(function (index, event) {
            this._supress[event] = true;
        }, this));
    };
    /**
     * Releases suppressed events.
     * @protected
     * @param {Array.<String>} events - The events to release.
     */
    Owl.prototype.release = function (events) {
        $.each(events, $.proxy(function (index, event) {
            delete this._supress[event];
        }, this));
    };
    /**
     * Gets unified pointer coordinates from event.
     * @todo #261
     * @protected
     * @param {Event} - The `mousedown` or `touchstart` event.
     * @returns {Object} - Contains `x` and `y` coordinates of current pointer position.
     */
    Owl.prototype.pointer = function (event) {
        var result = { x: null, y: null };
        event = event.originalEvent || event || window.event;
        event = event.touches && event.touches.length ?
            event.touches[0] : event.changedTouches && event.changedTouches.length ?
            event.changedTouches[0] : event;
        if (event.pageX) {
            result.x = event.pageX;
            result.y = event.pageY;
        }
        else {
            result.x = event.clientX;
            result.y = event.clientY;
        }
        return result;
    };
    /**
     * Determines if the input is a Number or something that can be coerced to a Number
     * @protected
     * @param {Number|String|Object|Array|Boolean|RegExp|Function|Symbol} - The input to be tested
     * @returns {Boolean} - An indication if the input is a Number or can be coerced to a Number
     */
    Owl.prototype.isNumeric = function (number) {
        return !isNaN(parseFloat(number));
    };
    /**
     * Gets the difference of two vectors.
     * @todo #261
     * @protected
     * @param {Object} - The first vector.
     * @param {Object} - The second vector.
     * @returns {Object} - The difference.
     */
    Owl.prototype.difference = function (first, second) {
        return {
            x: first.x - second.x,
            y: first.y - second.y
        };
    };
    /**
     * The jQuery Plugin for the Owl Carousel
     * @todo Navigation plugin `next` and `prev`
     * @public
     */
    $.fn.owlCarousel = function (option) {
        var args = Array.prototype.slice.call(arguments, 1);
        return this.each(function () {
            var $this = $(this), data = $this.data('owl.carousel');
            if (!data) {
                data = new Owl(this, typeof option == 'object' && option);
                $this.data('owl.carousel', data);
                $.each([
                    'next', 'prev', 'to', 'destroy', 'refresh', 'replace', 'add', 'remove'
                ], function (i, event) {
                    data.register({ type: Owl.Type.Event, name: event });
                    data.$element.on(event + '.owl.carousel.core', $.proxy(function (e) {
                        if (e.namespace && e.relatedTarget !== this) {
                            this.suppress([event]);
                            data[event].apply(this, [].slice.call(arguments, 1));
                            this.release([event]);
                        }
                    }, data));
                });
            }
            if (typeof option == 'string' && option.charAt(0) !== '_') {
                data[option].apply(data, args);
            }
        });
    };
    /**
     * The constructor for the jQuery Plugin
     * @public
     */
    $.fn.owlCarousel.Constructor = Owl;
})(window.Zepto || window.jQuery, window, document);
/**
 * AutoRefresh Plugin
 * @version 2.1.0
 * @author Artus Kolanowski
 * @author David Deutsch
 * @license The MIT License (MIT)
 */
;
(function ($, window, document, undefined) {
    /**
     * Creates the auto refresh plugin.
     * @class The Auto Refresh Plugin
     * @param {Owl} carousel - The Owl Carousel
     */
    var AutoRefresh = function (carousel) {
        /**
         * Reference to the core.
         * @protected
         * @type {Owl}
         */
        this._core = carousel;
        /**
         * Refresh interval.
         * @protected
         * @type {number}
         */
        this._interval = null;
        /**
         * Whether the element is currently visible or not.
         * @protected
         * @type {Boolean}
         */
        this._visible = null;
        /**
         * All event handlers.
         * @protected
         * @type {Object}
         */
        this._handlers = {
            'initialized.owl.carousel': $.proxy(function (e) {
                if (e.namespace && this._core.settings.autoRefresh) {
                    this.watch();
                }
            }, this)
        };
        // set default options
        this._core.options = $.extend({}, AutoRefresh.Defaults, this._core.options);
        // register event handlers
        this._core.$element.on(this._handlers);
    };
    /**
     * Default options.
     * @public
     */
    AutoRefresh.Defaults = {
        autoRefresh: true,
        autoRefreshInterval: 500
    };
    /**
     * Watches the element.
     */
    AutoRefresh.prototype.watch = function () {
        if (this._interval) {
            return;
        }
        this._visible = this._core.$element.is(':visible');
        this._interval = window.setInterval($.proxy(this.refresh, this), this._core.settings.autoRefreshInterval);
    };
    /**
     * Refreshes the element.
     */
    AutoRefresh.prototype.refresh = function () {
        if (this._core.$element.is(':visible') === this._visible) {
            return;
        }
        this._visible = !this._visible;
        this._core.$element.toggleClass('owl-hidden', !this._visible);
        this._visible && (this._core.invalidate('width') && this._core.refresh());
    };
    /**
     * Destroys the plugin.
     */
    AutoRefresh.prototype.destroy = function () {
        var handler, property;
        window.clearInterval(this._interval);
        for (handler in this._handlers) {
            this._core.$element.off(handler, this._handlers[handler]);
        }
        for (property in Object.getOwnPropertyNames(this)) {
            typeof this[property] != 'function' && (this[property] = null);
        }
    };
    $.fn.owlCarousel.Constructor.Plugins.AutoRefresh = AutoRefresh;
})(window.Zepto || window.jQuery, window, document);
/**
 * Lazy Plugin
 * @version 2.1.0
 * @author Bartosz Wojciechowski
 * @author David Deutsch
 * @license The MIT License (MIT)
 */
;
(function ($, window, document, undefined) {
    /**
     * Creates the lazy plugin.
     * @class The Lazy Plugin
     * @param {Owl} carousel - The Owl Carousel
     */
    var Lazy = function (carousel) {
        /**
         * Reference to the core.
         * @protected
         * @type {Owl}
         */
        this._core = carousel;
        /**
         * Already loaded items.
         * @protected
         * @type {Array.<jQuery>}
         */
        this._loaded = [];
        /**
         * Event handlers.
         * @protected
         * @type {Object}
         */
        this._handlers = {
            'initialized.owl.carousel change.owl.carousel resized.owl.carousel': $.proxy(function (e) {
                if (!e.namespace) {
                    return;
                }
                if (!this._core.settings || !this._core.settings.lazyLoad) {
                    return;
                }
                if ((e.property && e.property.name == 'position') || e.type == 'initialized') {
                    var settings = this._core.settings, n = (settings.center && Math.ceil(settings.items / 2) || settings.items), i = ((settings.center && n * -1) || 0), position = (e.property && e.property.value !== undefined ? e.property.value : this._core.current()) + i, clones = this._core.clones().length, load = $.proxy(function (i, v) { this.load(v); }, this);
                    while (i++ < n) {
                        this.load(clones / 2 + this._core.relative(position));
                        clones && $.each(this._core.clones(this._core.relative(position)), load);
                        position++;
                    }
                }
            }, this)
        };
        // set the default options
        this._core.options = $.extend({}, Lazy.Defaults, this._core.options);
        // register event handler
        this._core.$element.on(this._handlers);
    };
    /**
     * Default options.
     * @public
     */
    Lazy.Defaults = {
        lazyLoad: false
    };
    /**
     * Loads all resources of an item at the specified position.
     * @param {Number} position - The absolute position of the item.
     * @protected
     */
    Lazy.prototype.load = function (position) {
        var $item = this._core.$stage.children().eq(position), $elements = $item && $item.find('.owl-lazy');
        if (!$elements || $.inArray($item.get(0), this._loaded) > -1) {
            return;
        }
        $elements.each($.proxy(function (index, element) {
            var $element = $(element), image, url = (window.devicePixelRatio > 1 && $element.attr('data-src-retina')) || $element.attr('data-src');
            this._core.trigger('load', { element: $element, url: url }, 'lazy');
            if ($element.is('img')) {
                $element.one('load.owl.lazy', $.proxy(function () {
                    $element.css('opacity', 1);
                    this._core.trigger('loaded', { element: $element, url: url }, 'lazy');
                }, this)).attr('src', url);
            }
            else {
                image = new Image();
                image.onload = $.proxy(function () {
                    $element.css({
                        'background-image': 'url(' + url + ')',
                        'opacity': '1'
                    });
                    this._core.trigger('loaded', { element: $element, url: url }, 'lazy');
                }, this);
                image.src = url;
            }
        }, this));
        this._loaded.push($item.get(0));
    };
    /**
     * Destroys the plugin.
     * @public
     */
    Lazy.prototype.destroy = function () {
        var handler, property;
        for (handler in this.handlers) {
            this._core.$element.off(handler, this.handlers[handler]);
        }
        for (property in Object.getOwnPropertyNames(this)) {
            typeof this[property] != 'function' && (this[property] = null);
        }
    };
    $.fn.owlCarousel.Constructor.Plugins.Lazy = Lazy;
})(window.Zepto || window.jQuery, window, document);
/**
 * AutoHeight Plugin
 * @version 2.1.0
 * @author Bartosz Wojciechowski
 * @author David Deutsch
 * @license The MIT License (MIT)
 */
;
(function ($, window, document, undefined) {
    /**
     * Creates the auto height plugin.
     * @class The Auto Height Plugin
     * @param {Owl} carousel - The Owl Carousel
     */
    var AutoHeight = function (carousel) {
        /**
         * Reference to the core.
         * @protected
         * @type {Owl}
         */
        this._core = carousel;
        /**
         * All event handlers.
         * @protected
         * @type {Object}
         */
        this._handlers = {
            'initialized.owl.carousel refreshed.owl.carousel': $.proxy(function (e) {
                if (e.namespace && this._core.settings.autoHeight) {
                    this.update();
                }
            }, this),
            'changed.owl.carousel': $.proxy(function (e) {
                if (e.namespace && this._core.settings.autoHeight && e.property.name == 'position') {
                    this.update();
                }
            }, this),
            'loaded.owl.lazy': $.proxy(function (e) {
                if (e.namespace && this._core.settings.autoHeight
                    && e.element.closest('.' + this._core.settings.itemClass).index() === this._core.current()) {
                    this.update();
                }
            }, this)
        };
        // set default options
        this._core.options = $.extend({}, AutoHeight.Defaults, this._core.options);
        // register event handlers
        this._core.$element.on(this._handlers);
    };
    /**
     * Default options.
     * @public
     */
    AutoHeight.Defaults = {
        autoHeight: false,
        autoHeightClass: 'owl-height'
    };
    /**
     * Updates the view.
     */
    AutoHeight.prototype.update = function () {
        var start = this._core._current, end = start + this._core.settings.items, visible = this._core.$stage.children().toArray().slice(start, end), heights = [], maxheight = 0;
        $.each(visible, function (index, item) {
            heights.push($(item).height());
        });
        maxheight = Math.max.apply(null, heights);
        this._core.$stage.parent()
            .height(maxheight)
            .addClass(this._core.settings.autoHeightClass);
    };
    AutoHeight.prototype.destroy = function () {
        var handler, property;
        for (handler in this._handlers) {
            this._core.$element.off(handler, this._handlers[handler]);
        }
        for (property in Object.getOwnPropertyNames(this)) {
            typeof this[property] != 'function' && (this[property] = null);
        }
    };
    $.fn.owlCarousel.Constructor.Plugins.AutoHeight = AutoHeight;
})(window.Zepto || window.jQuery, window, document);
/**
 * Video Plugin
 * @version 2.1.0
 * @author Bartosz Wojciechowski
 * @author David Deutsch
 * @license The MIT License (MIT)
 */
;
(function ($, window, document, undefined) {
    /**
     * Creates the video plugin.
     * @class The Video Plugin
     * @param {Owl} carousel - The Owl Carousel
     */
    var Video = function (carousel) {
        /**
         * Reference to the core.
         * @protected
         * @type {Owl}
         */
        this._core = carousel;
        /**
         * Cache all video URLs.
         * @protected
         * @type {Object}
         */
        this._videos = {};
        /**
         * Current playing item.
         * @protected
         * @type {jQuery}
         */
        this._playing = null;
        /**
         * All event handlers.
         * @todo The cloned content removale is too late
         * @protected
         * @type {Object}
         */
        this._handlers = {
            'initialized.owl.carousel': $.proxy(function (e) {
                if (e.namespace) {
                    this._core.register({ type: 'state', name: 'playing', tags: ['interacting'] });
                }
            }, this),
            'resize.owl.carousel': $.proxy(function (e) {
                if (e.namespace && this._core.settings.video && this.isInFullScreen()) {
                    e.preventDefault();
                }
            }, this),
            'refreshed.owl.carousel': $.proxy(function (e) {
                if (e.namespace && this._core.is('resizing')) {
                    this._core.$stage.find('.cloned .owl-video-frame').remove();
                }
            }, this),
            'changed.owl.carousel': $.proxy(function (e) {
                if (e.namespace && e.property.name === 'position' && this._playing) {
                    this.stop();
                }
            }, this),
            'prepared.owl.carousel': $.proxy(function (e) {
                if (!e.namespace) {
                    return;
                }
                var $element = $(e.content).find('.owl-video');
                if ($element.length) {
                    $element.css('display', 'none');
                    this.fetch($element, $(e.content));
                }
            }, this)
        };
        // set default options
        this._core.options = $.extend({}, Video.Defaults, this._core.options);
        // register event handlers
        this._core.$element.on(this._handlers);
        this._core.$element.on('click.owl.video', '.owl-video-play-icon', $.proxy(function (e) {
            this.play(e);
        }, this));
    };
    /**
     * Default options.
     * @public
     */
    Video.Defaults = {
        video: false,
        videoHeight: false,
        videoWidth: false
    };
    /**
     * Gets the video ID and the type (YouTube/Vimeo/vzaar only).
     * @protected
     * @param {jQuery} target - The target containing the video data.
     * @param {jQuery} item - The item containing the video.
     */
    Video.prototype.fetch = function (target, item) {
        var type = (function () {
            if (target.attr('data-vimeo-id')) {
                return 'vimeo';
            }
            else if (target.attr('data-vzaar-id')) {
                return 'vzaar';
            }
            else {
                return 'youtube';
            }
        })(), id = target.attr('data-vimeo-id') || target.attr('data-youtube-id') || target.attr('data-vzaar-id'), width = target.attr('data-width') || this._core.settings.videoWidth, height = target.attr('data-height') || this._core.settings.videoHeight, url = target.attr('href');
        if (url) {
            /*
                    Parses the id's out of the following urls (and probably more):
                    https://www.youtube.com/watch?v=:id
                    https://youtu.be/:id
                    https://vimeo.com/:id
                    https://vimeo.com/channels/:channel/:id
                    https://vimeo.com/groups/:group/videos/:id
                    https://app.vzaar.com/videos/:id

                    Visual example: https://regexper.com/#(http%3A%7Chttps%3A%7C)%5C%2F%5C%2F(player.%7Cwww.%7Capp.)%3F(vimeo%5C.com%7Cyoutu(be%5C.com%7C%5C.be%7Cbe%5C.googleapis%5C.com)%7Cvzaar%5C.com)%5C%2F(video%5C%2F%7Cvideos%5C%2F%7Cembed%5C%2F%7Cchannels%5C%2F.%2B%5C%2F%7Cgroups%5C%2F.%2B%5C%2F%7Cwatch%5C%3Fv%3D%7Cv%5C%2F)%3F(%5BA-Za-z0-9._%25-%5D*)(%5C%26%5CS%2B)%3F
            */
            id = url.match(/(http:|https:|)\/\/(player.|www.|app.)?(vimeo\.com|youtu(be\.com|\.be|be\.googleapis\.com)|vzaar\.com)\/(video\/|videos\/|embed\/|channels\/.+\/|groups\/.+\/|watch\?v=|v\/)?([A-Za-z0-9._%-]*)(\&\S+)?/);
            if (id[3].indexOf('youtu') > -1) {
                type = 'youtube';
            }
            else if (id[3].indexOf('vimeo') > -1) {
                type = 'vimeo';
            }
            else if (id[3].indexOf('vzaar') > -1) {
                type = 'vzaar';
            }
            else {
                throw new Error('Video URL not supported.');
            }
            id = id[6];
        }
        else {
            throw new Error('Missing video URL.');
        }
        this._videos[url] = {
            type: type,
            id: id,
            width: width,
            height: height
        };
        item.attr('data-video', url);
        this.thumbnail(target, this._videos[url]);
    };
    /**
     * Creates video thumbnail.
     * @protected
     * @param {jQuery} target - The target containing the video data.
     * @param {Object} info - The video info object.
     * @see `fetch`
     */
    Video.prototype.thumbnail = function (target, video) {
        var tnLink, icon, path, dimensions = video.width && video.height ? 'style="width:' + video.width + 'px;height:' + video.height + 'px;"' : '', customTn = target.find('img'), srcType = 'src', lazyClass = '', settings = this._core.settings, create = function (path) {
            icon = '<div class="owl-video-play-icon"></div>';
            if (settings.lazyLoad) {
                tnLink = '<div class="owl-video-tn ' + lazyClass + '" ' + srcType + '="' + path + '"></div>';
            }
            else {
                tnLink = '<div class="owl-video-tn" style="opacity:1;background-image:url(' + path + ')"></div>';
            }
            target.after(tnLink);
            target.after(icon);
        };
        // wrap video content into owl-video-wrapper div
        target.wrap('<div class="owl-video-wrapper"' + dimensions + '></div>');
        if (this._core.settings.lazyLoad) {
            srcType = 'data-src';
            lazyClass = 'owl-lazy';
        }
        // custom thumbnail
        if (customTn.length) {
            create(customTn.attr(srcType));
            customTn.remove();
            return false;
        }
        if (video.type === 'youtube') {
            path = "//img.youtube.com/vi/" + video.id + "/hqdefault.jpg";
            create(path);
        }
        else if (video.type === 'vimeo') {
            $.ajax({
                type: 'GET',
                url: '//vimeo.com/api/v2/video/' + video.id + '.json',
                jsonp: 'callback',
                dataType: 'jsonp',
                success: function (data) {
                    path = data[0].thumbnail_large;
                    create(path);
                }
            });
        }
        else if (video.type === 'vzaar') {
            $.ajax({
                type: 'GET',
                url: '//vzaar.com/api/videos/' + video.id + '.json',
                jsonp: 'callback',
                dataType: 'jsonp',
                success: function (data) {
                    path = data.framegrab_url;
                    create(path);
                }
            });
        }
    };
    /**
     * Stops the current video.
     * @public
     */
    Video.prototype.stop = function () {
        this._core.trigger('stop', null, 'video');
        this._playing.find('.owl-video-frame').remove();
        this._playing.removeClass('owl-video-playing');
        this._playing = null;
        this._core.leave('playing');
        this._core.trigger('stopped', null, 'video');
    };
    /**
     * Starts the current video.
     * @public
     * @param {Event} event - The event arguments.
     */
    Video.prototype.play = function (event) {
        var target = $(event.target), item = target.closest('.' + this._core.settings.itemClass), video = this._videos[item.attr('data-video')], width = video.width || '100%', height = video.height || this._core.$stage.height(), html;
        if (this._playing) {
            return;
        }
        this._core.enter('playing');
        this._core.trigger('play', null, 'video');
        item = this._core.items(this._core.relative(item.index()));
        this._core.reset(item.index());
        if (video.type === 'youtube') {
            html = '<iframe width="' + width + '" height="' + height + '" src="//www.youtube.com/embed/' +
                video.id + '?autoplay=1&v=' + video.id + '" frameborder="0" allowfullscreen></iframe>';
        }
        else if (video.type === 'vimeo') {
            html = '<iframe src="//player.vimeo.com/video/' + video.id +
                '?autoplay=1" width="' + width + '" height="' + height +
                '" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>';
        }
        else if (video.type === 'vzaar') {
            html = '<iframe frameborder="0"' + 'height="' + height + '"' + 'width="' + width +
                '" allowfullscreen mozallowfullscreen webkitAllowFullScreen ' +
                'src="//view.vzaar.com/' + video.id + '/player?autoplay=true"></iframe>';
        }
        $('<div class="owl-video-frame">' + html + '</div>').insertAfter(item.find('.owl-video'));
        this._playing = item.addClass('owl-video-playing');
    };
    /**
     * Checks whether an video is currently in full screen mode or not.
     * @todo Bad style because looks like a readonly method but changes members.
     * @protected
     * @returns {Boolean}
     */
    Video.prototype.isInFullScreen = function () {
        var element = document.fullscreenElement || document.mozFullScreenElement ||
            document.webkitFullscreenElement;
        return element && $(element).parent().hasClass('owl-video-frame');
    };
    /**
     * Destroys the plugin.
     */
    Video.prototype.destroy = function () {
        var handler, property;
        this._core.$element.off('click.owl.video');
        for (handler in this._handlers) {
            this._core.$element.off(handler, this._handlers[handler]);
        }
        for (property in Object.getOwnPropertyNames(this)) {
            typeof this[property] != 'function' && (this[property] = null);
        }
    };
    $.fn.owlCarousel.Constructor.Plugins.Video = Video;
})(window.Zepto || window.jQuery, window, document);
/**
 * Animate Plugin
 * @version 2.1.0
 * @author Bartosz Wojciechowski
 * @author David Deutsch
 * @license The MIT License (MIT)
 */
;
(function ($, window, document, undefined) {
    /**
     * Creates the animate plugin.
     * @class The Navigation Plugin
     * @param {Owl} scope - The Owl Carousel
     */
    var Animate = function (scope) {
        this.core = scope;
        this.core.options = $.extend({}, Animate.Defaults, this.core.options);
        this.swapping = true;
        this.previous = undefined;
        this.next = undefined;
        this.handlers = {
            'change.owl.carousel': $.proxy(function (e) {
                if (e.namespace && e.property.name == 'position') {
                    this.previous = this.core.current();
                    this.next = e.property.value;
                }
            }, this),
            'drag.owl.carousel dragged.owl.carousel translated.owl.carousel': $.proxy(function (e) {
                if (e.namespace) {
                    this.swapping = e.type == 'translated';
                }
            }, this),
            'translate.owl.carousel': $.proxy(function (e) {
                if (e.namespace && this.swapping && (this.core.options.animateOut || this.core.options.animateIn)) {
                    this.swap();
                }
            }, this)
        };
        this.core.$element.on(this.handlers);
    };
    /**
     * Default options.
     * @public
     */
    Animate.Defaults = {
        animateOut: false,
        animateIn: false
    };
    /**
     * Toggles the animation classes whenever an translations starts.
     * @protected
     * @returns {Boolean|undefined}
     */
    Animate.prototype.swap = function () {
        if (this.core.settings.items !== 1) {
            return;
        }
        if (!$.support.animation || !$.support.transition) {
            return;
        }
        this.core.speed(0);
        var left, clear = $.proxy(this.clear, this), previous = this.core.$stage.children().eq(this.previous), next = this.core.$stage.children().eq(this.next), incoming = this.core.settings.animateIn, outgoing = this.core.settings.animateOut;
        if (this.core.current() === this.previous) {
            return;
        }
        if (outgoing) {
            left = this.core.coordinates(this.previous) - this.core.coordinates(this.next);
            previous.one($.support.animation.end, clear)
                .css({ 'left': left + 'px' })
                .addClass('animated owl-animated-out')
                .addClass(outgoing);
        }
        if (incoming) {
            next.one($.support.animation.end, clear)
                .addClass('animated owl-animated-in')
                .addClass(incoming);
        }
    };
    Animate.prototype.clear = function (e) {
        $(e.target).css({ 'left': '' })
            .removeClass('animated owl-animated-out owl-animated-in')
            .removeClass(this.core.settings.animateIn)
            .removeClass(this.core.settings.animateOut);
        this.core.onTransitionEnd();
    };
    /**
     * Destroys the plugin.
     * @public
     */
    Animate.prototype.destroy = function () {
        var handler, property;
        for (handler in this.handlers) {
            this.core.$element.off(handler, this.handlers[handler]);
        }
        for (property in Object.getOwnPropertyNames(this)) {
            typeof this[property] != 'function' && (this[property] = null);
        }
    };
    $.fn.owlCarousel.Constructor.Plugins.Animate = Animate;
})(window.Zepto || window.jQuery, window, document);
/**
 * Autoplay Plugin
 * @version 2.1.0
 * @author Bartosz Wojciechowski
 * @author Artus Kolanowski
 * @author David Deutsch
 * @license The MIT License (MIT)
 */
;
(function ($, window, document, undefined) {
    /**
     * Creates the autoplay plugin.
     * @class The Autoplay Plugin
     * @param {Owl} scope - The Owl Carousel
     */
    var Autoplay = function (carousel) {
        /**
         * Reference to the core.
         * @protected
         * @type {Owl}
         */
        this._core = carousel;
        /**
         * The autoplay timeout.
         * @type {Timeout}
         */
        this._timeout = null;
        /**
         * Indicates whenever the autoplay is paused.
         * @type {Boolean}
         */
        this._paused = false;
        /**
         * All event handlers.
         * @protected
         * @type {Object}
         */
        this._handlers = {
            'changed.owl.carousel': $.proxy(function (e) {
                if (e.namespace && e.property.name === 'settings') {
                    if (this._core.settings.autoplay) {
                        this.play();
                    }
                    else {
                        this.stop();
                    }
                }
                else if (e.namespace && e.property.name === 'position') {
                    //console.log('play?', e);
                    if (this._core.settings.autoplay) {
                        this._setAutoPlayInterval();
                    }
                }
            }, this),
            'initialized.owl.carousel': $.proxy(function (e) {
                if (e.namespace && this._core.settings.autoplay) {
                    this.play();
                }
            }, this),
            'play.owl.autoplay': $.proxy(function (e, t, s) {
                if (e.namespace) {
                    this.play(t, s);
                }
            }, this),
            'stop.owl.autoplay': $.proxy(function (e) {
                if (e.namespace) {
                    this.stop();
                }
            }, this),
            'mouseover.owl.autoplay': $.proxy(function () {
                if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) {
                    this.pause();
                }
            }, this),
            'mouseleave.owl.autoplay': $.proxy(function () {
                if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) {
                    this.play();
                }
            }, this),
            'touchstart.owl.core': $.proxy(function () {
                if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) {
                    this.pause();
                }
            }, this),
            'touchend.owl.core': $.proxy(function () {
                if (this._core.settings.autoplayHoverPause) {
                    this.play();
                }
            }, this)
        };
        // register event handlers
        this._core.$element.on(this._handlers);
        // set default options
        this._core.options = $.extend({}, Autoplay.Defaults, this._core.options);
    };
    /**
     * Default options.
     * @public
     */
    Autoplay.Defaults = {
        autoplay: false,
        autoplayTimeout: 5000,
        autoplayHoverPause: false,
        autoplaySpeed: false
    };
    /**
     * Starts the autoplay.
     * @public
     * @param {Number} [timeout] - The interval before the next animation starts.
     * @param {Number} [speed] - The animation speed for the animations.
     */
    Autoplay.prototype.play = function (timeout, speed) {
        this._paused = false;
        if (this._core.is('rotating')) {
            return;
        }
        this._core.enter('rotating');
        this._setAutoPlayInterval();
    };
    /**
     * Gets a new timeout
     * @private
     * @param {Number} [timeout] - The interval before the next animation starts.
     * @param {Number} [speed] - The animation speed for the animations.
     * @return {Timeout}
     */
    Autoplay.prototype._getNextTimeout = function (timeout, speed) {
        if (this._timeout) {
            window.clearTimeout(this._timeout);
        }
        return window.setTimeout($.proxy(function () {
            if (this._paused || this._core.is('busy') || this._core.is('interacting') || document.hidden) {
                return;
            }
            this._core.next(speed || this._core.settings.autoplaySpeed);
        }, this), timeout || this._core.settings.autoplayTimeout);
    };
    /**
     * Sets autoplay in motion.
     * @private
     */
    Autoplay.prototype._setAutoPlayInterval = function () {
        this._timeout = this._getNextTimeout();
    };
    /**
     * Stops the autoplay.
     * @public
     */
    Autoplay.prototype.stop = function () {
        if (!this._core.is('rotating')) {
            return;
        }
        window.clearTimeout(this._timeout);
        this._core.leave('rotating');
    };
    /**
     * Stops the autoplay.
     * @public
     */
    Autoplay.prototype.pause = function () {
        if (!this._core.is('rotating')) {
            return;
        }
        this._paused = true;
    };
    /**
     * Destroys the plugin.
     */
    Autoplay.prototype.destroy = function () {
        var handler, property;
        this.stop();
        for (handler in this._handlers) {
            this._core.$element.off(handler, this._handlers[handler]);
        }
        for (property in Object.getOwnPropertyNames(this)) {
            typeof this[property] != 'function' && (this[property] = null);
        }
    };
    $.fn.owlCarousel.Constructor.Plugins.autoplay = Autoplay;
})(window.Zepto || window.jQuery, window, document);
/**
 * Navigation Plugin
 * @version 2.1.0
 * @author Artus Kolanowski
 * @author David Deutsch
 * @license The MIT License (MIT)
 */
;
(function ($, window, document, undefined) {
    'use strict';
    /**
     * Creates the navigation plugin.
     * @class The Navigation Plugin
     * @param {Owl} carousel - The Owl Carousel.
     */
    var Navigation = function (carousel) {
        /**
         * Reference to the core.
         * @protected
         * @type {Owl}
         */
        this._core = carousel;
        /**
         * Indicates whether the plugin is initialized or not.
         * @protected
         * @type {Boolean}
         */
        this._initialized = false;
        /**
         * The current paging indexes.
         * @protected
         * @type {Array}
         */
        this._pages = [];
        /**
         * All DOM elements of the user interface.
         * @protected
         * @type {Object}
         */
        this._controls = {};
        /**
         * Markup for an indicator.
         * @protected
         * @type {Array.<String>}
         */
        this._templates = [];
        /**
         * The carousel element.
         * @type {jQuery}
         */
        this.$element = this._core.$element;
        /**
         * Overridden methods of the carousel.
         * @protected
         * @type {Object}
         */
        this._overrides = {
            next: this._core.next,
            prev: this._core.prev,
            to: this._core.to
        };
        /**
         * All event handlers.
         * @protected
         * @type {Object}
         */
        this._handlers = {
            'prepared.owl.carousel': $.proxy(function (e) {
                if (e.namespace && this._core.settings.dotsData) {
                    this._templates.push('<div class="' + this._core.settings.dotClass + '">' +
                        $(e.content).find('[data-dot]').addBack('[data-dot]').attr('data-dot') + '</div>');
                }
            }, this),
            'added.owl.carousel': $.proxy(function (e) {
                if (e.namespace && this._core.settings.dotsData) {
                    this._templates.splice(e.position, 0, this._templates.pop());
                }
            }, this),
            'remove.owl.carousel': $.proxy(function (e) {
                if (e.namespace && this._core.settings.dotsData) {
                    this._templates.splice(e.position, 1);
                }
            }, this),
            'changed.owl.carousel': $.proxy(function (e) {
                if (e.namespace && e.property.name == 'position') {
                    this.draw();
                }
            }, this),
            'initialized.owl.carousel': $.proxy(function (e) {
                if (e.namespace && !this._initialized) {
                    this._core.trigger('initialize', null, 'navigation');
                    this.initialize();
                    this.update();
                    this.draw();
                    this._initialized = true;
                    this._core.trigger('initialized', null, 'navigation');
                }
            }, this),
            'refreshed.owl.carousel': $.proxy(function (e) {
                if (e.namespace && this._initialized) {
                    this._core.trigger('refresh', null, 'navigation');
                    this.update();
                    this.draw();
                    this._core.trigger('refreshed', null, 'navigation');
                }
            }, this)
        };
        // set default options
        this._core.options = $.extend({}, Navigation.Defaults, this._core.options);
        // register event handlers
        this.$element.on(this._handlers);
    };
    /**
     * Default options.
     * @public
     * @todo Rename `slideBy` to `navBy`
     */
    Navigation.Defaults = {
        nav: false,
        navText: ['prev', 'next'],
        navSpeed: false,
        navElement: 'div',
        navContainer: false,
        navContainerClass: 'owl-nav',
        navClass: ['owl-prev', 'owl-next'],
        slideBy: 1,
        dotClass: 'owl-dot',
        dotsClass: 'owl-dots',
        dots: true,
        dotsEach: false,
        dotsData: false,
        dotsSpeed: false,
        dotsContainer: false
    };
    /**
     * Initializes the layout of the plugin and extends the carousel.
     * @protected
     */
    Navigation.prototype.initialize = function () {
        var override, settings = this._core.settings;
        // create DOM structure for relative navigation
        this._controls.$relative = (settings.navContainer ? $(settings.navContainer)
            : $('<div>').addClass(settings.navContainerClass).appendTo(this.$element)).addClass('disabled');
        this._controls.$previous = $('<' + settings.navElement + '>')
            .addClass(settings.navClass[0])
            .html(settings.navText[0])
            .prependTo(this._controls.$relative)
            .on('click', $.proxy(function (e) {
            this.prev(settings.navSpeed);
        }, this));
        this._controls.$next = $('<' + settings.navElement + '>')
            .addClass(settings.navClass[1])
            .html(settings.navText[1])
            .appendTo(this._controls.$relative)
            .on('click', $.proxy(function (e) {
            this.next(settings.navSpeed);
        }, this));
        // create DOM structure for absolute navigation
        if (!settings.dotsData) {
            this._templates = [$('<div>')
                    .addClass(settings.dotClass)
                    .append($('<span>'))
                    .prop('outerHTML')];
        }
        this._controls.$absolute = (settings.dotsContainer ? $(settings.dotsContainer)
            : $('<div>').addClass(settings.dotsClass).appendTo(this.$element)).addClass('disabled');
        this._controls.$absolute.on('click', 'div', $.proxy(function (e) {
            var index = $(e.target).parent().is(this._controls.$absolute)
                ? $(e.target).index() : $(e.target).parent().index();
            e.preventDefault();
            this.to(index, settings.dotsSpeed);
        }, this));
        // override public methods of the carousel
        for (override in this._overrides) {
            this._core[override] = $.proxy(this[override], this);
        }
    };
    /**
     * Destroys the plugin.
     * @protected
     */
    Navigation.prototype.destroy = function () {
        var handler, control, property, override;
        for (handler in this._handlers) {
            this.$element.off(handler, this._handlers[handler]);
        }
        for (control in this._controls) {
            this._controls[control].remove();
        }
        for (override in this.overides) {
            this._core[override] = this._overrides[override];
        }
        for (property in Object.getOwnPropertyNames(this)) {
            typeof this[property] != 'function' && (this[property] = null);
        }
    };
    /**
     * Updates the internal state.
     * @protected
     */
    Navigation.prototype.update = function () {
        var i, j, k, lower = this._core.clones().length / 2, upper = lower + this._core.items().length, maximum = this._core.maximum(true), settings = this._core.settings, size = settings.center || settings.autoWidth || settings.dotsData
            ? 1 : settings.dotsEach || settings.items;
        if (settings.slideBy !== 'page') {
            settings.slideBy = Math.min(settings.slideBy, settings.items);
        }
        if (settings.dots || settings.slideBy == 'page') {
            this._pages = [];
            for (i = lower, j = 0, k = 0; i < upper; i++) {
                if (j >= size || j === 0) {
                    this._pages.push({
                        start: Math.min(maximum, i - lower),
                        end: i - lower + size - 1
                    });
                    if (Math.min(maximum, i - lower) === maximum) {
                        break;
                    }
                    j = 0, ++k;
                }
                j += this._core.mergers(this._core.relative(i));
            }
        }
    };
    /**
     * Draws the user interface.
     * @todo The option `dotsData` wont work.
     * @protected
     */
    Navigation.prototype.draw = function () {
        var difference, settings = this._core.settings, disabled = this._core.items().length <= settings.items, index = this._core.relative(this._core.current()), loop = settings.loop || settings.rewind;
        this._controls.$relative.toggleClass('disabled', !settings.nav || disabled);
        if (settings.nav) {
            this._controls.$previous.toggleClass('disabled', !loop && index <= this._core.minimum(true));
            this._controls.$next.toggleClass('disabled', !loop && index >= this._core.maximum(true));
        }
        this._controls.$absolute.toggleClass('disabled', !settings.dots || disabled);
        if (settings.dots) {
            difference = this._pages.length - this._controls.$absolute.children().length;
            if (settings.dotsData && difference !== 0) {
                this._controls.$absolute.html(this._templates.join(''));
            }
            else if (difference > 0) {
                this._controls.$absolute.append(new Array(difference + 1).join(this._templates[0]));
            }
            else if (difference < 0) {
                this._controls.$absolute.children().slice(difference).remove();
            }
            this._controls.$absolute.find('.active').removeClass('active');
            this._controls.$absolute.children().eq($.inArray(this.current(), this._pages)).addClass('active');
        }
    };
    /**
     * Extends event data.
     * @protected
     * @param {Event} event - The event object which gets thrown.
     */
    Navigation.prototype.onTrigger = function (event) {
        var settings = this._core.settings;
        event.page = {
            index: $.inArray(this.current(), this._pages),
            count: this._pages.length,
            size: settings && (settings.center || settings.autoWidth || settings.dotsData
                ? 1 : settings.dotsEach || settings.items)
        };
    };
    /**
     * Gets the current page position of the carousel.
     * @protected
     * @returns {Number}
     */
    Navigation.prototype.current = function () {
        var current = this._core.relative(this._core.current());
        return $.grep(this._pages, $.proxy(function (page, index) {
            return page.start <= current && page.end >= current;
        }, this)).pop();
    };
    /**
     * Gets the current succesor/predecessor position.
     * @protected
     * @returns {Number}
     */
    Navigation.prototype.getPosition = function (successor) {
        var position, length, settings = this._core.settings;
        if (settings.slideBy == 'page') {
            position = $.inArray(this.current(), this._pages);
            length = this._pages.length;
            successor ? ++position : --position;
            position = this._pages[((position % length) + length) % length].start;
        }
        else {
            position = this._core.relative(this._core.current());
            length = this._core.items().length;
            successor ? position += settings.slideBy : position -= settings.slideBy;
        }
        return position;
    };
    /**
     * Slides to the next item or page.
     * @public
     * @param {Number} [speed=false] - The time in milliseconds for the transition.
     */
    Navigation.prototype.next = function (speed) {
        $.proxy(this._overrides.to, this._core)(this.getPosition(true), speed);
    };
    /**
     * Slides to the previous item or page.
     * @public
     * @param {Number} [speed=false] - The time in milliseconds for the transition.
     */
    Navigation.prototype.prev = function (speed) {
        $.proxy(this._overrides.to, this._core)(this.getPosition(false), speed);
    };
    /**
     * Slides to the specified item or page.
     * @public
     * @param {Number} position - The position of the item or page.
     * @param {Number} [speed] - The time in milliseconds for the transition.
     * @param {Boolean} [standard=false] - Whether to use the standard behaviour or not.
     */
    Navigation.prototype.to = function (position, speed, standard) {
        var length;
        if (!standard && this._pages.length) {
            length = this._pages.length;
            $.proxy(this._overrides.to, this._core)(this._pages[((position % length) + length) % length].start, speed);
        }
        else {
            $.proxy(this._overrides.to, this._core)(position, speed);
        }
    };
    $.fn.owlCarousel.Constructor.Plugins.Navigation = Navigation;
})(window.Zepto || window.jQuery, window, document);
/**
 * Hash Plugin
 * @version 2.1.0
 * @author Artus Kolanowski
 * @author David Deutsch
 * @license The MIT License (MIT)
 */
;
(function ($, window, document, undefined) {
    'use strict';
    /**
     * Creates the hash plugin.
     * @class The Hash Plugin
     * @param {Owl} carousel - The Owl Carousel
     */
    var Hash = function (carousel) {
        /**
         * Reference to the core.
         * @protected
         * @type {Owl}
         */
        this._core = carousel;
        /**
         * Hash index for the items.
         * @protected
         * @type {Object}
         */
        this._hashes = {};
        /**
         * The carousel element.
         * @type {jQuery}
         */
        this.$element = this._core.$element;
        /**
         * All event handlers.
         * @protected
         * @type {Object}
         */
        this._handlers = {
            'initialized.owl.carousel': $.proxy(function (e) {
                if (e.namespace && this._core.settings.startPosition === 'URLHash') {
                    $(window).trigger('hashchange.owl.navigation');
                }
            }, this),
            'prepared.owl.carousel': $.proxy(function (e) {
                if (e.namespace) {
                    var hash = $(e.content).find('[data-hash]').addBack('[data-hash]').attr('data-hash');
                    if (!hash) {
                        return;
                    }
                    this._hashes[hash] = e.content;
                }
            }, this),
            'changed.owl.carousel': $.proxy(function (e) {
                if (e.namespace && e.property.name === 'position') {
                    var current = this._core.items(this._core.relative(this._core.current())), hash = $.map(this._hashes, function (item, hash) {
                        return item === current ? hash : null;
                    }).join();
                    if (!hash || window.location.hash.slice(1) === hash) {
                        return;
                    }
                    window.location.hash = hash;
                }
            }, this)
        };
        // set default options
        this._core.options = $.extend({}, Hash.Defaults, this._core.options);
        // register the event handlers
        this.$element.on(this._handlers);
        // register event listener for hash navigation
        $(window).on('hashchange.owl.navigation', $.proxy(function (e) {
            var hash = window.location.hash.substring(1), items = this._core.$stage.children(), position = this._hashes[hash] && items.index(this._hashes[hash]);
            if (position === undefined || position === this._core.current()) {
                return;
            }
            this._core.to(this._core.relative(position), false, true);
        }, this));
    };
    /**
     * Default options.
     * @public
     */
    Hash.Defaults = {
        URLhashListener: false
    };
    /**
     * Destroys the plugin.
     * @public
     */
    Hash.prototype.destroy = function () {
        var handler, property;
        $(window).off('hashchange.owl.navigation');
        for (handler in this._handlers) {
            this._core.$element.off(handler, this._handlers[handler]);
        }
        for (property in Object.getOwnPropertyNames(this)) {
            typeof this[property] != 'function' && (this[property] = null);
        }
    };
    $.fn.owlCarousel.Constructor.Plugins.Hash = Hash;
})(window.Zepto || window.jQuery, window, document);
/**
 * Support Plugin
 *
 * @version 2.1.0
 * @author Vivid Planet Software GmbH
 * @author Artus Kolanowski
 * @author David Deutsch
 * @license The MIT License (MIT)
 */
;
(function ($, window, document, undefined) {
    var style = $('<support>').get(0).style, prefixes = 'Webkit Moz O ms'.split(' '), events = {
        transition: {
            end: {
                WebkitTransition: 'webkitTransitionEnd',
                MozTransition: 'transitionend',
                OTransition: 'oTransitionEnd',
                transition: 'transitionend'
            }
        },
        animation: {
            end: {
                WebkitAnimation: 'webkitAnimationEnd',
                MozAnimation: 'animationend',
                OAnimation: 'oAnimationEnd',
                animation: 'animationend'
            }
        }
    }, tests = {
        csstransforms: function () {
            return !!test('transform');
        },
        csstransforms3d: function () {
            return !!test('perspective');
        },
        csstransitions: function () {
            return !!test('transition');
        },
        cssanimations: function () {
            return !!test('animation');
        }
    };
    function test(property, prefixed) {
        var result = false, upper = property.charAt(0).toUpperCase() + property.slice(1);
        $.each((property + ' ' + prefixes.join(upper + ' ') + upper).split(' '), function (i, property) {
            if (style[property] !== undefined) {
                result = prefixed ? property : true;
                return false;
            }
        });
        return result;
    }
    function prefixed(property) {
        return test(property, true);
    }
    if (tests.csstransitions()) {
        /* jshint -W053 */
        $.support.transition = new String(prefixed('transition'));
        $.support.transition.end = events.transition.end[$.support.transition];
    }
    if (tests.cssanimations()) {
        /* jshint -W053 */
        $.support.animation = new String(prefixed('animation'));
        $.support.animation.end = events.animation.end[$.support.animation];
    }
    if (tests.csstransforms()) {
        /* jshint -W053 */
        $.support.transform = new String(prefixed('transform'));
        $.support.transform3d = tests.csstransforms3d();
    }
})(window.Zepto || window.jQuery, window, document);
//# sourceMappingURL=owl.carousel.js.map 
//# sourceMappingURL=owl.carousel.js.map 
//# sourceMappingURL=owl.carousel.js.map 
//# sourceMappingURL=owl.carousel.js.map 
//# sourceMappingURL=owl.carousel.js.map 
//# sourceMappingURL=owl.carousel.js.map 
//# sourceMappingURL=owl.carousel.js.map 
//# sourceMappingURL=owl.carousel.js.map;
/*!
 * parallax.js v1.4.2 (http://pixelcog.github.io/parallax.js/)
 * @copyright 2016 PixelCog, Inc.
 * @license MIT (https://github.com/pixelcog/parallax.js/blob/master/LICENSE)
 */
;
(function ($, window, document, undefined) {
    // Polyfill for requestAnimationFrame
    // via: https://gist.github.com/paulirish/1579671
    (function () {
        var lastTime = 0;
        var vendors = ['ms', 'moz', 'webkit', 'o'];
        for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
            window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame'];
            window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame']
                || window[vendors[x] + 'CancelRequestAnimationFrame'];
        }
        if (!window.requestAnimationFrame)
            window.requestAnimationFrame = function (callback) {
                var currTime = new Date().getTime();
                var timeToCall = Math.max(0, 16 - (currTime - lastTime));
                var id = window.setTimeout(function () { callback(currTime + timeToCall); }, timeToCall);
                lastTime = currTime + timeToCall;
                return id;
            };
        if (!window.cancelAnimationFrame)
            window.cancelAnimationFrame = function (id) {
                clearTimeout(id);
            };
    }());
    // Parallax Constructor
    function Parallax(element, options) {
        var self = this;
        if (typeof options == 'object') {
            delete options.refresh;
            delete options.render;
            $.extend(this, options);
        }
        this.$element = $(element);
        if (!this.imageSrc && this.$element.is('img')) {
            this.imageSrc = this.$element.attr('src');
        }
        var positions = (this.position + '').toLowerCase().match(/\S+/g) || [];
        if (positions.length < 1) {
            positions.push('center');
        }
        if (positions.length == 1) {
            positions.push(positions[0]);
        }
        if (positions[0] == 'top' || positions[0] == 'bottom' || positions[1] == 'left' || positions[1] == 'right') {
            positions = [positions[1], positions[0]];
        }
        if (this.positionX != undefined)
            positions[0] = this.positionX.toLowerCase();
        if (this.positionY != undefined)
            positions[1] = this.positionY.toLowerCase();
        self.positionX = positions[0];
        self.positionY = positions[1];
        if (this.positionX != 'left' && this.positionX != 'right') {
            if (isNaN(parseInt(this.positionX))) {
                this.positionX = 'center';
            }
            else {
                this.positionX = parseInt(this.positionX);
            }
        }
        if (this.positionY != 'top' && this.positionY != 'bottom') {
            if (isNaN(parseInt(this.positionY))) {
                this.positionY = 'center';
            }
            else {
                this.positionY = parseInt(this.positionY);
            }
        }
        this.position =
            this.positionX + (isNaN(this.positionX) ? '' : 'px') + ' ' +
                this.positionY + (isNaN(this.positionY) ? '' : 'px');
        if (navigator.userAgent.match(/(iPod|iPhone|iPad)/)) {
            if (this.imageSrc && this.iosFix && !this.$element.is('img')) {
                this.$element.css({
                    backgroundImage: 'url(' + this.imageSrc + ')',
                    backgroundSize: 'cover',
                    backgroundPosition: this.position
                });
            }
            return this;
        }
        if (navigator.userAgent.match(/(Android)/)) {
            if (this.imageSrc && this.androidFix && !this.$element.is('img')) {
                this.$element.css({
                    backgroundImage: 'url(' + this.imageSrc + ')',
                    backgroundSize: 'cover',
                    backgroundPosition: this.position
                });
            }
            return this;
        }
        this.$mirror = $('<div />').prependTo('body');
        var slider = this.$element.find('>.parallax-slider');
        var sliderExisted = false;
        if (slider.length == 0)
            this.$slider = $('<img />').prependTo(this.$mirror);
        else {
            this.$slider = slider.prependTo(this.$mirror);
            sliderExisted = true;
        }
        this.$mirror.addClass('parallax-mirror').css({
            visibility: 'hidden',
            zIndex: this.zIndex,
            position: 'fixed',
            top: 0,
            left: 0,
            overflow: 'hidden'
        });
        this.$slider.addClass('parallax-slider').one('load', function () {
            if (!self.naturalHeight || !self.naturalWidth) {
                self.naturalHeight = this.naturalHeight || this.height || 1;
                self.naturalWidth = this.naturalWidth || this.width || 1;
            }
            self.aspectRatio = self.naturalWidth / self.naturalHeight;
            Parallax.isSetup || Parallax.setup();
            Parallax.sliders.push(self);
            Parallax.isFresh = false;
            Parallax.requestRender();
        });
        if (!sliderExisted)
            this.$slider[0].src = this.imageSrc;
        if (this.naturalHeight && this.naturalWidth || this.$slider[0].complete || slider.length > 0) {
            this.$slider.trigger('load');
        }
    }
    ;
    // Parallax Instance Methods
    $.extend(Parallax.prototype, {
        speed: 0.2,
        bleed: 0,
        zIndex: -100,
        iosFix: true,
        androidFix: true,
        position: 'center',
        overScrollFix: false,
        refresh: function () {
            this.boxWidth = this.$element.outerWidth();
            this.boxHeight = this.$element.outerHeight() + this.bleed * 2;
            this.boxOffsetTop = this.$element.offset().top - this.bleed;
            this.boxOffsetLeft = this.$element.offset().left;
            this.boxOffsetBottom = this.boxOffsetTop + this.boxHeight;
            var winHeight = Parallax.winHeight;
            var docHeight = Parallax.docHeight;
            var maxOffset = Math.min(this.boxOffsetTop, docHeight - winHeight);
            var minOffset = Math.max(this.boxOffsetTop + this.boxHeight - winHeight, 0);
            var imageHeightMin = this.boxHeight + (maxOffset - minOffset) * (1 - this.speed) | 0;
            var imageOffsetMin = (this.boxOffsetTop - maxOffset) * (1 - this.speed) | 0;
            if (imageHeightMin * this.aspectRatio >= this.boxWidth) {
                this.imageWidth = imageHeightMin * this.aspectRatio | 0;
                this.imageHeight = imageHeightMin;
                this.offsetBaseTop = imageOffsetMin;
                var margin = this.imageWidth - this.boxWidth;
                if (this.positionX == 'left') {
                    this.offsetLeft = 0;
                }
                else if (this.positionX == 'right') {
                    this.offsetLeft = -margin;
                }
                else if (!isNaN(this.positionX)) {
                    this.offsetLeft = Math.max(this.positionX, -margin);
                }
                else {
                    this.offsetLeft = -margin / 2 | 0;
                }
            }
            else {
                this.imageWidth = this.boxWidth;
                this.imageHeight = this.boxWidth / this.aspectRatio | 0;
                this.offsetLeft = 0;
                var margin = this.imageHeight - imageHeightMin;
                if (this.positionY == 'top') {
                    this.offsetBaseTop = imageOffsetMin;
                }
                else if (this.positionY == 'bottom') {
                    this.offsetBaseTop = imageOffsetMin - margin;
                }
                else if (!isNaN(this.positionY)) {
                    this.offsetBaseTop = imageOffsetMin + Math.max(this.positionY, -margin);
                }
                else {
                    this.offsetBaseTop = imageOffsetMin - margin / 2 | 0;
                }
            }
        },
        render: function () {
            var scrollTop = Parallax.scrollTop;
            var scrollLeft = Parallax.scrollLeft;
            var overScroll = this.overScrollFix ? Parallax.overScroll : 0;
            var scrollBottom = scrollTop + Parallax.winHeight;
            if (this.boxOffsetBottom > scrollTop && this.boxOffsetTop <= scrollBottom) {
                this.visibility = 'visible';
                this.mirrorTop = this.boxOffsetTop - scrollTop;
                this.mirrorLeft = this.boxOffsetLeft - scrollLeft;
                this.offsetTop = this.offsetBaseTop - this.mirrorTop * (1 - this.speed);
            }
            else {
                this.visibility = 'hidden';
            }
            this.$mirror.css({
                transform: 'translate3d(0px, 0px, 0px)',
                visibility: this.visibility,
                top: this.mirrorTop - overScroll,
                left: this.mirrorLeft,
                height: this.boxHeight,
                width: this.boxWidth
            });
            this.$slider.css({
                transform: 'translate3d(0px, 0px, 0px)',
                position: 'absolute',
                top: this.offsetTop,
                left: this.offsetLeft,
                height: this.imageHeight,
                width: this.imageWidth,
                maxWidth: 'none'
            });
        }
    });
    // Parallax Static Methods
    $.extend(Parallax, {
        scrollTop: 0,
        scrollLeft: 0,
        winHeight: 0,
        winWidth: 0,
        docHeight: 1 << 30,
        docWidth: 1 << 30,
        sliders: [],
        isReady: false,
        isFresh: false,
        isBusy: false,
        setup: function () {
            if (this.isReady)
                return;
            var $doc = $(document), $win = $(window);
            var loadDimensions = function () {
                Parallax.winHeight = $win.height();
                Parallax.winWidth = $win.width();
                Parallax.docHeight = $doc.height();
                Parallax.docWidth = $doc.width();
            };
            var loadScrollPosition = function () {
                var winScrollTop = $win.scrollTop();
                var scrollTopMax = Parallax.docHeight - Parallax.winHeight;
                var scrollLeftMax = Parallax.docWidth - Parallax.winWidth;
                Parallax.scrollTop = Math.max(0, Math.min(scrollTopMax, winScrollTop));
                Parallax.scrollLeft = Math.max(0, Math.min(scrollLeftMax, $win.scrollLeft()));
                Parallax.overScroll = Math.max(winScrollTop - scrollTopMax, Math.min(winScrollTop, 0));
            };
            $win.on('resize.px.parallax load.px.parallax', function () {
                loadDimensions();
                Parallax.isFresh = false;
                Parallax.requestRender();
            })
                .on('scroll.px.parallax load.px.parallax', function () {
                loadScrollPosition();
                Parallax.requestRender();
            });
            loadDimensions();
            loadScrollPosition();
            this.isReady = true;
        },
        configure: function (options) {
            if (typeof options == 'object') {
                delete options.refresh;
                delete options.render;
                $.extend(this.prototype, options);
            }
        },
        refresh: function () {
            $.each(this.sliders, function () { this.refresh(); });
            this.isFresh = true;
        },
        render: function () {
            this.isFresh || this.refresh();
            $.each(this.sliders, function () { this.render(); });
        },
        requestRender: function () {
            var self = this;
            if (!this.isBusy) {
                this.isBusy = true;
                window.requestAnimationFrame(function () {
                    self.render();
                    self.isBusy = false;
                });
            }
        },
        destroy: function (el) {
            var i, parallaxElement = $(el).data('px.parallax');
            parallaxElement.$mirror.remove();
            for (i = 0; i < this.sliders.length; i += 1) {
                if (this.sliders[i] == parallaxElement) {
                    this.sliders.splice(i, 1);
                }
            }
            $(el).data('px.parallax', false);
            if (this.sliders.length === 0) {
                $(window).off('scroll.px.parallax resize.px.parallax load.px.parallax');
                this.isReady = false;
                Parallax.isSetup = false;
            }
        }
    });
    // Parallax Plugin Definition
    function Plugin(option) {
        return this.each(function () {
            var $this = $(this);
            var options = typeof option == 'object' && option;
            if (this == window || this == document || $this.is('body')) {
                Parallax.configure(options);
            }
            else if (!$this.data('px.parallax')) {
                options = $.extend({}, $this.data(), options);
                $this.data('px.parallax', new Parallax(this, options));
            }
            else if (typeof option == 'object') {
                $.extend($this.data('px.parallax'), options);
            }
            if (typeof option == 'string') {
                if (option == 'destroy') {
                    Parallax['destroy'](this);
                }
                else {
                    Parallax[option]();
                }
            }
        });
    }
    ;
    var old = $.fn.parallax;
    $.fn.parallax = Plugin;
    $.fn.parallax.Constructor = Parallax;
    // Parallax No Conflict
    $.fn.parallax.noConflict = function () {
        $.fn.parallax = old;
        return this;
    };
    // Parallax Data-API
    $(document).on('ready.px.parallax.data-api', function () {
        $('[data-parallax="scroll"]').parallax();
    });
}(jQuery, window, document));
//# sourceMappingURL=parallax.js.map 
//# sourceMappingURL=parallax.js.map 
//# sourceMappingURL=parallax.js.map 
//# sourceMappingURL=parallax.js.map 
//# sourceMappingURL=parallax.js.map 
//# sourceMappingURL=parallax.js.map 
//# sourceMappingURL=parallax.js.map;
/*!
 * Select2 4.0.3
 * https://select2.github.io
 *
 * Released under the MIT license
 * https://github.com/select2/select2/blob/master/LICENSE.md
 */
(function (factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD. Register as an anonymous module.
        define(['jquery'], factory);
    }
    else if (typeof exports === 'object') {
        // Node/CommonJS
        factory(require('jquery'));
    }
    else {
        // Browser globals
        factory(jQuery);
    }
}(function (jQuery) {
    // This is needed so we can catch the AMD loader configuration and use it
    // The inner file should be wrapped (by `banner.start.js`) in a function that
    // returns the AMD loader references.
    var S2 = (function () {
        // Restore the Select2 AMD loader so it can be used
        // Needed mostly in the language files, where the loader is not inserted
        if (jQuery && jQuery.fn && jQuery.fn.select2 && jQuery.fn.select2.amd) {
            var S2 = jQuery.fn.select2.amd;
        }
        var S2;
        (function () {
            if (!S2 || !S2.requirejs) {
                if (!S2) {
                    S2 = {};
                }
                else {
                    require = S2;
                }
                /**
                 * @license almond 0.3.1 Copyright (c) 2011-2014, The Dojo Foundation All Rights Reserved.
                 * Available via the MIT or new BSD license.
                 * see: http://github.com/jrburke/almond for details
                 */
                //Going sloppy to avoid 'use strict' string cost, but strict practices should
                //be followed.
                /*jslint sloppy: true */
                /*global setTimeout: false */
                var requirejs, require, define;
                (function (undef) {
                    var main, req, makeMap, handlers, defined = {}, waiting = {}, config = {}, defining = {}, hasOwn = Object.prototype.hasOwnProperty, aps = [].slice, jsSuffixRegExp = /\.js$/;
                    function hasProp(obj, prop) {
                        return hasOwn.call(obj, prop);
                    }
                    /**
                     * Given a relative module name, like ./something, normalize it to
                     * a real name that can be mapped to a path.
                     * @param {String} name the relative name
                     * @param {String} baseName a real name that the name arg is relative
                     * to.
                     * @returns {String} normalized name
                     */
                    function normalize(name, baseName) {
                        var nameParts, nameSegment, mapValue, foundMap, lastIndex, foundI, foundStarMap, starI, i, j, part, baseParts = baseName && baseName.split("/"), map = config.map, starMap = (map && map['*']) || {};
                        //Adjust any relative paths.
                        if (name && name.charAt(0) === ".") {
                            //If have a base name, try to normalize against it,
                            //otherwise, assume it is a top-level require that will
                            //be relative to baseUrl in the end.
                            if (baseName) {
                                name = name.split('/');
                                lastIndex = name.length - 1;
                                // Node .js allowance:
                                if (config.nodeIdCompat && jsSuffixRegExp.test(name[lastIndex])) {
                                    name[lastIndex] = name[lastIndex].replace(jsSuffixRegExp, '');
                                }
                                //Lop off the last part of baseParts, so that . matches the
                                //"directory" and not name of the baseName's module. For instance,
                                //baseName of "one/two/three", maps to "one/two/three.js", but we
                                //want the directory, "one/two" for this normalization.
                                name = baseParts.slice(0, baseParts.length - 1).concat(name);
                                //start trimDots
                                for (i = 0; i < name.length; i += 1) {
                                    part = name[i];
                                    if (part === ".") {
                                        name.splice(i, 1);
                                        i -= 1;
                                    }
                                    else if (part === "..") {
                                        if (i === 1 && (name[2] === '..' || name[0] === '..')) {
                                            //End of the line. Keep at least one non-dot
                                            //path segment at the front so it can be mapped
                                            //correctly to disk. Otherwise, there is likely
                                            //no path mapping for a path starting with '..'.
                                            //This can still fail, but catches the most reasonable
                                            //uses of ..
                                            break;
                                        }
                                        else if (i > 0) {
                                            name.splice(i - 1, 2);
                                            i -= 2;
                                        }
                                    }
                                }
                                //end trimDots
                                name = name.join("/");
                            }
                            else if (name.indexOf('./') === 0) {
                                // No baseName, so this is ID is resolved relative
                                // to baseUrl, pull off the leading dot.
                                name = name.substring(2);
                            }
                        }
                        //Apply map config if available.
                        if ((baseParts || starMap) && map) {
                            nameParts = name.split('/');
                            for (i = nameParts.length; i > 0; i -= 1) {
                                nameSegment = nameParts.slice(0, i).join("/");
                                if (baseParts) {
                                    //Find the longest baseName segment match in the config.
                                    //So, do joins on the biggest to smallest lengths of baseParts.
                                    for (j = baseParts.length; j > 0; j -= 1) {
                                        mapValue = map[baseParts.slice(0, j).join('/')];
                                        //baseName segment has  config, find if it has one for
                                        //this name.
                                        if (mapValue) {
                                            mapValue = mapValue[nameSegment];
                                            if (mapValue) {
                                                //Match, update name to the new value.
                                                foundMap = mapValue;
                                                foundI = i;
                                                break;
                                            }
                                        }
                                    }
                                }
                                if (foundMap) {
                                    break;
                                }
                                //Check for a star map match, but just hold on to it,
                                //if there is a shorter segment match later in a matching
                                //config, then favor over this star map.
                                if (!foundStarMap && starMap && starMap[nameSegment]) {
                                    foundStarMap = starMap[nameSegment];
                                    starI = i;
                                }
                            }
                            if (!foundMap && foundStarMap) {
                                foundMap = foundStarMap;
                                foundI = starI;
                            }
                            if (foundMap) {
                                nameParts.splice(0, foundI, foundMap);
                                name = nameParts.join('/');
                            }
                        }
                        return name;
                    }
                    function makeRequire(relName, forceSync) {
                        return function () {
                            //A version of a require function that passes a moduleName
                            //value for items that may need to
                            //look up paths relative to the moduleName
                            var args = aps.call(arguments, 0);
                            //If first arg is not require('string'), and there is only
                            //one arg, it is the array form without a callback. Insert
                            //a null so that the following concat is correct.
                            if (typeof args[0] !== 'string' && args.length === 1) {
                                args.push(null);
                            }
                            return req.apply(undef, args.concat([relName, forceSync]));
                        };
                    }
                    function makeNormalize(relName) {
                        return function (name) {
                            return normalize(name, relName);
                        };
                    }
                    function makeLoad(depName) {
                        return function (value) {
                            defined[depName] = value;
                        };
                    }
                    function callDep(name) {
                        if (hasProp(waiting, name)) {
                            var args = waiting[name];
                            delete waiting[name];
                            defining[name] = true;
                            main.apply(undef, args);
                        }
                        if (!hasProp(defined, name) && !hasProp(defining, name)) {
                            throw new Error('No ' + name);
                        }
                        return defined[name];
                    }
                    //Turns a plugin!resource to [plugin, resource]
                    //with the plugin being undefined if the name
                    //did not have a plugin prefix.
                    function splitPrefix(name) {
                        var prefix, index = name ? name.indexOf('!') : -1;
                        if (index > -1) {
                            prefix = name.substring(0, index);
                            name = name.substring(index + 1, name.length);
                        }
                        return [prefix, name];
                    }
                    /**
                     * Makes a name map, normalizing the name, and using a plugin
                     * for normalization if necessary. Grabs a ref to plugin
                     * too, as an optimization.
                     */
                    makeMap = function (name, relName) {
                        var plugin, parts = splitPrefix(name), prefix = parts[0];
                        name = parts[1];
                        if (prefix) {
                            prefix = normalize(prefix, relName);
                            plugin = callDep(prefix);
                        }
                        //Normalize according
                        if (prefix) {
                            if (plugin && plugin.normalize) {
                                name = plugin.normalize(name, makeNormalize(relName));
                            }
                            else {
                                name = normalize(name, relName);
                            }
                        }
                        else {
                            name = normalize(name, relName);
                            parts = splitPrefix(name);
                            prefix = parts[0];
                            name = parts[1];
                            if (prefix) {
                                plugin = callDep(prefix);
                            }
                        }
                        //Using ridiculous property names for space reasons
                        return {
                            f: prefix ? prefix + '!' + name : name,
                            n: name,
                            pr: prefix,
                            p: plugin
                        };
                    };
                    function makeConfig(name) {
                        return function () {
                            return (config && config.config && config.config[name]) || {};
                        };
                    }
                    handlers = {
                        require: function (name) {
                            return makeRequire(name);
                        },
                        exports: function (name) {
                            var e = defined[name];
                            if (typeof e !== 'undefined') {
                                return e;
                            }
                            else {
                                return (defined[name] = {});
                            }
                        },
                        module: function (name) {
                            return {
                                id: name,
                                uri: '',
                                exports: defined[name],
                                config: makeConfig(name)
                            };
                        }
                    };
                    main = function (name, deps, callback, relName) {
                        var cjsModule, depName, ret, map, i, args = [], callbackType = typeof callback, usingExports;
                        //Use name if no relName
                        relName = relName || name;
                        //Call the callback to define the module, if necessary.
                        if (callbackType === 'undefined' || callbackType === 'function') {
                            //Pull out the defined dependencies and pass the ordered
                            //values to the callback.
                            //Default to [require, exports, module] if no deps
                            deps = !deps.length && callback.length ? ['require', 'exports', 'module'] : deps;
                            for (i = 0; i < deps.length; i += 1) {
                                map = makeMap(deps[i], relName);
                                depName = map.f;
                                //Fast path CommonJS standard dependencies.
                                if (depName === "require") {
                                    args[i] = handlers.require(name);
                                }
                                else if (depName === "exports") {
                                    //CommonJS module spec 1.1
                                    args[i] = handlers.exports(name);
                                    usingExports = true;
                                }
                                else if (depName === "module") {
                                    //CommonJS module spec 1.1
                                    cjsModule = args[i] = handlers.module(name);
                                }
                                else if (hasProp(defined, depName) ||
                                    hasProp(waiting, depName) ||
                                    hasProp(defining, depName)) {
                                    args[i] = callDep(depName);
                                }
                                else if (map.p) {
                                    map.p.load(map.n, makeRequire(relName, true), makeLoad(depName), {});
                                    args[i] = defined[depName];
                                }
                                else {
                                    throw new Error(name + ' missing ' + depName);
                                }
                            }
                            ret = callback ? callback.apply(defined[name], args) : undefined;
                            if (name) {
                                //If setting exports via "module" is in play,
                                //favor that over return value and exports. After that,
                                //favor a non-undefined return value over exports use.
                                if (cjsModule && cjsModule.exports !== undef &&
                                    cjsModule.exports !== defined[name]) {
                                    defined[name] = cjsModule.exports;
                                }
                                else if (ret !== undef || !usingExports) {
                                    //Use the return value from the function.
                                    defined[name] = ret;
                                }
                            }
                        }
                        else if (name) {
                            //May just be an object definition for the module. Only
                            //worry about defining if have a module name.
                            defined[name] = callback;
                        }
                    };
                    requirejs = require = req = function (deps, callback, relName, forceSync, alt) {
                        if (typeof deps === "string") {
                            if (handlers[deps]) {
                                //callback in this case is really relName
                                return handlers[deps](callback);
                            }
                            //Just return the module wanted. In this scenario, the
                            //deps arg is the module name, and second arg (if passed)
                            //is just the relName.
                            //Normalize module name, if it contains . or ..
                            return callDep(makeMap(deps, callback).f);
                        }
                        else if (!deps.splice) {
                            //deps is a config object, not an array.
                            config = deps;
                            if (config.deps) {
                                req(config.deps, config.callback);
                            }
                            if (!callback) {
                                return;
                            }
                            if (callback.splice) {
                                //callback is an array, which means it is a dependency list.
                                //Adjust args if there are dependencies
                                deps = callback;
                                callback = relName;
                                relName = null;
                            }
                            else {
                                deps = undef;
                            }
                        }
                        //Support require(['a'])
                        callback = callback || function () { };
                        //If relName is a function, it is an errback handler,
                        //so remove it.
                        if (typeof relName === 'function') {
                            relName = forceSync;
                            forceSync = alt;
                        }
                        //Simulate async callback;
                        if (forceSync) {
                            main(undef, deps, callback, relName);
                        }
                        else {
                            //Using a non-zero value because of concern for what old browsers
                            //do, and latest browsers "upgrade" to 4 if lower value is used:
                            //http://www.whatwg.org/specs/web-apps/current-work/multipage/timers.html#dom-windowtimers-settimeout:
                            //If want a value immediately, use require('id') instead -- something
                            //that works in almond on the global level, but not guaranteed and
                            //unlikely to work in other AMD implementations.
                            setTimeout(function () {
                                main(undef, deps, callback, relName);
                            }, 4);
                        }
                        return req;
                    };
                    /**
                     * Just drops the config on the floor, but returns req in case
                     * the config return value is used.
                     */
                    req.config = function (cfg) {
                        return req(cfg);
                    };
                    /**
                     * Expose module registry for debugging and tooling
                     */
                    requirejs._defined = defined;
                    define = function (name, deps, callback) {
                        if (typeof name !== 'string') {
                            throw new Error('See almond README: incorrect module build, no module name');
                        }
                        //This module may not have dependencies
                        if (!deps.splice) {
                            //deps is not an array, so probably means
                            //an object literal or factory function for
                            //the value. Adjust args.
                            callback = deps;
                            deps = [];
                        }
                        if (!hasProp(defined, name) && !hasProp(waiting, name)) {
                            waiting[name] = [name, deps, callback];
                        }
                    };
                    define.amd = {
                        jQuery: true
                    };
                }());
                S2.requirejs = requirejs;
                S2.require = require;
                S2.define = define;
            }
        }());
        S2.define("almond", function () { });
        /* global jQuery:false, $:false */
        S2.define('jquery', [], function () {
            var _$ = jQuery || $;
            if (_$ == null && console && console.error) {
                console.error('Select2: An instance of jQuery or a jQuery-compatible library was not ' +
                    'found. Make sure that you are including jQuery before Select2 on your ' +
                    'web page.');
            }
            return _$;
        });
        S2.define('select2/utils', [
            'jquery'
        ], function ($) {
            var Utils = {};
            Utils.Extend = function (ChildClass, SuperClass) {
                var __hasProp = {}.hasOwnProperty;
                function BaseConstructor() {
                    this.constructor = ChildClass;
                }
                for (var key in SuperClass) {
                    if (__hasProp.call(SuperClass, key)) {
                        ChildClass[key] = SuperClass[key];
                    }
                }
                BaseConstructor.prototype = SuperClass.prototype;
                ChildClass.prototype = new BaseConstructor();
                ChildClass.__super__ = SuperClass.prototype;
                return ChildClass;
            };
            function getMethods(theClass) {
                var proto = theClass.prototype;
                var methods = [];
                for (var methodName in proto) {
                    var m = proto[methodName];
                    if (typeof m !== 'function') {
                        continue;
                    }
                    if (methodName === 'constructor') {
                        continue;
                    }
                    methods.push(methodName);
                }
                return methods;
            }
            Utils.Decorate = function (SuperClass, DecoratorClass) {
                var decoratedMethods = getMethods(DecoratorClass);
                var superMethods = getMethods(SuperClass);
                function DecoratedClass() {
                    var unshift = Array.prototype.unshift;
                    var argCount = DecoratorClass.prototype.constructor.length;
                    var calledConstructor = SuperClass.prototype.constructor;
                    if (argCount > 0) {
                        unshift.call(arguments, SuperClass.prototype.constructor);
                        calledConstructor = DecoratorClass.prototype.constructor;
                    }
                    calledConstructor.apply(this, arguments);
                }
                DecoratorClass.displayName = SuperClass.displayName;
                function ctr() {
                    this.constructor = DecoratedClass;
                }
                DecoratedClass.prototype = new ctr();
                for (var m = 0; m < superMethods.length; m++) {
                    var superMethod = superMethods[m];
                    DecoratedClass.prototype[superMethod] =
                        SuperClass.prototype[superMethod];
                }
                var calledMethod = function (methodName) {
                    // Stub out the original method if it's not decorating an actual method
                    var originalMethod = function () { };
                    if (methodName in DecoratedClass.prototype) {
                        originalMethod = DecoratedClass.prototype[methodName];
                    }
                    var decoratedMethod = DecoratorClass.prototype[methodName];
                    return function () {
                        var unshift = Array.prototype.unshift;
                        unshift.call(arguments, originalMethod);
                        return decoratedMethod.apply(this, arguments);
                    };
                };
                for (var d = 0; d < decoratedMethods.length; d++) {
                    var decoratedMethod = decoratedMethods[d];
                    DecoratedClass.prototype[decoratedMethod] = calledMethod(decoratedMethod);
                }
                return DecoratedClass;
            };
            var Observable = function () {
                this.listeners = {};
            };
            Observable.prototype.on = function (event, callback) {
                this.listeners = this.listeners || {};
                if (event in this.listeners) {
                    this.listeners[event].push(callback);
                }
                else {
                    this.listeners[event] = [callback];
                }
            };
            Observable.prototype.trigger = function (event) {
                var slice = Array.prototype.slice;
                var params = slice.call(arguments, 1);
                this.listeners = this.listeners || {};
                // Params should always come in as an array
                if (params == null) {
                    params = [];
                }
                // If there are no arguments to the event, use a temporary object
                if (params.length === 0) {
                    params.push({});
                }
                // Set the `_type` of the first object to the event
                params[0]._type = event;
                if (event in this.listeners) {
                    this.invoke(this.listeners[event], slice.call(arguments, 1));
                }
                if ('*' in this.listeners) {
                    this.invoke(this.listeners['*'], arguments);
                }
            };
            Observable.prototype.invoke = function (listeners, params) {
                for (var i = 0, len = listeners.length; i < len; i++) {
                    listeners[i].apply(this, params);
                }
            };
            Utils.Observable = Observable;
            Utils.generateChars = function (length) {
                var chars = '';
                for (var i = 0; i < length; i++) {
                    var randomChar = Math.floor(Math.random() * 36);
                    chars += randomChar.toString(36);
                }
                return chars;
            };
            Utils.bind = function (func, context) {
                return function () {
                    func.apply(context, arguments);
                };
            };
            Utils._convertData = function (data) {
                for (var originalKey in data) {
                    var keys = originalKey.split('-');
                    var dataLevel = data;
                    if (keys.length === 1) {
                        continue;
                    }
                    for (var k = 0; k < keys.length; k++) {
                        var key = keys[k];
                        // Lowercase the first letter
                        // By default, dash-separated becomes camelCase
                        key = key.substring(0, 1).toLowerCase() + key.substring(1);
                        if (!(key in dataLevel)) {
                            dataLevel[key] = {};
                        }
                        if (k == keys.length - 1) {
                            dataLevel[key] = data[originalKey];
                        }
                        dataLevel = dataLevel[key];
                    }
                    delete data[originalKey];
                }
                return data;
            };
            Utils.hasScroll = function (index, el) {
                // Adapted from the function created by @ShadowScripter
                // and adapted by @BillBarry on the Stack Exchange Code Review website.
                // The original code can be found at
                // http://codereview.stackexchange.com/q/13338
                // and was designed to be used with the Sizzle selector engine.
                var $el = $(el);
                var overflowX = el.style.overflowX;
                var overflowY = el.style.overflowY;
                //Check both x and y declarations
                if (overflowX === overflowY &&
                    (overflowY === 'hidden' || overflowY === 'visible')) {
                    return false;
                }
                if (overflowX === 'scroll' || overflowY === 'scroll') {
                    return true;
                }
                return ($el.innerHeight() < el.scrollHeight ||
                    $el.innerWidth() < el.scrollWidth);
            };
            Utils.escapeMarkup = function (markup) {
                var replaceMap = {
                    '\\': '&#92;',
                    '&': '&amp;',
                    '<': '&lt;',
                    '>': '&gt;',
                    '"': '&quot;',
                    '\'': '&#39;',
                    '/': '&#47;'
                };
                // Do not try to escape the markup if it's not a string
                if (typeof markup !== 'string') {
                    return markup;
                }
                return String(markup).replace(/[&<>"'\/\\]/g, function (match) {
                    return replaceMap[match];
                });
            };
            // Append an array of jQuery nodes to a given element.
            Utils.appendMany = function ($element, $nodes) {
                // jQuery 1.7.x does not support $.fn.append() with an array
                // Fall back to a jQuery object collection using $.fn.add()
                if ($.fn.jquery.substr(0, 3) === '1.7') {
                    var $jqNodes = $();
                    $.map($nodes, function (node) {
                        $jqNodes = $jqNodes.add(node);
                    });
                    $nodes = $jqNodes;
                }
                $element.append($nodes);
            };
            return Utils;
        });
        S2.define('select2/results', [
            'jquery',
            './utils'
        ], function ($, Utils) {
            function Results($element, options, dataAdapter) {
                this.$element = $element;
                this.data = dataAdapter;
                this.options = options;
                Results.__super__.constructor.call(this);
            }
            Utils.Extend(Results, Utils.Observable);
            Results.prototype.render = function () {
                var $results = $('<ul class="select2-results__options" role="tree"></ul>');
                if (this.options.get('multiple')) {
                    $results.attr('aria-multiselectable', 'true');
                }
                this.$results = $results;
                return $results;
            };
            Results.prototype.clear = function () {
                this.$results.empty();
            };
            Results.prototype.displayMessage = function (params) {
                var escapeMarkup = this.options.get('escapeMarkup');
                this.clear();
                this.hideLoading();
                var $message = $('<li role="treeitem" aria-live="assertive"' +
                    ' class="select2-results__option"></li>');
                var message = this.options.get('translations').get(params.message);
                $message.append(escapeMarkup(message(params.args)));
                $message[0].className += ' select2-results__message';
                this.$results.append($message);
            };
            Results.prototype.hideMessages = function () {
                this.$results.find('.select2-results__message').remove();
            };
            Results.prototype.append = function (data) {
                this.hideLoading();
                var $options = [];
                if (data.results == null || data.results.length === 0) {
                    if (this.$results.children().length === 0) {
                        this.trigger('results:message', {
                            message: 'noResults'
                        });
                    }
                    return;
                }
                data.results = this.sort(data.results);
                for (var d = 0; d < data.results.length; d++) {
                    var item = data.results[d];
                    var $option = this.option(item);
                    $options.push($option);
                }
                this.$results.append($options);
            };
            Results.prototype.position = function ($results, $dropdown) {
                var $resultsContainer = $dropdown.find('.select2-results');
                $resultsContainer.append($results);
            };
            Results.prototype.sort = function (data) {
                var sorter = this.options.get('sorter');
                return sorter(data);
            };
            Results.prototype.highlightFirstItem = function () {
                var $options = this.$results
                    .find('.select2-results__option[aria-selected]');
                var $selected = $options.filter('[aria-selected=true]');
                // Check if there are any selected options
                if ($selected.length > 0) {
                    // If there are selected options, highlight the first
                    $selected.first().trigger('mouseenter');
                }
                else {
                    // If there are no selected options, highlight the first option
                    // in the dropdown
                    $options.first().trigger('mouseenter');
                }
                this.ensureHighlightVisible();
            };
            Results.prototype.setClasses = function () {
                var self = this;
                this.data.current(function (selected) {
                    var selectedIds = $.map(selected, function (s) {
                        return s.id.toString();
                    });
                    var $options = self.$results
                        .find('.select2-results__option[aria-selected]');
                    $options.each(function () {
                        var $option = $(this);
                        var item = $.data(this, 'data');
                        // id needs to be converted to a string when comparing
                        var id = '' + item.id;
                        if ((item.element != null && item.element.selected) ||
                            (item.element == null && $.inArray(id, selectedIds) > -1)) {
                            $option.attr('aria-selected', 'true');
                        }
                        else {
                            $option.attr('aria-selected', 'false');
                        }
                    });
                });
            };
            Results.prototype.showLoading = function (params) {
                this.hideLoading();
                var loadingMore = this.options.get('translations').get('searching');
                var loading = {
                    disabled: true,
                    loading: true,
                    text: loadingMore(params)
                };
                var $loading = this.option(loading);
                $loading.className += ' loading-results';
                this.$results.prepend($loading);
            };
            Results.prototype.hideLoading = function () {
                this.$results.find('.loading-results').remove();
            };
            Results.prototype.option = function (data) {
                var option = document.createElement('li');
                option.className = 'select2-results__option';
                var attrs = {
                    'role': 'treeitem',
                    'aria-selected': 'false'
                };
                if (data.disabled) {
                    delete attrs['aria-selected'];
                    attrs['aria-disabled'] = 'true';
                }
                if (data.id == null) {
                    delete attrs['aria-selected'];
                }
                if (data._resultId != null) {
                    option.id = data._resultId;
                }
                if (data.title) {
                    option.title = data.title;
                }
                if (data.children) {
                    attrs.role = 'group';
                    attrs['aria-label'] = data.text;
                    delete attrs['aria-selected'];
                }
                for (var attr in attrs) {
                    var val = attrs[attr];
                    option.setAttribute(attr, val);
                }
                if (data.children) {
                    var $option = $(option);
                    var label = document.createElement('strong');
                    label.className = 'select2-results__group';
                    var $label = $(label);
                    this.template(data, label);
                    var $children = [];
                    for (var c = 0; c < data.children.length; c++) {
                        var child = data.children[c];
                        var $child = this.option(child);
                        $children.push($child);
                    }
                    var $childrenContainer = $('<ul></ul>', {
                        'class': 'select2-results__options select2-results__options--nested'
                    });
                    $childrenContainer.append($children);
                    $option.append(label);
                    $option.append($childrenContainer);
                }
                else {
                    this.template(data, option);
                }
                $.data(option, 'data', data);
                return option;
            };
            Results.prototype.bind = function (container, $container) {
                var self = this;
                var id = container.id + '-results';
                this.$results.attr('id', id);
                container.on('results:all', function (params) {
                    self.clear();
                    self.append(params.data);
                    if (container.isOpen()) {
                        self.setClasses();
                        self.highlightFirstItem();
                    }
                });
                container.on('results:append', function (params) {
                    self.append(params.data);
                    if (container.isOpen()) {
                        self.setClasses();
                    }
                });
                container.on('query', function (params) {
                    self.hideMessages();
                    self.showLoading(params);
                });
                container.on('select', function () {
                    if (!container.isOpen()) {
                        return;
                    }
                    self.setClasses();
                    self.highlightFirstItem();
                });
                container.on('unselect', function () {
                    if (!container.isOpen()) {
                        return;
                    }
                    self.setClasses();
                    self.highlightFirstItem();
                });
                container.on('open', function () {
                    // When the dropdown is open, aria-expended="true"
                    self.$results.attr('aria-expanded', 'true');
                    self.$results.attr('aria-hidden', 'false');
                    self.setClasses();
                    self.ensureHighlightVisible();
                });
                container.on('close', function () {
                    // When the dropdown is closed, aria-expended="false"
                    self.$results.attr('aria-expanded', 'false');
                    self.$results.attr('aria-hidden', 'true');
                    self.$results.removeAttr('aria-activedescendant');
                });
                container.on('results:toggle', function () {
                    var $highlighted = self.getHighlightedResults();
                    if ($highlighted.length === 0) {
                        return;
                    }
                    $highlighted.trigger('mouseup');
                });
                container.on('results:select', function () {
                    var $highlighted = self.getHighlightedResults();
                    if ($highlighted.length === 0) {
                        return;
                    }
                    var data = $highlighted.data('data');
                    if ($highlighted.attr('aria-selected') == 'true') {
                        self.trigger('close', {});
                    }
                    else {
                        self.trigger('select', {
                            data: data
                        });
                    }
                });
                container.on('results:previous', function () {
                    var $highlighted = self.getHighlightedResults();
                    var $options = self.$results.find('[aria-selected]');
                    var currentIndex = $options.index($highlighted);
                    // If we are already at te top, don't move further
                    if (currentIndex === 0) {
                        return;
                    }
                    var nextIndex = currentIndex - 1;
                    // If none are highlighted, highlight the first
                    if ($highlighted.length === 0) {
                        nextIndex = 0;
                    }
                    var $next = $options.eq(nextIndex);
                    $next.trigger('mouseenter');
                    var currentOffset = self.$results.offset().top;
                    var nextTop = $next.offset().top;
                    var nextOffset = self.$results.scrollTop() + (nextTop - currentOffset);
                    if (nextIndex === 0) {
                        self.$results.scrollTop(0);
                    }
                    else if (nextTop - currentOffset < 0) {
                        self.$results.scrollTop(nextOffset);
                    }
                });
                container.on('results:next', function () {
                    var $highlighted = self.getHighlightedResults();
                    var $options = self.$results.find('[aria-selected]');
                    var currentIndex = $options.index($highlighted);
                    var nextIndex = currentIndex + 1;
                    // If we are at the last option, stay there
                    if (nextIndex >= $options.length) {
                        return;
                    }
                    var $next = $options.eq(nextIndex);
                    $next.trigger('mouseenter');
                    var currentOffset = self.$results.offset().top +
                        self.$results.outerHeight(false);
                    var nextBottom = $next.offset().top + $next.outerHeight(false);
                    var nextOffset = self.$results.scrollTop() + nextBottom - currentOffset;
                    if (nextIndex === 0) {
                        self.$results.scrollTop(0);
                    }
                    else if (nextBottom > currentOffset) {
                        self.$results.scrollTop(nextOffset);
                    }
                });
                container.on('results:focus', function (params) {
                    params.element.addClass('select2-results__option--highlighted');
                });
                container.on('results:message', function (params) {
                    self.displayMessage(params);
                });
                if ($.fn.mousewheel) {
                    this.$results.on('mousewheel', function (e) {
                        var top = self.$results.scrollTop();
                        var bottom = self.$results.get(0).scrollHeight - top + e.deltaY;
                        var isAtTop = e.deltaY > 0 && top - e.deltaY <= 0;
                        var isAtBottom = e.deltaY < 0 && bottom <= self.$results.height();
                        if (isAtTop) {
                            self.$results.scrollTop(0);
                            e.preventDefault();
                            e.stopPropagation();
                        }
                        else if (isAtBottom) {
                            self.$results.scrollTop(self.$results.get(0).scrollHeight - self.$results.height());
                            e.preventDefault();
                            e.stopPropagation();
                        }
                    });
                }
                this.$results.on('mouseup', '.select2-results__option[aria-selected]', function (evt) {
                    var $this = $(this);
                    var data = $this.data('data');
                    if ($this.attr('aria-selected') === 'true') {
                        if (self.options.get('multiple')) {
                            self.trigger('unselect', {
                                originalEvent: evt,
                                data: data
                            });
                        }
                        else {
                            self.trigger('close', {});
                        }
                        return;
                    }
                    self.trigger('select', {
                        originalEvent: evt,
                        data: data
                    });
                });
                this.$results.on('mouseenter', '.select2-results__option[aria-selected]', function (evt) {
                    var data = $(this).data('data');
                    self.getHighlightedResults()
                        .removeClass('select2-results__option--highlighted');
                    self.trigger('results:focus', {
                        data: data,
                        element: $(this)
                    });
                });
            };
            Results.prototype.getHighlightedResults = function () {
                var $highlighted = this.$results
                    .find('.select2-results__option--highlighted');
                return $highlighted;
            };
            Results.prototype.destroy = function () {
                this.$results.remove();
            };
            Results.prototype.ensureHighlightVisible = function () {
                var $highlighted = this.getHighlightedResults();
                if ($highlighted.length === 0) {
                    return;
                }
                var $options = this.$results.find('[aria-selected]');
                var currentIndex = $options.index($highlighted);
                var currentOffset = this.$results.offset().top;
                var nextTop = $highlighted.offset().top;
                var nextOffset = this.$results.scrollTop() + (nextTop - currentOffset);
                var offsetDelta = nextTop - currentOffset;
                nextOffset -= $highlighted.outerHeight(false) * 2;
                if (currentIndex <= 2) {
                    this.$results.scrollTop(0);
                }
                else if (offsetDelta > this.$results.outerHeight() || offsetDelta < 0) {
                    this.$results.scrollTop(nextOffset);
                }
            };
            Results.prototype.template = function (result, container) {
                var template = this.options.get('templateResult');
                var escapeMarkup = this.options.get('escapeMarkup');
                var content = template(result, container);
                if (content == null) {
                    container.style.display = 'none';
                }
                else if (typeof content === 'string') {
                    container.innerHTML = escapeMarkup(content);
                }
                else {
                    $(container).append(content);
                }
            };
            return Results;
        });
        S2.define('select2/keys', [], function () {
            var KEYS = {
                BACKSPACE: 8,
                TAB: 9,
                ENTER: 13,
                SHIFT: 16,
                CTRL: 17,
                ALT: 18,
                ESC: 27,
                SPACE: 32,
                PAGE_UP: 33,
                PAGE_DOWN: 34,
                END: 35,
                HOME: 36,
                LEFT: 37,
                UP: 38,
                RIGHT: 39,
                DOWN: 40,
                DELETE: 46
            };
            return KEYS;
        });
        S2.define('select2/selection/base', [
            'jquery',
            '../utils',
            '../keys'
        ], function ($, Utils, KEYS) {
            function BaseSelection($element, options) {
                this.$element = $element;
                this.options = options;
                BaseSelection.__super__.constructor.call(this);
            }
            Utils.Extend(BaseSelection, Utils.Observable);
            BaseSelection.prototype.render = function () {
                var $selection = $('<span class="select2-selection" role="combobox" ' +
                    ' aria-haspopup="true" aria-expanded="false">' +
                    '</span>');
                this._tabindex = 0;
                if (this.$element.data('old-tabindex') != null) {
                    this._tabindex = this.$element.data('old-tabindex');
                }
                else if (this.$element.attr('tabindex') != null) {
                    this._tabindex = this.$element.attr('tabindex');
                }
                $selection.attr('title', this.$element.attr('title'));
                $selection.attr('tabindex', this._tabindex);
                this.$selection = $selection;
                return $selection;
            };
            BaseSelection.prototype.bind = function (container, $container) {
                var self = this;
                var id = container.id + '-container';
                var resultsId = container.id + '-results';
                this.container = container;
                this.$selection.on('focus', function (evt) {
                    self.trigger('focus', evt);
                });
                this.$selection.on('blur', function (evt) {
                    self._handleBlur(evt);
                });
                this.$selection.on('keydown', function (evt) {
                    self.trigger('keypress', evt);
                    if (evt.which === KEYS.SPACE) {
                        evt.preventDefault();
                    }
                });
                container.on('results:focus', function (params) {
                    self.$selection.attr('aria-activedescendant', params.data._resultId);
                });
                container.on('selection:update', function (params) {
                    self.update(params.data);
                });
                container.on('open', function () {
                    // When the dropdown is open, aria-expanded="true"
                    self.$selection.attr('aria-expanded', 'true');
                    self.$selection.attr('aria-owns', resultsId);
                    self._attachCloseHandler(container);
                });
                container.on('close', function () {
                    // When the dropdown is closed, aria-expanded="false"
                    self.$selection.attr('aria-expanded', 'false');
                    self.$selection.removeAttr('aria-activedescendant');
                    self.$selection.removeAttr('aria-owns');
                    self.$selection.focus();
                    self._detachCloseHandler(container);
                });
                container.on('enable', function () {
                    self.$selection.attr('tabindex', self._tabindex);
                });
                container.on('disable', function () {
                    self.$selection.attr('tabindex', '-1');
                });
            };
            BaseSelection.prototype._handleBlur = function (evt) {
                var self = this;
                // This needs to be delayed as the active element is the body when the tab
                // key is pressed, possibly along with others.
                window.setTimeout(function () {
                    // Don't trigger `blur` if the focus is still in the selection
                    if ((document.activeElement == self.$selection[0]) ||
                        ($.contains(self.$selection[0], document.activeElement))) {
                        return;
                    }
                    self.trigger('blur', evt);
                }, 1);
            };
            BaseSelection.prototype._attachCloseHandler = function (container) {
                var self = this;
                $(document.body).on('mousedown.select2.' + container.id, function (e) {
                    var $target = $(e.target);
                    var $select = $target.closest('.select2');
                    var $all = $('.select2.select2-container--open');
                    $all.each(function () {
                        var $this = $(this);
                        if (this == $select[0]) {
                            return;
                        }
                        var $element = $this.data('element');
                        $element.select2('close');
                    });
                });
            };
            BaseSelection.prototype._detachCloseHandler = function (container) {
                $(document.body).off('mousedown.select2.' + container.id);
            };
            BaseSelection.prototype.position = function ($selection, $container) {
                var $selectionContainer = $container.find('.selection');
                $selectionContainer.append($selection);
            };
            BaseSelection.prototype.destroy = function () {
                this._detachCloseHandler(this.container);
            };
            BaseSelection.prototype.update = function (data) {
                throw new Error('The `update` method must be defined in child classes.');
            };
            return BaseSelection;
        });
        S2.define('select2/selection/single', [
            'jquery',
            './base',
            '../utils',
            '../keys'
        ], function ($, BaseSelection, Utils, KEYS) {
            function SingleSelection() {
                SingleSelection.__super__.constructor.apply(this, arguments);
            }
            Utils.Extend(SingleSelection, BaseSelection);
            SingleSelection.prototype.render = function () {
                var $selection = SingleSelection.__super__.render.call(this);
                $selection.addClass('select2-selection--single');
                $selection.html('<span class="select2-selection__rendered"></span>' +
                    '<span class="select2-selection__arrow" role="presentation">' +
                    '<b role="presentation"></b>' +
                    '</span>');
                return $selection;
            };
            SingleSelection.prototype.bind = function (container, $container) {
                var self = this;
                SingleSelection.__super__.bind.apply(this, arguments);
                var id = container.id + '-container';
                this.$selection.find('.select2-selection__rendered').attr('id', id);
                this.$selection.attr('aria-labelledby', id);
                this.$selection.on('mousedown', function (evt) {
                    // Only respond to left clicks
                    if (evt.which !== 1) {
                        return;
                    }
                    self.trigger('toggle', {
                        originalEvent: evt
                    });
                });
                this.$selection.on('focus', function (evt) {
                    // User focuses on the container
                });
                this.$selection.on('blur', function (evt) {
                    // User exits the container
                });
                container.on('focus', function (evt) {
                    if (!container.isOpen()) {
                        self.$selection.focus();
                    }
                });
                container.on('selection:update', function (params) {
                    self.update(params.data);
                });
            };
            SingleSelection.prototype.clear = function () {
                this.$selection.find('.select2-selection__rendered').empty();
            };
            SingleSelection.prototype.display = function (data, container) {
                var template = this.options.get('templateSelection');
                var escapeMarkup = this.options.get('escapeMarkup');
                return escapeMarkup(template(data, container));
            };
            SingleSelection.prototype.selectionContainer = function () {
                return $('<span></span>');
            };
            SingleSelection.prototype.update = function (data) {
                if (data.length === 0) {
                    this.clear();
                    return;
                }
                var selection = data[0];
                var $rendered = this.$selection.find('.select2-selection__rendered');
                var formatted = this.display(selection, $rendered);
                $rendered.empty().append(formatted);
                $rendered.prop('title', selection.title || selection.text);
            };
            return SingleSelection;
        });
        S2.define('select2/selection/multiple', [
            'jquery',
            './base',
            '../utils'
        ], function ($, BaseSelection, Utils) {
            function MultipleSelection($element, options) {
                MultipleSelection.__super__.constructor.apply(this, arguments);
            }
            Utils.Extend(MultipleSelection, BaseSelection);
            MultipleSelection.prototype.render = function () {
                var $selection = MultipleSelection.__super__.render.call(this);
                $selection.addClass('select2-selection--multiple');
                $selection.html('<ul class="select2-selection__rendered"></ul>');
                return $selection;
            };
            MultipleSelection.prototype.bind = function (container, $container) {
                var self = this;
                MultipleSelection.__super__.bind.apply(this, arguments);
                this.$selection.on('click', function (evt) {
                    self.trigger('toggle', {
                        originalEvent: evt
                    });
                });
                this.$selection.on('click', '.select2-selection__choice__remove', function (evt) {
                    // Ignore the event if it is disabled
                    if (self.options.get('disabled')) {
                        return;
                    }
                    var $remove = $(this);
                    var $selection = $remove.parent();
                    var data = $selection.data('data');
                    self.trigger('unselect', {
                        originalEvent: evt,
                        data: data
                    });
                });
            };
            MultipleSelection.prototype.clear = function () {
                this.$selection.find('.select2-selection__rendered').empty();
            };
            MultipleSelection.prototype.display = function (data, container) {
                var template = this.options.get('templateSelection');
                var escapeMarkup = this.options.get('escapeMarkup');
                return escapeMarkup(template(data, container));
            };
            MultipleSelection.prototype.selectionContainer = function () {
                var $container = $('<li class="select2-selection__choice">' +
                    '<span class="select2-selection__choice__remove" role="presentation">' +
                    '&times;' +
                    '</span>' +
                    '</li>');
                return $container;
            };
            MultipleSelection.prototype.update = function (data) {
                this.clear();
                if (data.length === 0) {
                    return;
                }
                var $selections = [];
                for (var d = 0; d < data.length; d++) {
                    var selection = data[d];
                    var $selection = this.selectionContainer();
                    var formatted = this.display(selection, $selection);
                    $selection.append(formatted);
                    $selection.prop('title', selection.title || selection.text);
                    $selection.data('data', selection);
                    $selections.push($selection);
                }
                var $rendered = this.$selection.find('.select2-selection__rendered');
                Utils.appendMany($rendered, $selections);
            };
            return MultipleSelection;
        });
        S2.define('select2/selection/placeholder', [
            '../utils'
        ], function (Utils) {
            function Placeholder(decorated, $element, options) {
                this.placeholder = this.normalizePlaceholder(options.get('placeholder'));
                decorated.call(this, $element, options);
            }
            Placeholder.prototype.normalizePlaceholder = function (_, placeholder) {
                if (typeof placeholder === 'string') {
                    placeholder = {
                        id: '',
                        text: placeholder
                    };
                }
                return placeholder;
            };
            Placeholder.prototype.createPlaceholder = function (decorated, placeholder) {
                var $placeholder = this.selectionContainer();
                $placeholder.html(this.display(placeholder));
                $placeholder.addClass('select2-selection__placeholder')
                    .removeClass('select2-selection__choice');
                return $placeholder;
            };
            Placeholder.prototype.update = function (decorated, data) {
                var singlePlaceholder = (data.length == 1 && data[0].id != this.placeholder.id);
                var multipleSelections = data.length > 1;
                if (multipleSelections || singlePlaceholder) {
                    return decorated.call(this, data);
                }
                this.clear();
                var $placeholder = this.createPlaceholder(this.placeholder);
                this.$selection.find('.select2-selection__rendered').append($placeholder);
            };
            return Placeholder;
        });
        S2.define('select2/selection/allowClear', [
            'jquery',
            '../keys'
        ], function ($, KEYS) {
            function AllowClear() { }
            AllowClear.prototype.bind = function (decorated, container, $container) {
                var self = this;
                decorated.call(this, container, $container);
                if (this.placeholder == null) {
                    if (this.options.get('debug') && window.console && console.error) {
                        console.error('Select2: The `allowClear` option should be used in combination ' +
                            'with the `placeholder` option.');
                    }
                }
                this.$selection.on('mousedown', '.select2-selection__clear', function (evt) {
                    self._handleClear(evt);
                });
                container.on('keypress', function (evt) {
                    self._handleKeyboardClear(evt, container);
                });
            };
            AllowClear.prototype._handleClear = function (_, evt) {
                // Ignore the event if it is disabled
                if (this.options.get('disabled')) {
                    return;
                }
                var $clear = this.$selection.find('.select2-selection__clear');
                // Ignore the event if nothing has been selected
                if ($clear.length === 0) {
                    return;
                }
                evt.stopPropagation();
                var data = $clear.data('data');
                for (var d = 0; d < data.length; d++) {
                    var unselectData = {
                        data: data[d]
                    };
                    // Trigger the `unselect` event, so people can prevent it from being
                    // cleared.
                    this.trigger('unselect', unselectData);
                    // If the event was prevented, don't clear it out.
                    if (unselectData.prevented) {
                        return;
                    }
                }
                this.$element.val(this.placeholder.id).trigger('change');
                this.trigger('toggle', {});
            };
            AllowClear.prototype._handleKeyboardClear = function (_, evt, container) {
                if (container.isOpen()) {
                    return;
                }
                if (evt.which == KEYS.DELETE || evt.which == KEYS.BACKSPACE) {
                    this._handleClear(evt);
                }
            };
            AllowClear.prototype.update = function (decorated, data) {
                decorated.call(this, data);
                if (this.$selection.find('.select2-selection__placeholder').length > 0 ||
                    data.length === 0) {
                    return;
                }
                var $remove = $('<span class="select2-selection__clear">' +
                    '&times;' +
                    '</span>');
                $remove.data('data', data);
                this.$selection.find('.select2-selection__rendered').prepend($remove);
            };
            return AllowClear;
        });
        S2.define('select2/selection/search', [
            'jquery',
            '../utils',
            '../keys'
        ], function ($, Utils, KEYS) {
            function Search(decorated, $element, options) {
                decorated.call(this, $element, options);
            }
            Search.prototype.render = function (decorated) {
                var $search = $('<li class="select2-search select2-search--inline">' +
                    '<input class="select2-search__field" type="search" tabindex="-1"' +
                    ' autocomplete="off" autocorrect="off" autocapitalize="off"' +
                    ' spellcheck="false" role="textbox" aria-autocomplete="list" />' +
                    '</li>');
                this.$searchContainer = $search;
                this.$search = $search.find('input');
                var $rendered = decorated.call(this);
                this._transferTabIndex();
                return $rendered;
            };
            Search.prototype.bind = function (decorated, container, $container) {
                var self = this;
                decorated.call(this, container, $container);
                container.on('open', function () {
                    self.$search.trigger('focus');
                });
                container.on('close', function () {
                    self.$search.val('');
                    self.$search.removeAttr('aria-activedescendant');
                    self.$search.trigger('focus');
                });
                container.on('enable', function () {
                    self.$search.prop('disabled', false);
                    self._transferTabIndex();
                });
                container.on('disable', function () {
                    self.$search.prop('disabled', true);
                });
                container.on('focus', function (evt) {
                    self.$search.trigger('focus');
                });
                container.on('results:focus', function (params) {
                    self.$search.attr('aria-activedescendant', params.id);
                });
                this.$selection.on('focusin', '.select2-search--inline', function (evt) {
                    self.trigger('focus', evt);
                });
                this.$selection.on('focusout', '.select2-search--inline', function (evt) {
                    self._handleBlur(evt);
                });
                this.$selection.on('keydown', '.select2-search--inline', function (evt) {
                    evt.stopPropagation();
                    self.trigger('keypress', evt);
                    self._keyUpPrevented = evt.isDefaultPrevented();
                    var key = evt.which;
                    if (key === KEYS.BACKSPACE && self.$search.val() === '') {
                        var $previousChoice = self.$searchContainer
                            .prev('.select2-selection__choice');
                        if ($previousChoice.length > 0) {
                            var item = $previousChoice.data('data');
                            self.searchRemoveChoice(item);
                            evt.preventDefault();
                        }
                    }
                });
                // Try to detect the IE version should the `documentMode` property that
                // is stored on the document. This is only implemented in IE and is
                // slightly cleaner than doing a user agent check.
                // This property is not available in Edge, but Edge also doesn't have
                // this bug.
                var msie = document.documentMode;
                var disableInputEvents = msie && msie <= 11;
                // Workaround for browsers which do not support the `input` event
                // This will prevent double-triggering of events for browsers which support
                // both the `keyup` and `input` events.
                this.$selection.on('input.searchcheck', '.select2-search--inline', function (evt) {
                    // IE will trigger the `input` event when a placeholder is used on a
                    // search box. To get around this issue, we are forced to ignore all
                    // `input` events in IE and keep using `keyup`.
                    if (disableInputEvents) {
                        self.$selection.off('input.search input.searchcheck');
                        return;
                    }
                    // Unbind the duplicated `keyup` event
                    self.$selection.off('keyup.search');
                });
                this.$selection.on('keyup.search input.search', '.select2-search--inline', function (evt) {
                    // IE will trigger the `input` event when a placeholder is used on a
                    // search box. To get around this issue, we are forced to ignore all
                    // `input` events in IE and keep using `keyup`.
                    if (disableInputEvents && evt.type === 'input') {
                        self.$selection.off('input.search input.searchcheck');
                        return;
                    }
                    var key = evt.which;
                    // We can freely ignore events from modifier keys
                    if (key == KEYS.SHIFT || key == KEYS.CTRL || key == KEYS.ALT) {
                        return;
                    }
                    // Tabbing will be handled during the `keydown` phase
                    if (key == KEYS.TAB) {
                        return;
                    }
                    self.handleSearch(evt);
                });
            };
            /**
             * This method will transfer the tabindex attribute from the rendered
             * selection to the search box. This allows for the search box to be used as
             * the primary focus instead of the selection container.
             *
             * @private
             */
            Search.prototype._transferTabIndex = function (decorated) {
                this.$search.attr('tabindex', this.$selection.attr('tabindex'));
                this.$selection.attr('tabindex', '-1');
            };
            Search.prototype.createPlaceholder = function (decorated, placeholder) {
                this.$search.attr('placeholder', placeholder.text);
            };
            Search.prototype.update = function (decorated, data) {
                var searchHadFocus = this.$search[0] == document.activeElement;
                this.$search.attr('placeholder', '');
                decorated.call(this, data);
                this.$selection.find('.select2-selection__rendered')
                    .append(this.$searchContainer);
                this.resizeSearch();
                if (searchHadFocus) {
                    this.$search.focus();
                }
            };
            Search.prototype.handleSearch = function () {
                this.resizeSearch();
                if (!this._keyUpPrevented) {
                    var input = this.$search.val();
                    this.trigger('query', {
                        term: input
                    });
                }
                this._keyUpPrevented = false;
            };
            Search.prototype.searchRemoveChoice = function (decorated, item) {
                this.trigger('unselect', {
                    data: item
                });
                this.$search.val(item.text);
                this.handleSearch();
            };
            Search.prototype.resizeSearch = function () {
                this.$search.css('width', '25px');
                var width = '';
                if (this.$search.attr('placeholder') !== '') {
                    width = this.$selection.find('.select2-selection__rendered').innerWidth();
                }
                else {
                    var minimumWidth = this.$search.val().length + 1;
                    width = (minimumWidth * 0.75) + 'em';
                }
                this.$search.css('width', width);
            };
            return Search;
        });
        S2.define('select2/selection/eventRelay', [
            'jquery'
        ], function ($) {
            function EventRelay() { }
            EventRelay.prototype.bind = function (decorated, container, $container) {
                var self = this;
                var relayEvents = [
                    'open', 'opening',
                    'close', 'closing',
                    'select', 'selecting',
                    'unselect', 'unselecting'
                ];
                var preventableEvents = ['opening', 'closing', 'selecting', 'unselecting'];
                decorated.call(this, container, $container);
                container.on('*', function (name, params) {
                    // Ignore events that should not be relayed
                    if ($.inArray(name, relayEvents) === -1) {
                        return;
                    }
                    // The parameters should always be an object
                    params = params || {};
                    // Generate the jQuery event for the Select2 event
                    var evt = $.Event('select2:' + name, {
                        params: params
                    });
                    self.$element.trigger(evt);
                    // Only handle preventable events if it was one
                    if ($.inArray(name, preventableEvents) === -1) {
                        return;
                    }
                    params.prevented = evt.isDefaultPrevented();
                });
            };
            return EventRelay;
        });
        S2.define('select2/translation', [
            'jquery',
            'require'
        ], function ($, require) {
            function Translation(dict) {
                this.dict = dict || {};
            }
            Translation.prototype.all = function () {
                return this.dict;
            };
            Translation.prototype.get = function (key) {
                return this.dict[key];
            };
            Translation.prototype.extend = function (translation) {
                this.dict = $.extend({}, translation.all(), this.dict);
            };
            // Static functions
            Translation._cache = {};
            Translation.loadPath = function (path) {
                if (!(path in Translation._cache)) {
                    var translations = require(path);
                    Translation._cache[path] = translations;
                }
                return new Translation(Translation._cache[path]);
            };
            return Translation;
        });
        S2.define('select2/diacritics', [], function () {
            var diacritics = {
                '\u24B6': 'A',
                '\uFF21': 'A',
                '\u00C0': 'A',
                '\u00C1': 'A',
                '\u00C2': 'A',
                '\u1EA6': 'A',
                '\u1EA4': 'A',
                '\u1EAA': 'A',
                '\u1EA8': 'A',
                '\u00C3': 'A',
                '\u0100': 'A',
                '\u0102': 'A',
                '\u1EB0': 'A',
                '\u1EAE': 'A',
                '\u1EB4': 'A',
                '\u1EB2': 'A',
                '\u0226': 'A',
                '\u01E0': 'A',
                '\u00C4': 'A',
                '\u01DE': 'A',
                '\u1EA2': 'A',
                '\u00C5': 'A',
                '\u01FA': 'A',
                '\u01CD': 'A',
                '\u0200': 'A',
                '\u0202': 'A',
                '\u1EA0': 'A',
                '\u1EAC': 'A',
                '\u1EB6': 'A',
                '\u1E00': 'A',
                '\u0104': 'A',
                '\u023A': 'A',
                '\u2C6F': 'A',
                '\uA732': 'AA',
                '\u00C6': 'AE',
                '\u01FC': 'AE',
                '\u01E2': 'AE',
                '\uA734': 'AO',
                '\uA736': 'AU',
                '\uA738': 'AV',
                '\uA73A': 'AV',
                '\uA73C': 'AY',
                '\u24B7': 'B',
                '\uFF22': 'B',
                '\u1E02': 'B',
                '\u1E04': 'B',
                '\u1E06': 'B',
                '\u0243': 'B',
                '\u0182': 'B',
                '\u0181': 'B',
                '\u24B8': 'C',
                '\uFF23': 'C',
                '\u0106': 'C',
                '\u0108': 'C',
                '\u010A': 'C',
                '\u010C': 'C',
                '\u00C7': 'C',
                '\u1E08': 'C',
                '\u0187': 'C',
                '\u023B': 'C',
                '\uA73E': 'C',
                '\u24B9': 'D',
                '\uFF24': 'D',
                '\u1E0A': 'D',
                '\u010E': 'D',
                '\u1E0C': 'D',
                '\u1E10': 'D',
                '\u1E12': 'D',
                '\u1E0E': 'D',
                '\u0110': 'D',
                '\u018B': 'D',
                '\u018A': 'D',
                '\u0189': 'D',
                '\uA779': 'D',
                '\u01F1': 'DZ',
                '\u01C4': 'DZ',
                '\u01F2': 'Dz',
                '\u01C5': 'Dz',
                '\u24BA': 'E',
                '\uFF25': 'E',
                '\u00C8': 'E',
                '\u00C9': 'E',
                '\u00CA': 'E',
                '\u1EC0': 'E',
                '\u1EBE': 'E',
                '\u1EC4': 'E',
                '\u1EC2': 'E',
                '\u1EBC': 'E',
                '\u0112': 'E',
                '\u1E14': 'E',
                '\u1E16': 'E',
                '\u0114': 'E',
                '\u0116': 'E',
                '\u00CB': 'E',
                '\u1EBA': 'E',
                '\u011A': 'E',
                '\u0204': 'E',
                '\u0206': 'E',
                '\u1EB8': 'E',
                '\u1EC6': 'E',
                '\u0228': 'E',
                '\u1E1C': 'E',
                '\u0118': 'E',
                '\u1E18': 'E',
                '\u1E1A': 'E',
                '\u0190': 'E',
                '\u018E': 'E',
                '\u24BB': 'F',
                '\uFF26': 'F',
                '\u1E1E': 'F',
                '\u0191': 'F',
                '\uA77B': 'F',
                '\u24BC': 'G',
                '\uFF27': 'G',
                '\u01F4': 'G',
                '\u011C': 'G',
                '\u1E20': 'G',
                '\u011E': 'G',
                '\u0120': 'G',
                '\u01E6': 'G',
                '\u0122': 'G',
                '\u01E4': 'G',
                '\u0193': 'G',
                '\uA7A0': 'G',
                '\uA77D': 'G',
                '\uA77E': 'G',
                '\u24BD': 'H',
                '\uFF28': 'H',
                '\u0124': 'H',
                '\u1E22': 'H',
                '\u1E26': 'H',
                '\u021E': 'H',
                '\u1E24': 'H',
                '\u1E28': 'H',
                '\u1E2A': 'H',
                '\u0126': 'H',
                '\u2C67': 'H',
                '\u2C75': 'H',
                '\uA78D': 'H',
                '\u24BE': 'I',
                '\uFF29': 'I',
                '\u00CC': 'I',
                '\u00CD': 'I',
                '\u00CE': 'I',
                '\u0128': 'I',
                '\u012A': 'I',
                '\u012C': 'I',
                '\u0130': 'I',
                '\u00CF': 'I',
                '\u1E2E': 'I',
                '\u1EC8': 'I',
                '\u01CF': 'I',
                '\u0208': 'I',
                '\u020A': 'I',
                '\u1ECA': 'I',
                '\u012E': 'I',
                '\u1E2C': 'I',
                '\u0197': 'I',
                '\u24BF': 'J',
                '\uFF2A': 'J',
                '\u0134': 'J',
                '\u0248': 'J',
                '\u24C0': 'K',
                '\uFF2B': 'K',
                '\u1E30': 'K',
                '\u01E8': 'K',
                '\u1E32': 'K',
                '\u0136': 'K',
                '\u1E34': 'K',
                '\u0198': 'K',
                '\u2C69': 'K',
                '\uA740': 'K',
                '\uA742': 'K',
                '\uA744': 'K',
                '\uA7A2': 'K',
                '\u24C1': 'L',
                '\uFF2C': 'L',
                '\u013F': 'L',
                '\u0139': 'L',
                '\u013D': 'L',
                '\u1E36': 'L',
                '\u1E38': 'L',
                '\u013B': 'L',
                '\u1E3C': 'L',
                '\u1E3A': 'L',
                '\u0141': 'L',
                '\u023D': 'L',
                '\u2C62': 'L',
                '\u2C60': 'L',
                '\uA748': 'L',
                '\uA746': 'L',
                '\uA780': 'L',
                '\u01C7': 'LJ',
                '\u01C8': 'Lj',
                '\u24C2': 'M',
                '\uFF2D': 'M',
                '\u1E3E': 'M',
                '\u1E40': 'M',
                '\u1E42': 'M',
                '\u2C6E': 'M',
                '\u019C': 'M',
                '\u24C3': 'N',
                '\uFF2E': 'N',
                '\u01F8': 'N',
                '\u0143': 'N',
                '\u00D1': 'N',
                '\u1E44': 'N',
                '\u0147': 'N',
                '\u1E46': 'N',
                '\u0145': 'N',
                '\u1E4A': 'N',
                '\u1E48': 'N',
                '\u0220': 'N',
                '\u019D': 'N',
                '\uA790': 'N',
                '\uA7A4': 'N',
                '\u01CA': 'NJ',
                '\u01CB': 'Nj',
                '\u24C4': 'O',
                '\uFF2F': 'O',
                '\u00D2': 'O',
                '\u00D3': 'O',
                '\u00D4': 'O',
                '\u1ED2': 'O',
                '\u1ED0': 'O',
                '\u1ED6': 'O',
                '\u1ED4': 'O',
                '\u00D5': 'O',
                '\u1E4C': 'O',
                '\u022C': 'O',
                '\u1E4E': 'O',
                '\u014C': 'O',
                '\u1E50': 'O',
                '\u1E52': 'O',
                '\u014E': 'O',
                '\u022E': 'O',
                '\u0230': 'O',
                '\u00D6': 'O',
                '\u022A': 'O',
                '\u1ECE': 'O',
                '\u0150': 'O',
                '\u01D1': 'O',
                '\u020C': 'O',
                '\u020E': 'O',
                '\u01A0': 'O',
                '\u1EDC': 'O',
                '\u1EDA': 'O',
                '\u1EE0': 'O',
                '\u1EDE': 'O',
                '\u1EE2': 'O',
                '\u1ECC': 'O',
                '\u1ED8': 'O',
                '\u01EA': 'O',
                '\u01EC': 'O',
                '\u00D8': 'O',
                '\u01FE': 'O',
                '\u0186': 'O',
                '\u019F': 'O',
                '\uA74A': 'O',
                '\uA74C': 'O',
                '\u01A2': 'OI',
                '\uA74E': 'OO',
                '\u0222': 'OU',
                '\u24C5': 'P',
                '\uFF30': 'P',
                '\u1E54': 'P',
                '\u1E56': 'P',
                '\u01A4': 'P',
                '\u2C63': 'P',
                '\uA750': 'P',
                '\uA752': 'P',
                '\uA754': 'P',
                '\u24C6': 'Q',
                '\uFF31': 'Q',
                '\uA756': 'Q',
                '\uA758': 'Q',
                '\u024A': 'Q',
                '\u24C7': 'R',
                '\uFF32': 'R',
                '\u0154': 'R',
                '\u1E58': 'R',
                '\u0158': 'R',
                '\u0210': 'R',
                '\u0212': 'R',
                '\u1E5A': 'R',
                '\u1E5C': 'R',
                '\u0156': 'R',
                '\u1E5E': 'R',
                '\u024C': 'R',
                '\u2C64': 'R',
                '\uA75A': 'R',
                '\uA7A6': 'R',
                '\uA782': 'R',
                '\u24C8': 'S',
                '\uFF33': 'S',
                '\u1E9E': 'S',
                '\u015A': 'S',
                '\u1E64': 'S',
                '\u015C': 'S',
                '\u1E60': 'S',
                '\u0160': 'S',
                '\u1E66': 'S',
                '\u1E62': 'S',
                '\u1E68': 'S',
                '\u0218': 'S',
                '\u015E': 'S',
                '\u2C7E': 'S',
                '\uA7A8': 'S',
                '\uA784': 'S',
                '\u24C9': 'T',
                '\uFF34': 'T',
                '\u1E6A': 'T',
                '\u0164': 'T',
                '\u1E6C': 'T',
                '\u021A': 'T',
                '\u0162': 'T',
                '\u1E70': 'T',
                '\u1E6E': 'T',
                '\u0166': 'T',
                '\u01AC': 'T',
                '\u01AE': 'T',
                '\u023E': 'T',
                '\uA786': 'T',
                '\uA728': 'TZ',
                '\u24CA': 'U',
                '\uFF35': 'U',
                '\u00D9': 'U',
                '\u00DA': 'U',
                '\u00DB': 'U',
                '\u0168': 'U',
                '\u1E78': 'U',
                '\u016A': 'U',
                '\u1E7A': 'U',
                '\u016C': 'U',
                '\u00DC': 'U',
                '\u01DB': 'U',
                '\u01D7': 'U',
                '\u01D5': 'U',
                '\u01D9': 'U',
                '\u1EE6': 'U',
                '\u016E': 'U',
                '\u0170': 'U',
                '\u01D3': 'U',
                '\u0214': 'U',
                '\u0216': 'U',
                '\u01AF': 'U',
                '\u1EEA': 'U',
                '\u1EE8': 'U',
                '\u1EEE': 'U',
                '\u1EEC': 'U',
                '\u1EF0': 'U',
                '\u1EE4': 'U',
                '\u1E72': 'U',
                '\u0172': 'U',
                '\u1E76': 'U',
                '\u1E74': 'U',
                '\u0244': 'U',
                '\u24CB': 'V',
                '\uFF36': 'V',
                '\u1E7C': 'V',
                '\u1E7E': 'V',
                '\u01B2': 'V',
                '\uA75E': 'V',
                '\u0245': 'V',
                '\uA760': 'VY',
                '\u24CC': 'W',
                '\uFF37': 'W',
                '\u1E80': 'W',
                '\u1E82': 'W',
                '\u0174': 'W',
                '\u1E86': 'W',
                '\u1E84': 'W',
                '\u1E88': 'W',
                '\u2C72': 'W',
                '\u24CD': 'X',
                '\uFF38': 'X',
                '\u1E8A': 'X',
                '\u1E8C': 'X',
                '\u24CE': 'Y',
                '\uFF39': 'Y',
                '\u1EF2': 'Y',
                '\u00DD': 'Y',
                '\u0176': 'Y',
                '\u1EF8': 'Y',
                '\u0232': 'Y',
                '\u1E8E': 'Y',
                '\u0178': 'Y',
                '\u1EF6': 'Y',
                '\u1EF4': 'Y',
                '\u01B3': 'Y',
                '\u024E': 'Y',
                '\u1EFE': 'Y',
                '\u24CF': 'Z',
                '\uFF3A': 'Z',
                '\u0179': 'Z',
                '\u1E90': 'Z',
                '\u017B': 'Z',
                '\u017D': 'Z',
                '\u1E92': 'Z',
                '\u1E94': 'Z',
                '\u01B5': 'Z',
                '\u0224': 'Z',
                '\u2C7F': 'Z',
                '\u2C6B': 'Z',
                '\uA762': 'Z',
                '\u24D0': 'a',
                '\uFF41': 'a',
                '\u1E9A': 'a',
                '\u00E0': 'a',
                '\u00E1': 'a',
                '\u00E2': 'a',
                '\u1EA7': 'a',
                '\u1EA5': 'a',
                '\u1EAB': 'a',
                '\u1EA9': 'a',
                '\u00E3': 'a',
                '\u0101': 'a',
                '\u0103': 'a',
                '\u1EB1': 'a',
                '\u1EAF': 'a',
                '\u1EB5': 'a',
                '\u1EB3': 'a',
                '\u0227': 'a',
                '\u01E1': 'a',
                '\u00E4': 'a',
                '\u01DF': 'a',
                '\u1EA3': 'a',
                '\u00E5': 'a',
                '\u01FB': 'a',
                '\u01CE': 'a',
                '\u0201': 'a',
                '\u0203': 'a',
                '\u1EA1': 'a',
                '\u1EAD': 'a',
                '\u1EB7': 'a',
                '\u1E01': 'a',
                '\u0105': 'a',
                '\u2C65': 'a',
                '\u0250': 'a',
                '\uA733': 'aa',
                '\u00E6': 'ae',
                '\u01FD': 'ae',
                '\u01E3': 'ae',
                '\uA735': 'ao',
                '\uA737': 'au',
                '\uA739': 'av',
                '\uA73B': 'av',
                '\uA73D': 'ay',
                '\u24D1': 'b',
                '\uFF42': 'b',
                '\u1E03': 'b',
                '\u1E05': 'b',
                '\u1E07': 'b',
                '\u0180': 'b',
                '\u0183': 'b',
                '\u0253': 'b',
                '\u24D2': 'c',
                '\uFF43': 'c',
                '\u0107': 'c',
                '\u0109': 'c',
                '\u010B': 'c',
                '\u010D': 'c',
                '\u00E7': 'c',
                '\u1E09': 'c',
                '\u0188': 'c',
                '\u023C': 'c',
                '\uA73F': 'c',
                '\u2184': 'c',
                '\u24D3': 'd',
                '\uFF44': 'd',
                '\u1E0B': 'd',
                '\u010F': 'd',
                '\u1E0D': 'd',
                '\u1E11': 'd',
                '\u1E13': 'd',
                '\u1E0F': 'd',
                '\u0111': 'd',
                '\u018C': 'd',
                '\u0256': 'd',
                '\u0257': 'd',
                '\uA77A': 'd',
                '\u01F3': 'dz',
                '\u01C6': 'dz',
                '\u24D4': 'e',
                '\uFF45': 'e',
                '\u00E8': 'e',
                '\u00E9': 'e',
                '\u00EA': 'e',
                '\u1EC1': 'e',
                '\u1EBF': 'e',
                '\u1EC5': 'e',
                '\u1EC3': 'e',
                '\u1EBD': 'e',
                '\u0113': 'e',
                '\u1E15': 'e',
                '\u1E17': 'e',
                '\u0115': 'e',
                '\u0117': 'e',
                '\u00EB': 'e',
                '\u1EBB': 'e',
                '\u011B': 'e',
                '\u0205': 'e',
                '\u0207': 'e',
                '\u1EB9': 'e',
                '\u1EC7': 'e',
                '\u0229': 'e',
                '\u1E1D': 'e',
                '\u0119': 'e',
                '\u1E19': 'e',
                '\u1E1B': 'e',
                '\u0247': 'e',
                '\u025B': 'e',
                '\u01DD': 'e',
                '\u24D5': 'f',
                '\uFF46': 'f',
                '\u1E1F': 'f',
                '\u0192': 'f',
                '\uA77C': 'f',
                '\u24D6': 'g',
                '\uFF47': 'g',
                '\u01F5': 'g',
                '\u011D': 'g',
                '\u1E21': 'g',
                '\u011F': 'g',
                '\u0121': 'g',
                '\u01E7': 'g',
                '\u0123': 'g',
                '\u01E5': 'g',
                '\u0260': 'g',
                '\uA7A1': 'g',
                '\u1D79': 'g',
                '\uA77F': 'g',
                '\u24D7': 'h',
                '\uFF48': 'h',
                '\u0125': 'h',
                '\u1E23': 'h',
                '\u1E27': 'h',
                '\u021F': 'h',
                '\u1E25': 'h',
                '\u1E29': 'h',
                '\u1E2B': 'h',
                '\u1E96': 'h',
                '\u0127': 'h',
                '\u2C68': 'h',
                '\u2C76': 'h',
                '\u0265': 'h',
                '\u0195': 'hv',
                '\u24D8': 'i',
                '\uFF49': 'i',
                '\u00EC': 'i',
                '\u00ED': 'i',
                '\u00EE': 'i',
                '\u0129': 'i',
                '\u012B': 'i',
                '\u012D': 'i',
                '\u00EF': 'i',
                '\u1E2F': 'i',
                '\u1EC9': 'i',
                '\u01D0': 'i',
                '\u0209': 'i',
                '\u020B': 'i',
                '\u1ECB': 'i',
                '\u012F': 'i',
                '\u1E2D': 'i',
                '\u0268': 'i',
                '\u0131': 'i',
                '\u24D9': 'j',
                '\uFF4A': 'j',
                '\u0135': 'j',
                '\u01F0': 'j',
                '\u0249': 'j',
                '\u24DA': 'k',
                '\uFF4B': 'k',
                '\u1E31': 'k',
                '\u01E9': 'k',
                '\u1E33': 'k',
                '\u0137': 'k',
                '\u1E35': 'k',
                '\u0199': 'k',
                '\u2C6A': 'k',
                '\uA741': 'k',
                '\uA743': 'k',
                '\uA745': 'k',
                '\uA7A3': 'k',
                '\u24DB': 'l',
                '\uFF4C': 'l',
                '\u0140': 'l',
                '\u013A': 'l',
                '\u013E': 'l',
                '\u1E37': 'l',
                '\u1E39': 'l',
                '\u013C': 'l',
                '\u1E3D': 'l',
                '\u1E3B': 'l',
                '\u017F': 'l',
                '\u0142': 'l',
                '\u019A': 'l',
                '\u026B': 'l',
                '\u2C61': 'l',
                '\uA749': 'l',
                '\uA781': 'l',
                '\uA747': 'l',
                '\u01C9': 'lj',
                '\u24DC': 'm',
                '\uFF4D': 'm',
                '\u1E3F': 'm',
                '\u1E41': 'm',
                '\u1E43': 'm',
                '\u0271': 'm',
                '\u026F': 'm',
                '\u24DD': 'n',
                '\uFF4E': 'n',
                '\u01F9': 'n',
                '\u0144': 'n',
                '\u00F1': 'n',
                '\u1E45': 'n',
                '\u0148': 'n',
                '\u1E47': 'n',
                '\u0146': 'n',
                '\u1E4B': 'n',
                '\u1E49': 'n',
                '\u019E': 'n',
                '\u0272': 'n',
                '\u0149': 'n',
                '\uA791': 'n',
                '\uA7A5': 'n',
                '\u01CC': 'nj',
                '\u24DE': 'o',
                '\uFF4F': 'o',
                '\u00F2': 'o',
                '\u00F3': 'o',
                '\u00F4': 'o',
                '\u1ED3': 'o',
                '\u1ED1': 'o',
                '\u1ED7': 'o',
                '\u1ED5': 'o',
                '\u00F5': 'o',
                '\u1E4D': 'o',
                '\u022D': 'o',
                '\u1E4F': 'o',
                '\u014D': 'o',
                '\u1E51': 'o',
                '\u1E53': 'o',
                '\u014F': 'o',
                '\u022F': 'o',
                '\u0231': 'o',
                '\u00F6': 'o',
                '\u022B': 'o',
                '\u1ECF': 'o',
                '\u0151': 'o',
                '\u01D2': 'o',
                '\u020D': 'o',
                '\u020F': 'o',
                '\u01A1': 'o',
                '\u1EDD': 'o',
                '\u1EDB': 'o',
                '\u1EE1': 'o',
                '\u1EDF': 'o',
                '\u1EE3': 'o',
                '\u1ECD': 'o',
                '\u1ED9': 'o',
                '\u01EB': 'o',
                '\u01ED': 'o',
                '\u00F8': 'o',
                '\u01FF': 'o',
                '\u0254': 'o',
                '\uA74B': 'o',
                '\uA74D': 'o',
                '\u0275': 'o',
                '\u01A3': 'oi',
                '\u0223': 'ou',
                '\uA74F': 'oo',
                '\u24DF': 'p',
                '\uFF50': 'p',
                '\u1E55': 'p',
                '\u1E57': 'p',
                '\u01A5': 'p',
                '\u1D7D': 'p',
                '\uA751': 'p',
                '\uA753': 'p',
                '\uA755': 'p',
                '\u24E0': 'q',
                '\uFF51': 'q',
                '\u024B': 'q',
                '\uA757': 'q',
                '\uA759': 'q',
                '\u24E1': 'r',
                '\uFF52': 'r',
                '\u0155': 'r',
                '\u1E59': 'r',
                '\u0159': 'r',
                '\u0211': 'r',
                '\u0213': 'r',
                '\u1E5B': 'r',
                '\u1E5D': 'r',
                '\u0157': 'r',
                '\u1E5F': 'r',
                '\u024D': 'r',
                '\u027D': 'r',
                '\uA75B': 'r',
                '\uA7A7': 'r',
                '\uA783': 'r',
                '\u24E2': 's',
                '\uFF53': 's',
                '\u00DF': 's',
                '\u015B': 's',
                '\u1E65': 's',
                '\u015D': 's',
                '\u1E61': 's',
                '\u0161': 's',
                '\u1E67': 's',
                '\u1E63': 's',
                '\u1E69': 's',
                '\u0219': 's',
                '\u015F': 's',
                '\u023F': 's',
                '\uA7A9': 's',
                '\uA785': 's',
                '\u1E9B': 's',
                '\u24E3': 't',
                '\uFF54': 't',
                '\u1E6B': 't',
                '\u1E97': 't',
                '\u0165': 't',
                '\u1E6D': 't',
                '\u021B': 't',
                '\u0163': 't',
                '\u1E71': 't',
                '\u1E6F': 't',
                '\u0167': 't',
                '\u01AD': 't',
                '\u0288': 't',
                '\u2C66': 't',
                '\uA787': 't',
                '\uA729': 'tz',
                '\u24E4': 'u',
                '\uFF55': 'u',
                '\u00F9': 'u',
                '\u00FA': 'u',
                '\u00FB': 'u',
                '\u0169': 'u',
                '\u1E79': 'u',
                '\u016B': 'u',
                '\u1E7B': 'u',
                '\u016D': 'u',
                '\u00FC': 'u',
                '\u01DC': 'u',
                '\u01D8': 'u',
                '\u01D6': 'u',
                '\u01DA': 'u',
                '\u1EE7': 'u',
                '\u016F': 'u',
                '\u0171': 'u',
                '\u01D4': 'u',
                '\u0215': 'u',
                '\u0217': 'u',
                '\u01B0': 'u',
                '\u1EEB': 'u',
                '\u1EE9': 'u',
                '\u1EEF': 'u',
                '\u1EED': 'u',
                '\u1EF1': 'u',
                '\u1EE5': 'u',
                '\u1E73': 'u',
                '\u0173': 'u',
                '\u1E77': 'u',
                '\u1E75': 'u',
                '\u0289': 'u',
                '\u24E5': 'v',
                '\uFF56': 'v',
                '\u1E7D': 'v',
                '\u1E7F': 'v',
                '\u028B': 'v',
                '\uA75F': 'v',
                '\u028C': 'v',
                '\uA761': 'vy',
                '\u24E6': 'w',
                '\uFF57': 'w',
                '\u1E81': 'w',
                '\u1E83': 'w',
                '\u0175': 'w',
                '\u1E87': 'w',
                '\u1E85': 'w',
                '\u1E98': 'w',
                '\u1E89': 'w',
                '\u2C73': 'w',
                '\u24E7': 'x',
                '\uFF58': 'x',
                '\u1E8B': 'x',
                '\u1E8D': 'x',
                '\u24E8': 'y',
                '\uFF59': 'y',
                '\u1EF3': 'y',
                '\u00FD': 'y',
                '\u0177': 'y',
                '\u1EF9': 'y',
                '\u0233': 'y',
                '\u1E8F': 'y',
                '\u00FF': 'y',
                '\u1EF7': 'y',
                '\u1E99': 'y',
                '\u1EF5': 'y',
                '\u01B4': 'y',
                '\u024F': 'y',
                '\u1EFF': 'y',
                '\u24E9': 'z',
                '\uFF5A': 'z',
                '\u017A': 'z',
                '\u1E91': 'z',
                '\u017C': 'z',
                '\u017E': 'z',
                '\u1E93': 'z',
                '\u1E95': 'z',
                '\u01B6': 'z',
                '\u0225': 'z',
                '\u0240': 'z',
                '\u2C6C': 'z',
                '\uA763': 'z',
                '\u0386': '\u0391',
                '\u0388': '\u0395',
                '\u0389': '\u0397',
                '\u038A': '\u0399',
                '\u03AA': '\u0399',
                '\u038C': '\u039F',
                '\u038E': '\u03A5',
                '\u03AB': '\u03A5',
                '\u038F': '\u03A9',
                '\u03AC': '\u03B1',
                '\u03AD': '\u03B5',
                '\u03AE': '\u03B7',
                '\u03AF': '\u03B9',
                '\u03CA': '\u03B9',
                '\u0390': '\u03B9',
                '\u03CC': '\u03BF',
                '\u03CD': '\u03C5',
                '\u03CB': '\u03C5',
                '\u03B0': '\u03C5',
                '\u03C9': '\u03C9',
                '\u03C2': '\u03C3'
            };
            return diacritics;
        });
        S2.define('select2/data/base', [
            '../utils'
        ], function (Utils) {
            function BaseAdapter($element, options) {
                BaseAdapter.__super__.constructor.call(this);
            }
            Utils.Extend(BaseAdapter, Utils.Observable);
            BaseAdapter.prototype.current = function (callback) {
                throw new Error('The `current` method must be defined in child classes.');
            };
            BaseAdapter.prototype.query = function (params, callback) {
                throw new Error('The `query` method must be defined in child classes.');
            };
            BaseAdapter.prototype.bind = function (container, $container) {
                // Can be implemented in subclasses
            };
            BaseAdapter.prototype.destroy = function () {
                // Can be implemented in subclasses
            };
            BaseAdapter.prototype.generateResultId = function (container, data) {
                var id = container.id + '-result-';
                id += Utils.generateChars(4);
                if (data.id != null) {
                    id += '-' + data.id.toString();
                }
                else {
                    id += '-' + Utils.generateChars(4);
                }
                return id;
            };
            return BaseAdapter;
        });
        S2.define('select2/data/select', [
            './base',
            '../utils',
            'jquery'
        ], function (BaseAdapter, Utils, $) {
            function SelectAdapter($element, options) {
                this.$element = $element;
                this.options = options;
                SelectAdapter.__super__.constructor.call(this);
            }
            Utils.Extend(SelectAdapter, BaseAdapter);
            SelectAdapter.prototype.current = function (callback) {
                var data = [];
                var self = this;
                this.$element.find(':selected').each(function () {
                    var $option = $(this);
                    var option = self.item($option);
                    data.push(option);
                });
                callback(data);
            };
            SelectAdapter.prototype.select = function (data) {
                var self = this;
                data.selected = true;
                // If data.element is a DOM node, use it instead
                if ($(data.element).is('option')) {
                    data.element.selected = true;
                    this.$element.trigger('change');
                    return;
                }
                if (this.$element.prop('multiple')) {
                    this.current(function (currentData) {
                        var val = [];
                        data = [data];
                        data.push.apply(data, currentData);
                        for (var d = 0; d < data.length; d++) {
                            var id = data[d].id;
                            if ($.inArray(id, val) === -1) {
                                val.push(id);
                            }
                        }
                        self.$element.val(val);
                        self.$element.trigger('change');
                    });
                }
                else {
                    var val = data.id;
                    this.$element.val(val);
                    this.$element.trigger('change');
                }
            };
            SelectAdapter.prototype.unselect = function (data) {
                var self = this;
                if (!this.$element.prop('multiple')) {
                    return;
                }
                data.selected = false;
                if ($(data.element).is('option')) {
                    data.element.selected = false;
                    this.$element.trigger('change');
                    return;
                }
                this.current(function (currentData) {
                    var val = [];
                    for (var d = 0; d < currentData.length; d++) {
                        var id = currentData[d].id;
                        if (id !== data.id && $.inArray(id, val) === -1) {
                            val.push(id);
                        }
                    }
                    self.$element.val(val);
                    self.$element.trigger('change');
                });
            };
            SelectAdapter.prototype.bind = function (container, $container) {
                var self = this;
                this.container = container;
                container.on('select', function (params) {
                    self.select(params.data);
                });
                container.on('unselect', function (params) {
                    self.unselect(params.data);
                });
            };
            SelectAdapter.prototype.destroy = function () {
                // Remove anything added to child elements
                this.$element.find('*').each(function () {
                    // Remove any custom data set by Select2
                    $.removeData(this, 'data');
                });
            };
            SelectAdapter.prototype.query = function (params, callback) {
                var data = [];
                var self = this;
                var $options = this.$element.children();
                $options.each(function () {
                    var $option = $(this);
                    if (!$option.is('option') && !$option.is('optgroup')) {
                        return;
                    }
                    var option = self.item($option);
                    var matches = self.matches(params, option);
                    if (matches !== null) {
                        data.push(matches);
                    }
                });
                callback({
                    results: data
                });
            };
            SelectAdapter.prototype.addOptions = function ($options) {
                Utils.appendMany(this.$element, $options);
            };
            SelectAdapter.prototype.option = function (data) {
                var option;
                if (data.children) {
                    option = document.createElement('optgroup');
                    option.label = data.text;
                }
                else {
                    option = document.createElement('option');
                    if (option.textContent !== undefined) {
                        option.textContent = data.text;
                    }
                    else {
                        option.innerText = data.text;
                    }
                }
                if (data.id) {
                    option.value = data.id;
                }
                if (data.disabled) {
                    option.disabled = true;
                }
                if (data.selected) {
                    option.selected = true;
                }
                if (data.title) {
                    option.title = data.title;
                }
                var $option = $(option);
                var normalizedData = this._normalizeItem(data);
                normalizedData.element = option;
                // Override the option's data with the combined data
                $.data(option, 'data', normalizedData);
                return $option;
            };
            SelectAdapter.prototype.item = function ($option) {
                var data = {};
                data = $.data($option[0], 'data');
                if (data != null) {
                    return data;
                }
                if ($option.is('option')) {
                    data = {
                        id: $option.val(),
                        text: $option.text(),
                        disabled: $option.prop('disabled'),
                        selected: $option.prop('selected'),
                        title: $option.prop('title')
                    };
                }
                else if ($option.is('optgroup')) {
                    data = {
                        text: $option.prop('label'),
                        children: [],
                        title: $option.prop('title')
                    };
                    var $children = $option.children('option');
                    var children = [];
                    for (var c = 0; c < $children.length; c++) {
                        var $child = $($children[c]);
                        var child = this.item($child);
                        children.push(child);
                    }
                    data.children = children;
                }
                data = this._normalizeItem(data);
                data.element = $option[0];
                $.data($option[0], 'data', data);
                return data;
            };
            SelectAdapter.prototype._normalizeItem = function (item) {
                if (!$.isPlainObject(item)) {
                    item = {
                        id: item,
                        text: item
                    };
                }
                item = $.extend({}, {
                    text: ''
                }, item);
                var defaults = {
                    selected: false,
                    disabled: false
                };
                if (item.id != null) {
                    item.id = item.id.toString();
                }
                if (item.text != null) {
                    item.text = item.text.toString();
                }
                if (item._resultId == null && item.id && this.container != null) {
                    item._resultId = this.generateResultId(this.container, item);
                }
                return $.extend({}, defaults, item);
            };
            SelectAdapter.prototype.matches = function (params, data) {
                var matcher = this.options.get('matcher');
                return matcher(params, data);
            };
            return SelectAdapter;
        });
        S2.define('select2/data/array', [
            './select',
            '../utils',
            'jquery'
        ], function (SelectAdapter, Utils, $) {
            function ArrayAdapter($element, options) {
                var data = options.get('data') || [];
                ArrayAdapter.__super__.constructor.call(this, $element, options);
                this.addOptions(this.convertToOptions(data));
            }
            Utils.Extend(ArrayAdapter, SelectAdapter);
            ArrayAdapter.prototype.select = function (data) {
                var $option = this.$element.find('option').filter(function (i, elm) {
                    return elm.value == data.id.toString();
                });
                if ($option.length === 0) {
                    $option = this.option(data);
                    this.addOptions($option);
                }
                ArrayAdapter.__super__.select.call(this, data);
            };
            ArrayAdapter.prototype.convertToOptions = function (data) {
                var self = this;
                var $existing = this.$element.find('option');
                var existingIds = $existing.map(function () {
                    return self.item($(this)).id;
                }).get();
                var $options = [];
                // Filter out all items except for the one passed in the argument
                function onlyItem(item) {
                    return function () {
                        return $(this).val() == item.id;
                    };
                }
                for (var d = 0; d < data.length; d++) {
                    var item = this._normalizeItem(data[d]);
                    // Skip items which were pre-loaded, only merge the data
                    if ($.inArray(item.id, existingIds) >= 0) {
                        var $existingOption = $existing.filter(onlyItem(item));
                        var existingData = this.item($existingOption);
                        var newData = $.extend(true, {}, item, existingData);
                        var $newOption = this.option(newData);
                        $existingOption.replaceWith($newOption);
                        continue;
                    }
                    var $option = this.option(item);
                    if (item.children) {
                        var $children = this.convertToOptions(item.children);
                        Utils.appendMany($option, $children);
                    }
                    $options.push($option);
                }
                return $options;
            };
            return ArrayAdapter;
        });
        S2.define('select2/data/ajax', [
            './array',
            '../utils',
            'jquery'
        ], function (ArrayAdapter, Utils, $) {
            function AjaxAdapter($element, options) {
                this.ajaxOptions = this._applyDefaults(options.get('ajax'));
                if (this.ajaxOptions.processResults != null) {
                    this.processResults = this.ajaxOptions.processResults;
                }
                AjaxAdapter.__super__.constructor.call(this, $element, options);
            }
            Utils.Extend(AjaxAdapter, ArrayAdapter);
            AjaxAdapter.prototype._applyDefaults = function (options) {
                var defaults = {
                    data: function (params) {
                        return $.extend({}, params, {
                            q: params.term
                        });
                    },
                    transport: function (params, success, failure) {
                        var $request = $.ajax(params);
                        $request.then(success);
                        $request.fail(failure);
                        return $request;
                    }
                };
                return $.extend({}, defaults, options, true);
            };
            AjaxAdapter.prototype.processResults = function (results) {
                return results;
            };
            AjaxAdapter.prototype.query = function (params, callback) {
                var matches = [];
                var self = this;
                if (this._request != null) {
                    // JSONP requests cannot always be aborted
                    if ($.isFunction(this._request.abort)) {
                        this._request.abort();
                    }
                    this._request = null;
                }
                var options = $.extend({
                    type: 'GET'
                }, this.ajaxOptions);
                if (typeof options.url === 'function') {
                    options.url = options.url.call(this.$element, params);
                }
                if (typeof options.data === 'function') {
                    options.data = options.data.call(this.$element, params);
                }
                function request() {
                    var $request = options.transport(options, function (data) {
                        var results = self.processResults(data, params);
                        if (self.options.get('debug') && window.console && console.error) {
                            // Check to make sure that the response included a `results` key.
                            if (!results || !results.results || !$.isArray(results.results)) {
                                console.error('Select2: The AJAX results did not return an array in the ' +
                                    '`results` key of the response.');
                            }
                        }
                        callback(results);
                    }, function () {
                        // Attempt to detect if a request was aborted
                        // Only works if the transport exposes a status property
                        if ($request.status && $request.status === '0') {
                            return;
                        }
                        self.trigger('results:message', {
                            message: 'errorLoading'
                        });
                    });
                    self._request = $request;
                }
                if (this.ajaxOptions.delay && params.term != null) {
                    if (this._queryTimeout) {
                        window.clearTimeout(this._queryTimeout);
                    }
                    this._queryTimeout = window.setTimeout(request, this.ajaxOptions.delay);
                }
                else {
                    request();
                }
            };
            return AjaxAdapter;
        });
        S2.define('select2/data/tags', [
            'jquery'
        ], function ($) {
            function Tags(decorated, $element, options) {
                var tags = options.get('tags');
                var createTag = options.get('createTag');
                if (createTag !== undefined) {
                    this.createTag = createTag;
                }
                var insertTag = options.get('insertTag');
                if (insertTag !== undefined) {
                    this.insertTag = insertTag;
                }
                decorated.call(this, $element, options);
                if ($.isArray(tags)) {
                    for (var t = 0; t < tags.length; t++) {
                        var tag = tags[t];
                        var item = this._normalizeItem(tag);
                        var $option = this.option(item);
                        this.$element.append($option);
                    }
                }
            }
            Tags.prototype.query = function (decorated, params, callback) {
                var self = this;
                this._removeOldTags();
                if (params.term == null || params.page != null) {
                    decorated.call(this, params, callback);
                    return;
                }
                function wrapper(obj, child) {
                    var data = obj.results;
                    for (var i = 0; i < data.length; i++) {
                        var option = data[i];
                        var checkChildren = (option.children != null &&
                            !wrapper({
                                results: option.children
                            }, true));
                        var checkText = option.text === params.term;
                        if (checkText || checkChildren) {
                            if (child) {
                                return false;
                            }
                            obj.data = data;
                            callback(obj);
                            return;
                        }
                    }
                    if (child) {
                        return true;
                    }
                    var tag = self.createTag(params);
                    if (tag != null) {
                        var $option = self.option(tag);
                        $option.attr('data-select2-tag', true);
                        self.addOptions([$option]);
                        self.insertTag(data, tag);
                    }
                    obj.results = data;
                    callback(obj);
                }
                decorated.call(this, params, wrapper);
            };
            Tags.prototype.createTag = function (decorated, params) {
                var term = $.trim(params.term);
                if (term === '') {
                    return null;
                }
                return {
                    id: term,
                    text: term
                };
            };
            Tags.prototype.insertTag = function (_, data, tag) {
                data.unshift(tag);
            };
            Tags.prototype._removeOldTags = function (_) {
                var tag = this._lastTag;
                var $options = this.$element.find('option[data-select2-tag]');
                $options.each(function () {
                    if (this.selected) {
                        return;
                    }
                    $(this).remove();
                });
            };
            return Tags;
        });
        S2.define('select2/data/tokenizer', [
            'jquery'
        ], function ($) {
            function Tokenizer(decorated, $element, options) {
                var tokenizer = options.get('tokenizer');
                if (tokenizer !== undefined) {
                    this.tokenizer = tokenizer;
                }
                decorated.call(this, $element, options);
            }
            Tokenizer.prototype.bind = function (decorated, container, $container) {
                decorated.call(this, container, $container);
                this.$search = container.dropdown.$search || container.selection.$search ||
                    $container.find('.select2-search__field');
            };
            Tokenizer.prototype.query = function (decorated, params, callback) {
                var self = this;
                function createAndSelect(data) {
                    // Normalize the data object so we can use it for checks
                    var item = self._normalizeItem(data);
                    // Check if the data object already exists as a tag
                    // Select it if it doesn't
                    var $existingOptions = self.$element.find('option').filter(function () {
                        return $(this).val() === item.id;
                    });
                    // If an existing option wasn't found for it, create the option
                    if (!$existingOptions.length) {
                        var $option = self.option(item);
                        $option.attr('data-select2-tag', true);
                        self._removeOldTags();
                        self.addOptions([$option]);
                    }
                    // Select the item, now that we know there is an option for it
                    select(item);
                }
                function select(data) {
                    self.trigger('select', {
                        data: data
                    });
                }
                params.term = params.term || '';
                var tokenData = this.tokenizer(params, this.options, createAndSelect);
                if (tokenData.term !== params.term) {
                    // Replace the search term if we have the search box
                    if (this.$search.length) {
                        this.$search.val(tokenData.term);
                        this.$search.focus();
                    }
                    params.term = tokenData.term;
                }
                decorated.call(this, params, callback);
            };
            Tokenizer.prototype.tokenizer = function (_, params, options, callback) {
                var separators = options.get('tokenSeparators') || [];
                var term = params.term;
                var i = 0;
                var createTag = this.createTag || function (params) {
                    return {
                        id: params.term,
                        text: params.term
                    };
                };
                while (i < term.length) {
                    var termChar = term[i];
                    if ($.inArray(termChar, separators) === -1) {
                        i++;
                        continue;
                    }
                    var part = term.substr(0, i);
                    var partParams = $.extend({}, params, {
                        term: part
                    });
                    var data = createTag(partParams);
                    if (data == null) {
                        i++;
                        continue;
                    }
                    callback(data);
                    // Reset the term to not include the tokenized portion
                    term = term.substr(i + 1) || '';
                    i = 0;
                }
                return {
                    term: term
                };
            };
            return Tokenizer;
        });
        S2.define('select2/data/minimumInputLength', [], function () {
            function MinimumInputLength(decorated, $e, options) {
                this.minimumInputLength = options.get('minimumInputLength');
                decorated.call(this, $e, options);
            }
            MinimumInputLength.prototype.query = function (decorated, params, callback) {
                params.term = params.term || '';
                if (params.term.length < this.minimumInputLength) {
                    this.trigger('results:message', {
                        message: 'inputTooShort',
                        args: {
                            minimum: this.minimumInputLength,
                            input: params.term,
                            params: params
                        }
                    });
                    return;
                }
                decorated.call(this, params, callback);
            };
            return MinimumInputLength;
        });
        S2.define('select2/data/maximumInputLength', [], function () {
            function MaximumInputLength(decorated, $e, options) {
                this.maximumInputLength = options.get('maximumInputLength');
                decorated.call(this, $e, options);
            }
            MaximumInputLength.prototype.query = function (decorated, params, callback) {
                params.term = params.term || '';
                if (this.maximumInputLength > 0 &&
                    params.term.length > this.maximumInputLength) {
                    this.trigger('results:message', {
                        message: 'inputTooLong',
                        args: {
                            maximum: this.maximumInputLength,
                            input: params.term,
                            params: params
                        }
                    });
                    return;
                }
                decorated.call(this, params, callback);
            };
            return MaximumInputLength;
        });
        S2.define('select2/data/maximumSelectionLength', [], function () {
            function MaximumSelectionLength(decorated, $e, options) {
                this.maximumSelectionLength = options.get('maximumSelectionLength');
                decorated.call(this, $e, options);
            }
            MaximumSelectionLength.prototype.query =
                function (decorated, params, callback) {
                    var self = this;
                    this.current(function (currentData) {
                        var count = currentData != null ? currentData.length : 0;
                        if (self.maximumSelectionLength > 0 &&
                            count >= self.maximumSelectionLength) {
                            self.trigger('results:message', {
                                message: 'maximumSelected',
                                args: {
                                    maximum: self.maximumSelectionLength
                                }
                            });
                            return;
                        }
                        decorated.call(self, params, callback);
                    });
                };
            return MaximumSelectionLength;
        });
        S2.define('select2/dropdown', [
            'jquery',
            './utils'
        ], function ($, Utils) {
            function Dropdown($element, options) {
                this.$element = $element;
                this.options = options;
                Dropdown.__super__.constructor.call(this);
            }
            Utils.Extend(Dropdown, Utils.Observable);
            Dropdown.prototype.render = function () {
                var $dropdown = $('<span class="select2-dropdown">' +
                    '<span class="select2-results"></span>' +
                    '</span>');
                $dropdown.attr('dir', this.options.get('dir'));
                this.$dropdown = $dropdown;
                return $dropdown;
            };
            Dropdown.prototype.bind = function () {
                // Should be implemented in subclasses
            };
            Dropdown.prototype.position = function ($dropdown, $container) {
                // Should be implmented in subclasses
            };
            Dropdown.prototype.destroy = function () {
                // Remove the dropdown from the DOM
                this.$dropdown.remove();
            };
            return Dropdown;
        });
        S2.define('select2/dropdown/search', [
            'jquery',
            '../utils'
        ], function ($, Utils) {
            function Search() { }
            Search.prototype.render = function (decorated) {
                var $rendered = decorated.call(this);
                var $search = $('<span class="select2-search select2-search--dropdown">' +
                    '<input class="select2-search__field" type="search" tabindex="-1"' +
                    ' autocomplete="off" autocorrect="off" autocapitalize="off"' +
                    ' spellcheck="false" role="textbox" />' +
                    '</span>');
                this.$searchContainer = $search;
                this.$search = $search.find('input');
                $rendered.prepend($search);
                return $rendered;
            };
            Search.prototype.bind = function (decorated, container, $container) {
                var self = this;
                decorated.call(this, container, $container);
                this.$search.on('keydown', function (evt) {
                    self.trigger('keypress', evt);
                    self._keyUpPrevented = evt.isDefaultPrevented();
                });
                // Workaround for browsers which do not support the `input` event
                // This will prevent double-triggering of events for browsers which support
                // both the `keyup` and `input` events.
                this.$search.on('input', function (evt) {
                    // Unbind the duplicated `keyup` event
                    $(this).off('keyup');
                });
                this.$search.on('keyup input', function (evt) {
                    self.handleSearch(evt);
                });
                container.on('open', function () {
                    self.$search.attr('tabindex', 0);
                    self.$search.focus();
                    window.setTimeout(function () {
                        self.$search.focus();
                    }, 0);
                });
                container.on('close', function () {
                    self.$search.attr('tabindex', -1);
                    self.$search.val('');
                });
                container.on('focus', function () {
                    if (container.isOpen()) {
                        self.$search.focus();
                    }
                });
                container.on('results:all', function (params) {
                    if (params.query.term == null || params.query.term === '') {
                        var showSearch = self.showSearch(params);
                        if (showSearch) {
                            self.$searchContainer.removeClass('select2-search--hide');
                        }
                        else {
                            self.$searchContainer.addClass('select2-search--hide');
                        }
                    }
                });
            };
            Search.prototype.handleSearch = function (evt) {
                if (!this._keyUpPrevented) {
                    var input = this.$search.val();
                    this.trigger('query', {
                        term: input
                    });
                }
                this._keyUpPrevented = false;
            };
            Search.prototype.showSearch = function (_, params) {
                return true;
            };
            return Search;
        });
        S2.define('select2/dropdown/hidePlaceholder', [], function () {
            function HidePlaceholder(decorated, $element, options, dataAdapter) {
                this.placeholder = this.normalizePlaceholder(options.get('placeholder'));
                decorated.call(this, $element, options, dataAdapter);
            }
            HidePlaceholder.prototype.append = function (decorated, data) {
                data.results = this.removePlaceholder(data.results);
                decorated.call(this, data);
            };
            HidePlaceholder.prototype.normalizePlaceholder = function (_, placeholder) {
                if (typeof placeholder === 'string') {
                    placeholder = {
                        id: '',
                        text: placeholder
                    };
                }
                return placeholder;
            };
            HidePlaceholder.prototype.removePlaceholder = function (_, data) {
                var modifiedData = data.slice(0);
                for (var d = data.length - 1; d >= 0; d--) {
                    var item = data[d];
                    if (this.placeholder.id === item.id) {
                        modifiedData.splice(d, 1);
                    }
                }
                return modifiedData;
            };
            return HidePlaceholder;
        });
        S2.define('select2/dropdown/infiniteScroll', [
            'jquery'
        ], function ($) {
            function InfiniteScroll(decorated, $element, options, dataAdapter) {
                this.lastParams = {};
                decorated.call(this, $element, options, dataAdapter);
                this.$loadingMore = this.createLoadingMore();
                this.loading = false;
            }
            InfiniteScroll.prototype.append = function (decorated, data) {
                this.$loadingMore.remove();
                this.loading = false;
                decorated.call(this, data);
                if (this.showLoadingMore(data)) {
                    this.$results.append(this.$loadingMore);
                }
            };
            InfiniteScroll.prototype.bind = function (decorated, container, $container) {
                var self = this;
                decorated.call(this, container, $container);
                container.on('query', function (params) {
                    self.lastParams = params;
                    self.loading = true;
                });
                container.on('query:append', function (params) {
                    self.lastParams = params;
                    self.loading = true;
                });
                this.$results.on('scroll', function () {
                    var isLoadMoreVisible = $.contains(document.documentElement, self.$loadingMore[0]);
                    if (self.loading || !isLoadMoreVisible) {
                        return;
                    }
                    var currentOffset = self.$results.offset().top +
                        self.$results.outerHeight(false);
                    var loadingMoreOffset = self.$loadingMore.offset().top +
                        self.$loadingMore.outerHeight(false);
                    if (currentOffset + 50 >= loadingMoreOffset) {
                        self.loadMore();
                    }
                });
            };
            InfiniteScroll.prototype.loadMore = function () {
                this.loading = true;
                var params = $.extend({}, { page: 1 }, this.lastParams);
                params.page++;
                this.trigger('query:append', params);
            };
            InfiniteScroll.prototype.showLoadingMore = function (_, data) {
                return data.pagination && data.pagination.more;
            };
            InfiniteScroll.prototype.createLoadingMore = function () {
                var $option = $('<li ' +
                    'class="select2-results__option select2-results__option--load-more"' +
                    'role="treeitem" aria-disabled="true"></li>');
                var message = this.options.get('translations').get('loadingMore');
                $option.html(message(this.lastParams));
                return $option;
            };
            return InfiniteScroll;
        });
        S2.define('select2/dropdown/attachBody', [
            'jquery',
            '../utils'
        ], function ($, Utils) {
            function AttachBody(decorated, $element, options) {
                this.$dropdownParent = options.get('dropdownParent') || $(document.body);
                decorated.call(this, $element, options);
            }
            AttachBody.prototype.bind = function (decorated, container, $container) {
                var self = this;
                var setupResultsEvents = false;
                decorated.call(this, container, $container);
                container.on('open', function () {
                    self._showDropdown();
                    self._attachPositioningHandler(container);
                    if (!setupResultsEvents) {
                        setupResultsEvents = true;
                        container.on('results:all', function () {
                            self._positionDropdown();
                            self._resizeDropdown();
                        });
                        container.on('results:append', function () {
                            self._positionDropdown();
                            self._resizeDropdown();
                        });
                    }
                });
                container.on('close', function () {
                    self._hideDropdown();
                    self._detachPositioningHandler(container);
                });
                this.$dropdownContainer.on('mousedown', function (evt) {
                    evt.stopPropagation();
                });
            };
            AttachBody.prototype.destroy = function (decorated) {
                decorated.call(this);
                this.$dropdownContainer.remove();
            };
            AttachBody.prototype.position = function (decorated, $dropdown, $container) {
                // Clone all of the container classes
                $dropdown.attr('class', $container.attr('class'));
                $dropdown.removeClass('select2');
                $dropdown.addClass('select2-container--open');
                $dropdown.css({
                    position: 'absolute',
                    top: -999999
                });
                this.$container = $container;
            };
            AttachBody.prototype.render = function (decorated) {
                var $container = $('<span></span>');
                var $dropdown = decorated.call(this);
                $container.append($dropdown);
                this.$dropdownContainer = $container;
                return $container;
            };
            AttachBody.prototype._hideDropdown = function (decorated) {
                this.$dropdownContainer.detach();
            };
            AttachBody.prototype._attachPositioningHandler =
                function (decorated, container) {
                    var self = this;
                    var scrollEvent = 'scroll.select2.' + container.id;
                    var resizeEvent = 'resize.select2.' + container.id;
                    var orientationEvent = 'orientationchange.select2.' + container.id;
                    var $watchers = this.$container.parents().filter(Utils.hasScroll);
                    $watchers.each(function () {
                        $(this).data('select2-scroll-position', {
                            x: $(this).scrollLeft(),
                            y: $(this).scrollTop()
                        });
                    });
                    $watchers.on(scrollEvent, function (ev) {
                        var position = $(this).data('select2-scroll-position');
                        $(this).scrollTop(position.y);
                    });
                    $(window).on(scrollEvent + ' ' + resizeEvent + ' ' + orientationEvent, function (e) {
                        self._positionDropdown();
                        self._resizeDropdown();
                    });
                };
            AttachBody.prototype._detachPositioningHandler =
                function (decorated, container) {
                    var scrollEvent = 'scroll.select2.' + container.id;
                    var resizeEvent = 'resize.select2.' + container.id;
                    var orientationEvent = 'orientationchange.select2.' + container.id;
                    var $watchers = this.$container.parents().filter(Utils.hasScroll);
                    $watchers.off(scrollEvent);
                    $(window).off(scrollEvent + ' ' + resizeEvent + ' ' + orientationEvent);
                };
            AttachBody.prototype._positionDropdown = function () {
                var $window = $(window);
                var isCurrentlyAbove = this.$dropdown.hasClass('select2-dropdown--above');
                var isCurrentlyBelow = this.$dropdown.hasClass('select2-dropdown--below');
                var newDirection = null;
                var offset = this.$container.offset();
                offset.bottom = offset.top + this.$container.outerHeight(false);
                var container = {
                    height: this.$container.outerHeight(false)
                };
                container.top = offset.top;
                container.bottom = offset.top + container.height;
                var dropdown = {
                    height: this.$dropdown.outerHeight(false)
                };
                var viewport = {
                    top: $window.scrollTop(),
                    bottom: $window.scrollTop() + $window.height()
                };
                var enoughRoomAbove = viewport.top < (offset.top - dropdown.height);
                var enoughRoomBelow = viewport.bottom > (offset.bottom + dropdown.height);
                var css = {
                    left: offset.left,
                    top: container.bottom
                };
                // Determine what the parent element is to use for calciulating the offset
                var $offsetParent = this.$dropdownParent;
                // For statically positoned elements, we need to get the element
                // that is determining the offset
                if ($offsetParent.css('position') === 'static') {
                    $offsetParent = $offsetParent.offsetParent();
                }
                var parentOffset = $offsetParent.offset();
                css.top -= parentOffset.top;
                css.left -= parentOffset.left;
                if (!isCurrentlyAbove && !isCurrentlyBelow) {
                    newDirection = 'below';
                }
                if (!enoughRoomBelow && enoughRoomAbove && !isCurrentlyAbove) {
                    newDirection = 'above';
                }
                else if (!enoughRoomAbove && enoughRoomBelow && isCurrentlyAbove) {
                    newDirection = 'below';
                }
                if (newDirection == 'above' ||
                    (isCurrentlyAbove && newDirection !== 'below')) {
                    css.top = container.top - parentOffset.top - dropdown.height;
                }
                if (newDirection != null) {
                    this.$dropdown
                        .removeClass('select2-dropdown--below select2-dropdown--above')
                        .addClass('select2-dropdown--' + newDirection);
                    this.$container
                        .removeClass('select2-container--below select2-container--above')
                        .addClass('select2-container--' + newDirection);
                }
                this.$dropdownContainer.css(css);
            };
            AttachBody.prototype._resizeDropdown = function () {
                var css = {
                    width: this.$container.outerWidth(false) + 'px'
                };
                if (this.options.get('dropdownAutoWidth')) {
                    css.minWidth = css.width;
                    css.position = 'relative';
                    css.width = 'auto';
                }
                this.$dropdown.css(css);
            };
            AttachBody.prototype._showDropdown = function (decorated) {
                this.$dropdownContainer.appendTo(this.$dropdownParent);
                this._positionDropdown();
                this._resizeDropdown();
            };
            return AttachBody;
        });
        S2.define('select2/dropdown/minimumResultsForSearch', [], function () {
            function countResults(data) {
                var count = 0;
                for (var d = 0; d < data.length; d++) {
                    var item = data[d];
                    if (item.children) {
                        count += countResults(item.children);
                    }
                    else {
                        count++;
                    }
                }
                return count;
            }
            function MinimumResultsForSearch(decorated, $element, options, dataAdapter) {
                this.minimumResultsForSearch = options.get('minimumResultsForSearch');
                if (this.minimumResultsForSearch < 0) {
                    this.minimumResultsForSearch = Infinity;
                }
                decorated.call(this, $element, options, dataAdapter);
            }
            MinimumResultsForSearch.prototype.showSearch = function (decorated, params) {
                if (countResults(params.data.results) < this.minimumResultsForSearch) {
                    return false;
                }
                return decorated.call(this, params);
            };
            return MinimumResultsForSearch;
        });
        S2.define('select2/dropdown/selectOnClose', [], function () {
            function SelectOnClose() { }
            SelectOnClose.prototype.bind = function (decorated, container, $container) {
                var self = this;
                decorated.call(this, container, $container);
                container.on('close', function (params) {
                    self._handleSelectOnClose(params);
                });
            };
            SelectOnClose.prototype._handleSelectOnClose = function (_, params) {
                if (params && params.originalSelect2Event != null) {
                    var event = params.originalSelect2Event;
                    // Don't select an item if the close event was triggered from a select or
                    // unselect event
                    if (event._type === 'select' || event._type === 'unselect') {
                        return;
                    }
                }
                var $highlightedResults = this.getHighlightedResults();
                // Only select highlighted results
                if ($highlightedResults.length < 1) {
                    return;
                }
                var data = $highlightedResults.data('data');
                // Don't re-select already selected resulte
                if ((data.element != null && data.element.selected) ||
                    (data.element == null && data.selected)) {
                    return;
                }
                this.trigger('select', {
                    data: data
                });
            };
            return SelectOnClose;
        });
        S2.define('select2/dropdown/closeOnSelect', [], function () {
            function CloseOnSelect() { }
            CloseOnSelect.prototype.bind = function (decorated, container, $container) {
                var self = this;
                decorated.call(this, container, $container);
                container.on('select', function (evt) {
                    self._selectTriggered(evt);
                });
                container.on('unselect', function (evt) {
                    self._selectTriggered(evt);
                });
            };
            CloseOnSelect.prototype._selectTriggered = function (_, evt) {
                var originalEvent = evt.originalEvent;
                // Don't close if the control key is being held
                if (originalEvent && originalEvent.ctrlKey) {
                    return;
                }
                this.trigger('close', {
                    originalEvent: originalEvent,
                    originalSelect2Event: evt
                });
            };
            return CloseOnSelect;
        });
        S2.define('select2/i18n/en', [], function () {
            // English
            return {
                errorLoading: function () {
                    return 'The results could not be loaded.';
                },
                inputTooLong: function (args) {
                    var overChars = args.input.length - args.maximum;
                    var message = 'Please delete ' + overChars + ' character';
                    if (overChars != 1) {
                        message += 's';
                    }
                    return message;
                },
                inputTooShort: function (args) {
                    var remainingChars = args.minimum - args.input.length;
                    var message = 'Please enter ' + remainingChars + ' or more characters';
                    return message;
                },
                loadingMore: function () {
                    return 'Loading more results…';
                },
                maximumSelected: function (args) {
                    var message = 'You can only select ' + args.maximum + ' item';
                    if (args.maximum != 1) {
                        message += 's';
                    }
                    return message;
                },
                noResults: function () {
                    return 'No results found';
                },
                searching: function () {
                    return 'Searching…';
                }
            };
        });
        S2.define('select2/defaults', [
            'jquery',
            'require',
            './results',
            './selection/single',
            './selection/multiple',
            './selection/placeholder',
            './selection/allowClear',
            './selection/search',
            './selection/eventRelay',
            './utils',
            './translation',
            './diacritics',
            './data/select',
            './data/array',
            './data/ajax',
            './data/tags',
            './data/tokenizer',
            './data/minimumInputLength',
            './data/maximumInputLength',
            './data/maximumSelectionLength',
            './dropdown',
            './dropdown/search',
            './dropdown/hidePlaceholder',
            './dropdown/infiniteScroll',
            './dropdown/attachBody',
            './dropdown/minimumResultsForSearch',
            './dropdown/selectOnClose',
            './dropdown/closeOnSelect',
            './i18n/en'
        ], function ($, require, ResultsList, SingleSelection, MultipleSelection, Placeholder, AllowClear, SelectionSearch, EventRelay, Utils, Translation, DIACRITICS, SelectData, ArrayData, AjaxData, Tags, Tokenizer, MinimumInputLength, MaximumInputLength, MaximumSelectionLength, Dropdown, DropdownSearch, HidePlaceholder, InfiniteScroll, AttachBody, MinimumResultsForSearch, SelectOnClose, CloseOnSelect, EnglishTranslation) {
            function Defaults() {
                this.reset();
            }
            Defaults.prototype.apply = function (options) {
                options = $.extend(true, {}, this.defaults, options);
                if (options.dataAdapter == null) {
                    if (options.ajax != null) {
                        options.dataAdapter = AjaxData;
                    }
                    else if (options.data != null) {
                        options.dataAdapter = ArrayData;
                    }
                    else {
                        options.dataAdapter = SelectData;
                    }
                    if (options.minimumInputLength > 0) {
                        options.dataAdapter = Utils.Decorate(options.dataAdapter, MinimumInputLength);
                    }
                    if (options.maximumInputLength > 0) {
                        options.dataAdapter = Utils.Decorate(options.dataAdapter, MaximumInputLength);
                    }
                    if (options.maximumSelectionLength > 0) {
                        options.dataAdapter = Utils.Decorate(options.dataAdapter, MaximumSelectionLength);
                    }
                    if (options.tags) {
                        options.dataAdapter = Utils.Decorate(options.dataAdapter, Tags);
                    }
                    if (options.tokenSeparators != null || options.tokenizer != null) {
                        options.dataAdapter = Utils.Decorate(options.dataAdapter, Tokenizer);
                    }
                    if (options.query != null) {
                        var Query = require(options.amdBase + 'compat/query');
                        options.dataAdapter = Utils.Decorate(options.dataAdapter, Query);
                    }
                    if (options.initSelection != null) {
                        var InitSelection = require(options.amdBase + 'compat/initSelection');
                        options.dataAdapter = Utils.Decorate(options.dataAdapter, InitSelection);
                    }
                }
                if (options.resultsAdapter == null) {
                    options.resultsAdapter = ResultsList;
                    if (options.ajax != null) {
                        options.resultsAdapter = Utils.Decorate(options.resultsAdapter, InfiniteScroll);
                    }
                    if (options.placeholder != null) {
                        options.resultsAdapter = Utils.Decorate(options.resultsAdapter, HidePlaceholder);
                    }
                    if (options.selectOnClose) {
                        options.resultsAdapter = Utils.Decorate(options.resultsAdapter, SelectOnClose);
                    }
                }
                if (options.dropdownAdapter == null) {
                    if (options.multiple) {
                        options.dropdownAdapter = Dropdown;
                    }
                    else {
                        var SearchableDropdown = Utils.Decorate(Dropdown, DropdownSearch);
                        options.dropdownAdapter = SearchableDropdown;
                    }
                    if (options.minimumResultsForSearch !== 0) {
                        options.dropdownAdapter = Utils.Decorate(options.dropdownAdapter, MinimumResultsForSearch);
                    }
                    if (options.closeOnSelect) {
                        options.dropdownAdapter = Utils.Decorate(options.dropdownAdapter, CloseOnSelect);
                    }
                    if (options.dropdownCssClass != null ||
                        options.dropdownCss != null ||
                        options.adaptDropdownCssClass != null) {
                        var DropdownCSS = require(options.amdBase + 'compat/dropdownCss');
                        options.dropdownAdapter = Utils.Decorate(options.dropdownAdapter, DropdownCSS);
                    }
                    options.dropdownAdapter = Utils.Decorate(options.dropdownAdapter, AttachBody);
                }
                if (options.selectionAdapter == null) {
                    if (options.multiple) {
                        options.selectionAdapter = MultipleSelection;
                    }
                    else {
                        options.selectionAdapter = SingleSelection;
                    }
                    // Add the placeholder mixin if a placeholder was specified
                    if (options.placeholder != null) {
                        options.selectionAdapter = Utils.Decorate(options.selectionAdapter, Placeholder);
                    }
                    if (options.allowClear) {
                        options.selectionAdapter = Utils.Decorate(options.selectionAdapter, AllowClear);
                    }
                    if (options.multiple) {
                        options.selectionAdapter = Utils.Decorate(options.selectionAdapter, SelectionSearch);
                    }
                    if (options.containerCssClass != null ||
                        options.containerCss != null ||
                        options.adaptContainerCssClass != null) {
                        var ContainerCSS = require(options.amdBase + 'compat/containerCss');
                        options.selectionAdapter = Utils.Decorate(options.selectionAdapter, ContainerCSS);
                    }
                    options.selectionAdapter = Utils.Decorate(options.selectionAdapter, EventRelay);
                }
                if (typeof options.language === 'string') {
                    // Check if the language is specified with a region
                    if (options.language.indexOf('-') > 0) {
                        // Extract the region information if it is included
                        var languageParts = options.language.split('-');
                        var baseLanguage = languageParts[0];
                        options.language = [options.language, baseLanguage];
                    }
                    else {
                        options.language = [options.language];
                    }
                }
                if ($.isArray(options.language)) {
                    var languages = new Translation();
                    options.language.push('en');
                    var languageNames = options.language;
                    for (var l = 0; l < languageNames.length; l++) {
                        var name = languageNames[l];
                        var language = {};
                        try {
                            // Try to load it with the original name
                            language = Translation.loadPath(name);
                        }
                        catch (e) {
                            try {
                                // If we couldn't load it, check if it wasn't the full path
                                name = this.defaults.amdLanguageBase + name;
                                language = Translation.loadPath(name);
                            }
                            catch (ex) {
                                // The translation could not be loaded at all. Sometimes this is
                                // because of a configuration problem, other times this can be
                                // because of how Select2 helps load all possible translation files.
                                if (options.debug && window.console && console.warn) {
                                    console.warn('Select2: The language file for "' + name + '" could not be ' +
                                        'automatically loaded. A fallback will be used instead.');
                                }
                                continue;
                            }
                        }
                        languages.extend(language);
                    }
                    options.translations = languages;
                }
                else {
                    var baseTranslation = Translation.loadPath(this.defaults.amdLanguageBase + 'en');
                    var customTranslation = new Translation(options.language);
                    customTranslation.extend(baseTranslation);
                    options.translations = customTranslation;
                }
                return options;
            };
            Defaults.prototype.reset = function () {
                function stripDiacritics(text) {
                    // Used 'uni range + named function' from http://jsperf.com/diacritics/18
                    function match(a) {
                        return DIACRITICS[a] || a;
                    }
                    return text.replace(/[^\u0000-\u007E]/g, match);
                }
                function matcher(params, data) {
                    // Always return the object if there is nothing to compare
                    if ($.trim(params.term) === '') {
                        return data;
                    }
                    // Do a recursive check for options with children
                    if (data.children && data.children.length > 0) {
                        // Clone the data object if there are children
                        // This is required as we modify the object to remove any non-matches
                        var match = $.extend(true, {}, data);
                        // Check each child of the option
                        for (var c = data.children.length - 1; c >= 0; c--) {
                            var child = data.children[c];
                            var matches = matcher(params, child);
                            // If there wasn't a match, remove the object in the array
                            if (matches == null) {
                                match.children.splice(c, 1);
                            }
                        }
                        // If any children matched, return the new object
                        if (match.children.length > 0) {
                            return match;
                        }
                        // If there were no matching children, check just the plain object
                        return matcher(params, match);
                    }
                    var original = stripDiacritics(data.text).toUpperCase();
                    var term = stripDiacritics(params.term).toUpperCase();
                    // Check if the text contains the term
                    if (original.indexOf(term) > -1) {
                        return data;
                    }
                    // If it doesn't contain the term, don't return anything
                    return null;
                }
                this.defaults = {
                    amdBase: './',
                    amdLanguageBase: './i18n/',
                    closeOnSelect: true,
                    debug: false,
                    dropdownAutoWidth: false,
                    escapeMarkup: Utils.escapeMarkup,
                    language: EnglishTranslation,
                    matcher: matcher,
                    minimumInputLength: 0,
                    maximumInputLength: 0,
                    maximumSelectionLength: 0,
                    minimumResultsForSearch: 0,
                    selectOnClose: false,
                    sorter: function (data) {
                        return data;
                    },
                    templateResult: function (result) {
                        return result.text;
                    },
                    templateSelection: function (selection) {
                        return selection.text;
                    },
                    theme: 'default',
                    width: 'resolve'
                };
            };
            Defaults.prototype.set = function (key, value) {
                var camelKey = $.camelCase(key);
                var data = {};
                data[camelKey] = value;
                var convertedData = Utils._convertData(data);
                $.extend(this.defaults, convertedData);
            };
            var defaults = new Defaults();
            return defaults;
        });
        S2.define('select2/options', [
            'require',
            'jquery',
            './defaults',
            './utils'
        ], function (require, $, Defaults, Utils) {
            function Options(options, $element) {
                this.options = options;
                if ($element != null) {
                    this.fromElement($element);
                }
                this.options = Defaults.apply(this.options);
                if ($element && $element.is('input')) {
                    var InputCompat = require(this.get('amdBase') + 'compat/inputData');
                    this.options.dataAdapter = Utils.Decorate(this.options.dataAdapter, InputCompat);
                }
            }
            Options.prototype.fromElement = function ($e) {
                var excludedData = ['select2'];
                if (this.options.multiple == null) {
                    this.options.multiple = $e.prop('multiple');
                }
                if (this.options.disabled == null) {
                    this.options.disabled = $e.prop('disabled');
                }
                if (this.options.language == null) {
                    if ($e.prop('lang')) {
                        this.options.language = $e.prop('lang').toLowerCase();
                    }
                    else if ($e.closest('[lang]').prop('lang')) {
                        this.options.language = $e.closest('[lang]').prop('lang');
                    }
                }
                if (this.options.dir == null) {
                    if ($e.prop('dir')) {
                        this.options.dir = $e.prop('dir');
                    }
                    else if ($e.closest('[dir]').prop('dir')) {
                        this.options.dir = $e.closest('[dir]').prop('dir');
                    }
                    else {
                        this.options.dir = 'ltr';
                    }
                }
                $e.prop('disabled', this.options.disabled);
                $e.prop('multiple', this.options.multiple);
                if ($e.data('select2Tags')) {
                    if (this.options.debug && window.console && console.warn) {
                        console.warn('Select2: The `data-select2-tags` attribute has been changed to ' +
                            'use the `data-data` and `data-tags="true"` attributes and will be ' +
                            'removed in future versions of Select2.');
                    }
                    $e.data('data', $e.data('select2Tags'));
                    $e.data('tags', true);
                }
                if ($e.data('ajaxUrl')) {
                    if (this.options.debug && window.console && console.warn) {
                        console.warn('Select2: The `data-ajax-url` attribute has been changed to ' +
                            '`data-ajax--url` and support for the old attribute will be removed' +
                            ' in future versions of Select2.');
                    }
                    $e.attr('ajax--url', $e.data('ajaxUrl'));
                    $e.data('ajax--url', $e.data('ajaxUrl'));
                }
                var dataset = {};
                // Prefer the element's `dataset` attribute if it exists
                // jQuery 1.x does not correctly handle data attributes with multiple dashes
                if ($.fn.jquery && $.fn.jquery.substr(0, 2) == '1.' && $e[0].dataset) {
                    dataset = $.extend(true, {}, $e[0].dataset, $e.data());
                }
                else {
                    dataset = $e.data();
                }
                var data = $.extend(true, {}, dataset);
                data = Utils._convertData(data);
                for (var key in data) {
                    if ($.inArray(key, excludedData) > -1) {
                        continue;
                    }
                    if ($.isPlainObject(this.options[key])) {
                        $.extend(this.options[key], data[key]);
                    }
                    else {
                        this.options[key] = data[key];
                    }
                }
                return this;
            };
            Options.prototype.get = function (key) {
                return this.options[key];
            };
            Options.prototype.set = function (key, val) {
                this.options[key] = val;
            };
            return Options;
        });
        S2.define('select2/core', [
            'jquery',
            './options',
            './utils',
            './keys'
        ], function ($, Options, Utils, KEYS) {
            var Select2 = function ($element, options) {
                if ($element.data('select2') != null) {
                    $element.data('select2').destroy();
                }
                this.$element = $element;
                this.id = this._generateId($element);
                options = options || {};
                this.options = new Options(options, $element);
                Select2.__super__.constructor.call(this);
                // Set up the tabindex
                var tabindex = $element.attr('tabindex') || 0;
                $element.data('old-tabindex', tabindex);
                $element.attr('tabindex', '-1');
                // Set up containers and adapters
                var DataAdapter = this.options.get('dataAdapter');
                this.dataAdapter = new DataAdapter($element, this.options);
                var $container = this.render();
                this._placeContainer($container);
                var SelectionAdapter = this.options.get('selectionAdapter');
                this.selection = new SelectionAdapter($element, this.options);
                this.$selection = this.selection.render();
                this.selection.position(this.$selection, $container);
                var DropdownAdapter = this.options.get('dropdownAdapter');
                this.dropdown = new DropdownAdapter($element, this.options);
                this.$dropdown = this.dropdown.render();
                this.dropdown.position(this.$dropdown, $container);
                var ResultsAdapter = this.options.get('resultsAdapter');
                this.results = new ResultsAdapter($element, this.options, this.dataAdapter);
                this.$results = this.results.render();
                this.results.position(this.$results, this.$dropdown);
                // Bind events
                var self = this;
                // Bind the container to all of the adapters
                this._bindAdapters();
                // Register any DOM event handlers
                this._registerDomEvents();
                // Register any internal event handlers
                this._registerDataEvents();
                this._registerSelectionEvents();
                this._registerDropdownEvents();
                this._registerResultsEvents();
                this._registerEvents();
                // Set the initial state
                this.dataAdapter.current(function (initialData) {
                    self.trigger('selection:update', {
                        data: initialData
                    });
                });
                // Hide the original select
                $element.addClass('select2-hidden-accessible');
                $element.attr('aria-hidden', 'true');
                // Synchronize any monitored attributes
                this._syncAttributes();
                $element.data('select2', this);
            };
            Utils.Extend(Select2, Utils.Observable);
            Select2.prototype._generateId = function ($element) {
                var id = '';
                if ($element.attr('id') != null) {
                    id = $element.attr('id');
                }
                else if ($element.attr('name') != null) {
                    id = $element.attr('name') + '-' + Utils.generateChars(2);
                }
                else {
                    id = Utils.generateChars(4);
                }
                id = id.replace(/(:|\.|\[|\]|,)/g, '');
                id = 'select2-' + id;
                return id;
            };
            Select2.prototype._placeContainer = function ($container) {
                $container.insertAfter(this.$element);
                var width = this._resolveWidth(this.$element, this.options.get('width'));
                if (width != null) {
                    $container.css('width', width);
                }
            };
            Select2.prototype._resolveWidth = function ($element, method) {
                var WIDTH = /^width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/i;
                if (method == 'resolve') {
                    var styleWidth = this._resolveWidth($element, 'style');
                    if (styleWidth != null) {
                        return styleWidth;
                    }
                    return this._resolveWidth($element, 'element');
                }
                if (method == 'element') {
                    var elementWidth = $element.outerWidth(false);
                    if (elementWidth <= 0) {
                        return 'auto';
                    }
                    return elementWidth + 'px';
                }
                if (method == 'style') {
                    var style = $element.attr('style');
                    if (typeof (style) !== 'string') {
                        return null;
                    }
                    var attrs = style.split(';');
                    for (var i = 0, l = attrs.length; i < l; i = i + 1) {
                        var attr = attrs[i].replace(/\s/g, '');
                        var matches = attr.match(WIDTH);
                        if (matches !== null && matches.length >= 1) {
                            return matches[1];
                        }
                    }
                    return null;
                }
                return method;
            };
            Select2.prototype._bindAdapters = function () {
                this.dataAdapter.bind(this, this.$container);
                this.selection.bind(this, this.$container);
                this.dropdown.bind(this, this.$container);
                this.results.bind(this, this.$container);
            };
            Select2.prototype._registerDomEvents = function () {
                var self = this;
                this.$element.on('change.select2', function () {
                    self.dataAdapter.current(function (data) {
                        self.trigger('selection:update', {
                            data: data
                        });
                    });
                });
                this.$element.on('focus.select2', function (evt) {
                    self.trigger('focus', evt);
                });
                this._syncA = Utils.bind(this._syncAttributes, this);
                this._syncS = Utils.bind(this._syncSubtree, this);
                if (this.$element[0].attachEvent) {
                    this.$element[0].attachEvent('onpropertychange', this._syncA);
                }
                var observer = window.MutationObserver ||
                    window.WebKitMutationObserver ||
                    window.MozMutationObserver;
                if (observer != null) {
                    this._observer = new observer(function (mutations) {
                        $.each(mutations, self._syncA);
                        $.each(mutations, self._syncS);
                    });
                    this._observer.observe(this.$element[0], {
                        attributes: true,
                        childList: true,
                        subtree: false
                    });
                }
                else if (this.$element[0].addEventListener) {
                    this.$element[0].addEventListener('DOMAttrModified', self._syncA, false);
                    this.$element[0].addEventListener('DOMNodeInserted', self._syncS, false);
                    this.$element[0].addEventListener('DOMNodeRemoved', self._syncS, false);
                }
            };
            Select2.prototype._registerDataEvents = function () {
                var self = this;
                this.dataAdapter.on('*', function (name, params) {
                    self.trigger(name, params);
                });
            };
            Select2.prototype._registerSelectionEvents = function () {
                var self = this;
                var nonRelayEvents = ['toggle', 'focus'];
                this.selection.on('toggle', function () {
                    self.toggleDropdown();
                });
                this.selection.on('focus', function (params) {
                    self.focus(params);
                });
                this.selection.on('*', function (name, params) {
                    if ($.inArray(name, nonRelayEvents) !== -1) {
                        return;
                    }
                    self.trigger(name, params);
                });
            };
            Select2.prototype._registerDropdownEvents = function () {
                var self = this;
                this.dropdown.on('*', function (name, params) {
                    self.trigger(name, params);
                });
            };
            Select2.prototype._registerResultsEvents = function () {
                var self = this;
                this.results.on('*', function (name, params) {
                    self.trigger(name, params);
                });
            };
            Select2.prototype._registerEvents = function () {
                var self = this;
                this.on('open', function () {
                    self.$container.addClass('select2-container--open');
                });
                this.on('close', function () {
                    self.$container.removeClass('select2-container--open');
                });
                this.on('enable', function () {
                    self.$container.removeClass('select2-container--disabled');
                });
                this.on('disable', function () {
                    self.$container.addClass('select2-container--disabled');
                });
                this.on('blur', function () {
                    self.$container.removeClass('select2-container--focus');
                });
                this.on('query', function (params) {
                    if (!self.isOpen()) {
                        self.trigger('open', {});
                    }
                    this.dataAdapter.query(params, function (data) {
                        self.trigger('results:all', {
                            data: data,
                            query: params
                        });
                    });
                });
                this.on('query:append', function (params) {
                    this.dataAdapter.query(params, function (data) {
                        self.trigger('results:append', {
                            data: data,
                            query: params
                        });
                    });
                });
                this.on('keypress', function (evt) {
                    var key = evt.which;
                    if (self.isOpen()) {
                        if (key === KEYS.ESC || key === KEYS.TAB ||
                            (key === KEYS.UP && evt.altKey)) {
                            self.close();
                            evt.preventDefault();
                        }
                        else if (key === KEYS.ENTER) {
                            self.trigger('results:select', {});
                            evt.preventDefault();
                        }
                        else if ((key === KEYS.SPACE && evt.ctrlKey)) {
                            self.trigger('results:toggle', {});
                            evt.preventDefault();
                        }
                        else if (key === KEYS.UP) {
                            self.trigger('results:previous', {});
                            evt.preventDefault();
                        }
                        else if (key === KEYS.DOWN) {
                            self.trigger('results:next', {});
                            evt.preventDefault();
                        }
                    }
                    else {
                        if (key === KEYS.ENTER || key === KEYS.SPACE ||
                            (key === KEYS.DOWN && evt.altKey)) {
                            self.open();
                            evt.preventDefault();
                        }
                    }
                });
            };
            Select2.prototype._syncAttributes = function () {
                this.options.set('disabled', this.$element.prop('disabled'));
                if (this.options.get('disabled')) {
                    if (this.isOpen()) {
                        this.close();
                    }
                    this.trigger('disable', {});
                }
                else {
                    this.trigger('enable', {});
                }
            };
            Select2.prototype._syncSubtree = function (evt, mutations) {
                var changed = false;
                var self = this;
                // Ignore any mutation events raised for elements that aren't options or
                // optgroups. This handles the case when the select element is destroyed
                if (evt && evt.target && (evt.target.nodeName !== 'OPTION' && evt.target.nodeName !== 'OPTGROUP')) {
                    return;
                }
                if (!mutations) {
                    // If mutation events aren't supported, then we can only assume that the
                    // change affected the selections
                    changed = true;
                }
                else if (mutations.addedNodes && mutations.addedNodes.length > 0) {
                    for (var n = 0; n < mutations.addedNodes.length; n++) {
                        var node = mutations.addedNodes[n];
                        if (node.selected) {
                            changed = true;
                        }
                    }
                }
                else if (mutations.removedNodes && mutations.removedNodes.length > 0) {
                    changed = true;
                }
                // Only re-pull the data if we think there is a change
                if (changed) {
                    this.dataAdapter.current(function (currentData) {
                        self.trigger('selection:update', {
                            data: currentData
                        });
                    });
                }
            };
            /**
             * Override the trigger method to automatically trigger pre-events when
             * there are events that can be prevented.
             */
            Select2.prototype.trigger = function (name, args) {
                var actualTrigger = Select2.__super__.trigger;
                var preTriggerMap = {
                    'open': 'opening',
                    'close': 'closing',
                    'select': 'selecting',
                    'unselect': 'unselecting'
                };
                if (args === undefined) {
                    args = {};
                }
                if (name in preTriggerMap) {
                    var preTriggerName = preTriggerMap[name];
                    var preTriggerArgs = {
                        prevented: false,
                        name: name,
                        args: args
                    };
                    actualTrigger.call(this, preTriggerName, preTriggerArgs);
                    if (preTriggerArgs.prevented) {
                        args.prevented = true;
                        return;
                    }
                }
                actualTrigger.call(this, name, args);
            };
            Select2.prototype.toggleDropdown = function () {
                if (this.options.get('disabled')) {
                    return;
                }
                if (this.isOpen()) {
                    this.close();
                }
                else {
                    this.open();
                }
            };
            Select2.prototype.open = function () {
                if (this.isOpen()) {
                    return;
                }
                this.trigger('query', {});
            };
            Select2.prototype.close = function () {
                if (!this.isOpen()) {
                    return;
                }
                this.trigger('close', {});
            };
            Select2.prototype.isOpen = function () {
                return this.$container.hasClass('select2-container--open');
            };
            Select2.prototype.hasFocus = function () {
                return this.$container.hasClass('select2-container--focus');
            };
            Select2.prototype.focus = function (data) {
                // No need to re-trigger focus events if we are already focused
                if (this.hasFocus()) {
                    return;
                }
                this.$container.addClass('select2-container--focus');
                this.trigger('focus', {});
            };
            Select2.prototype.enable = function (args) {
                if (this.options.get('debug') && window.console && console.warn) {
                    console.warn('Select2: The `select2("enable")` method has been deprecated and will' +
                        ' be removed in later Select2 versions. Use $element.prop("disabled")' +
                        ' instead.');
                }
                if (args == null || args.length === 0) {
                    args = [true];
                }
                var disabled = !args[0];
                this.$element.prop('disabled', disabled);
            };
            Select2.prototype.data = function () {
                if (this.options.get('debug') &&
                    arguments.length > 0 && window.console && console.warn) {
                    console.warn('Select2: Data can no longer be set using `select2("data")`. You ' +
                        'should consider setting the value instead using `$element.val()`.');
                }
                var data = [];
                this.dataAdapter.current(function (currentData) {
                    data = currentData;
                });
                return data;
            };
            Select2.prototype.val = function (args) {
                if (this.options.get('debug') && window.console && console.warn) {
                    console.warn('Select2: The `select2("val")` method has been deprecated and will be' +
                        ' removed in later Select2 versions. Use $element.val() instead.');
                }
                if (args == null || args.length === 0) {
                    return this.$element.val();
                }
                var newVal = args[0];
                if ($.isArray(newVal)) {
                    newVal = $.map(newVal, function (obj) {
                        return obj.toString();
                    });
                }
                this.$element.val(newVal).trigger('change');
            };
            Select2.prototype.destroy = function () {
                this.$container.remove();
                if (this.$element[0].detachEvent) {
                    this.$element[0].detachEvent('onpropertychange', this._syncA);
                }
                if (this._observer != null) {
                    this._observer.disconnect();
                    this._observer = null;
                }
                else if (this.$element[0].removeEventListener) {
                    this.$element[0]
                        .removeEventListener('DOMAttrModified', this._syncA, false);
                    this.$element[0]
                        .removeEventListener('DOMNodeInserted', this._syncS, false);
                    this.$element[0]
                        .removeEventListener('DOMNodeRemoved', this._syncS, false);
                }
                this._syncA = null;
                this._syncS = null;
                this.$element.off('.select2');
                this.$element.attr('tabindex', this.$element.data('old-tabindex'));
                this.$element.removeClass('select2-hidden-accessible');
                this.$element.attr('aria-hidden', 'false');
                this.$element.removeData('select2');
                this.dataAdapter.destroy();
                this.selection.destroy();
                this.dropdown.destroy();
                this.results.destroy();
                this.dataAdapter = null;
                this.selection = null;
                this.dropdown = null;
                this.results = null;
            };
            Select2.prototype.render = function () {
                var $container = $('<span class="select2 select2-container">' +
                    '<span class="selection"></span>' +
                    '<span class="dropdown-wrapper" aria-hidden="true"></span>' +
                    '</span>');
                $container.attr('dir', this.options.get('dir'));
                this.$container = $container;
                this.$container.addClass('select2-container--' + this.options.get('theme'));
                $container.data('element', this.$element);
                return $container;
            };
            return Select2;
        });
        S2.define('jquery-mousewheel', [
            'jquery'
        ], function ($) {
            // Used to shim jQuery.mousewheel for non-full builds.
            return $;
        });
        S2.define('jquery.select2', [
            'jquery',
            'jquery-mousewheel',
            './select2/core',
            './select2/defaults'
        ], function ($, _, Select2, Defaults) {
            if ($.fn.select2 == null) {
                // All methods that should return the element
                var thisMethods = ['open', 'close', 'destroy'];
                $.fn.select2 = function (options) {
                    options = options || {};
                    if (typeof options === 'object') {
                        this.each(function () {
                            var instanceOptions = $.extend(true, {}, options);
                            var instance = new Select2($(this), instanceOptions);
                        });
                        return this;
                    }
                    else if (typeof options === 'string') {
                        var ret;
                        var args = Array.prototype.slice.call(arguments, 1);
                        this.each(function () {
                            var instance = $(this).data('select2');
                            if (instance == null && window.console && console.error) {
                                console.error('The select2(\'' + options + '\') method was called on an ' +
                                    'element that is not using Select2.');
                            }
                            ret = instance[options].apply(instance, args);
                        });
                        // Check if we should be returning `this`
                        if ($.inArray(options, thisMethods) > -1) {
                            return this;
                        }
                        return ret;
                    }
                    else {
                        throw new Error('Invalid arguments for Select2: ' + options);
                    }
                };
            }
            if ($.fn.select2.defaults == null) {
                $.fn.select2.defaults = Defaults;
            }
            return Select2;
        });
        // Return the AMD loader configuration so it can be used outside of this file
        return {
            define: S2.define,
            require: S2.require
        };
    }());
    // Autoload the jQuery bindings
    // We know that all of the modules exist above this, so we're safe
    var select2 = S2.require('jquery.select2');
    // Hold the AMD module references on the jQuery function that was just loaded
    // This allows Select2 to use the internal loader outside of this file, such
    // as in the language files.
    jQuery.fn.select2.amd = S2;
    // Return the Select2 instance for anyone who is importing it.
    return select2;
}));
//# sourceMappingURL=select2.js.map 
//# sourceMappingURL=select2.js.map 
//# sourceMappingURL=select2.js.map 
//# sourceMappingURL=select2.js.map 
//# sourceMappingURL=select2.js.map;
;/*! showdown 02-06-2017 */
(function () {
    /**
     * Created by Tivie on 13-07-2015.
     */

    function getDefaultOpts(simple) {
        'use strict';

        var defaultOptions = {
            omitExtraWLInCodeBlocks: {
                defaultValue: false,
                describe: 'Omit the default extra whiteline added to code blocks',
                type: 'boolean'
            },
            noHeaderId: {
                defaultValue: false,
                describe: 'Turn on/off generated header id',
                type: 'boolean'
            },
            prefixHeaderId: {
                defaultValue: false,
                describe: 'Specify a prefix to generated header ids',
                type: 'string'
            },
            ghCompatibleHeaderId: {
                defaultValue: false,
                describe: 'Generate header ids compatible with github style (spaces are replaced with dashes, a bunch of non alphanumeric chars are removed)',
                type: 'boolean'
            },
            headerLevelStart: {
                defaultValue: false,
                describe: 'The header blocks level start',
                type: 'integer'
            },
            parseImgDimensions: {
                defaultValue: false,
                describe: 'Turn on/off image dimension parsing',
                type: 'boolean'
            },
            simplifiedAutoLink: {
                defaultValue: false,
                describe: 'Turn on/off GFM autolink style',
                type: 'boolean'
            },
            excludeTrailingPunctuationFromURLs: {
                defaultValue: false,
                describe: 'Excludes trailing punctuation from links generated with autoLinking',
                type: 'boolean'
            },
            literalMidWordUnderscores: {
                defaultValue: false,
                describe: 'Parse midword underscores as literal underscores',
                type: 'boolean'
            },
            literalMidWordAsterisks: {
                defaultValue: false,
                describe: 'Parse midword asterisks as literal asterisks',
                type: 'boolean'
            },
            strikethrough: {
                defaultValue: false,
                describe: 'Turn on/off strikethrough support',
                type: 'boolean'
            },
            tables: {
                defaultValue: false,
                describe: 'Turn on/off tables support',
                type: 'boolean'
            },
            tablesHeaderId: {
                defaultValue: false,
                describe: 'Add an id to table headers',
                type: 'boolean'
            },
            ghCodeBlocks: {
                defaultValue: true,
                describe: 'Turn on/off GFM fenced code blocks support',
                type: 'boolean'
            },
            tasklists: {
                defaultValue: false,
                describe: 'Turn on/off GFM tasklist support',
                type: 'boolean'
            },
            smoothLivePreview: {
                defaultValue: false,
                describe: 'Prevents weird effects in live previews due to incomplete input',
                type: 'boolean'
            },
            smartIndentationFix: {
                defaultValue: false,
                description: 'Tries to smartly fix indentation in es6 strings',
                type: 'boolean'
            },
            disableForced4SpacesIndentedSublists: {
                defaultValue: false,
                description: 'Disables the requirement of indenting nested sublists by 4 spaces',
                type: 'boolean'
            },
            simpleLineBreaks: {
                defaultValue: false,
                description: 'Parses simple line breaks as <br> (GFM Style)',
                type: 'boolean'
            },
            requireSpaceBeforeHeadingText: {
                defaultValue: false,
                description: 'Makes adding a space between `#` and the header text mandatory (GFM Style)',
                type: 'boolean'
            },
            ghMentions: {
                defaultValue: false,
                description: 'Enables github @mentions',
                type: 'boolean'
            },
            ghMentionsLink: {
                defaultValue: 'https://github.com/{u}',
                description: 'Changes the link generated by @mentions. Only applies if ghMentions option is enabled.',
                type: 'string'
            },
            encodeEmails: {
                defaultValue: true,
                description: 'Encode e-mail addresses through the use of Character Entities, transforming ASCII e-mail addresses into its equivalent decimal entities',
                type: 'boolean'
            },
            openLinksInNewWindow: {
                defaultValue: false,
                description: 'Open all links in new windows',
                type: 'boolean'
            }
        };
        if (simple === false) {
            return JSON.parse(JSON.stringify(defaultOptions));
        }
        var ret = {};
        for (var opt in defaultOptions) {
            if (defaultOptions.hasOwnProperty(opt)) {
                ret[opt] = defaultOptions[opt].defaultValue;
            }
        }
        return ret;
    }

    function allOptionsOn() {
        'use strict';
        var options = getDefaultOpts(true),
            ret = {};
        for (var opt in options) {
            if (options.hasOwnProperty(opt)) {
                ret[opt] = true;
            }
        }
        return ret;
    }

    /**
     * Created by Tivie on 06-01-2015.
     */

    // Private properties
    var showdown = {},
        parsers = {},
        extensions = {},
        globalOptions = getDefaultOpts(true),
        setFlavor = 'vanilla',
        flavor = {
            github: {
                omitExtraWLInCodeBlocks: true,
                simplifiedAutoLink: true,
                excludeTrailingPunctuationFromURLs: true,
                literalMidWordUnderscores: true,
                strikethrough: true,
                tables: true,
                tablesHeaderId: true,
                ghCodeBlocks: true,
                tasklists: true,
                disableForced4SpacesIndentedSublists: true,
                simpleLineBreaks: true,
                requireSpaceBeforeHeadingText: true,
                ghCompatibleHeaderId: true,
                ghMentions: true
            },
            original: {
                noHeaderId: true,
                ghCodeBlocks: false
            },
            ghost: {
                omitExtraWLInCodeBlocks: true,
                parseImgDimensions: true,
                simplifiedAutoLink: true,
                excludeTrailingPunctuationFromURLs: true,
                literalMidWordUnderscores: true,
                strikethrough: true,
                tables: true,
                tablesHeaderId: true,
                ghCodeBlocks: true,
                tasklists: true,
                smoothLivePreview: true,
                simpleLineBreaks: true,
                requireSpaceBeforeHeadingText: true,
                ghMentions: false,
                encodeEmails: true
            },
            vanilla: getDefaultOpts(true),
            allOn: allOptionsOn()
        };

    /**
     * helper namespace
     * @type {{}}
     */
    showdown.helper = {};

    /**
     * TODO LEGACY SUPPORT CODE
     * @type {{}}
     */
    showdown.extensions = {};

    /**
     * Set a global option
     * @static
     * @param {string} key
     * @param {*} value
     * @returns {showdown}
     */
    showdown.setOption = function (key, value) {
        'use strict';
        globalOptions[key] = value;
        return this;
    };

    /**
     * Get a global option
     * @static
     * @param {string} key
     * @returns {*}
     */
    showdown.getOption = function (key) {
        'use strict';
        return globalOptions[key];
    };

    /**
     * Get the global options
     * @static
     * @returns {{}}
     */
    showdown.getOptions = function () {
        'use strict';
        return globalOptions;
    };

    /**
     * Reset global options to the default values
     * @static
     */
    showdown.resetOptions = function () {
        'use strict';
        globalOptions = getDefaultOpts(true);
    };

    /**
     * Set the flavor showdown should use as default
     * @param {string} name
     */
    showdown.setFlavor = function (name) {
        'use strict';
        if (!flavor.hasOwnProperty(name)) {
            throw Error(name + ' flavor was not found');
        }
        showdown.resetOptions();
        var preset = flavor[name];
        setFlavor = name;
        for (var option in preset) {
            if (preset.hasOwnProperty(option)) {
                globalOptions[option] = preset[option];
            }
        }
    };

    /**
     * Get the currently set flavor
     * @returns {string}
     */
    showdown.getFlavor = function () {
        'use strict';
        return setFlavor;
    };

    /**
     * Get the options of a specified flavor. Returns undefined if the flavor was not found
     * @param {string} name Name of the flavor
     * @returns {{}|undefined}
     */
    showdown.getFlavorOptions = function (name) {
        'use strict';
        if (flavor.hasOwnProperty(name)) {
            return flavor[name];
        }
    };

    /**
     * Get the default options
     * @static
     * @param {boolean} [simple=true]
     * @returns {{}}
     */
    showdown.getDefaultOptions = function (simple) {
        'use strict';
        return getDefaultOpts(simple);
    };

    /**
     * Get or set a subParser
     *
     * subParser(name)       - Get a registered subParser
     * subParser(name, func) - Register a subParser
     * @static
     * @param {string} name
     * @param {function} [func]
     * @returns {*}
     */
    showdown.subParser = function (name, func) {
        'use strict';
        if (showdown.helper.isString(name)) {
            if (typeof func !== 'undefined') {
                parsers[name] = func;
            } else {
                if (parsers.hasOwnProperty(name)) {
                    return parsers[name];
                } else {
                    throw Error('SubParser named ' + name + ' not registered!');
                }
            }
        }
    };

    /**
     * Gets or registers an extension
     * @static
     * @param {string} name
     * @param {object|function=} ext
     * @returns {*}
     */
    showdown.extension = function (name, ext) {
        'use strict';

        if (!showdown.helper.isString(name)) {
            throw Error('Extension \'name\' must be a string');
        }

        name = showdown.helper.stdExtName(name);

        // Getter
        if (showdown.helper.isUndefined(ext)) {
            if (!extensions.hasOwnProperty(name)) {
                throw Error('Extension named ' + name + ' is not registered!');
            }
            return extensions[name];

            // Setter
        } else {
            // Expand extension if it's wrapped in a function
            if (typeof ext === 'function') {
                ext = ext();
            }

            // Ensure extension is an array
            if (!showdown.helper.isArray(ext)) {
                ext = [ext];
            }

            var validExtension = validate(ext, name);

            if (validExtension.valid) {
                extensions[name] = ext;
            } else {
                throw Error(validExtension.error);
            }
        }
    };

    /**
     * Gets all extensions registered
     * @returns {{}}
     */
    showdown.getAllExtensions = function () {
        'use strict';
        return extensions;
    };

    /**
     * Remove an extension
     * @param {string} name
     */
    showdown.removeExtension = function (name) {
        'use strict';
        delete extensions[name];
    };

    /**
     * Removes all extensions
     */
    showdown.resetExtensions = function () {
        'use strict';
        extensions = {};
    };

    /**
     * Validate extension
     * @param {array} extension
     * @param {string} name
     * @returns {{valid: boolean, error: string}}
     */
    function validate(extension, name) {
        'use strict';

        var errMsg = (name) ? 'Error in ' + name + ' extension->' : 'Error in unnamed extension',
            ret = {
                valid: true,
                error: ''
            };

        if (!showdown.helper.isArray(extension)) {
            extension = [extension];
        }

        for (var i = 0; i < extension.length; ++i) {
            var baseMsg = errMsg + ' sub-extension ' + i + ': ',
                ext = extension[i];
            if (typeof ext !== 'object') {
                ret.valid = false;
                ret.error = baseMsg + 'must be an object, but ' + typeof ext + ' given';
                return ret;
            }

            if (!showdown.helper.isString(ext.type)) {
                ret.valid = false;
                ret.error = baseMsg + 'property "type" must be a string, but ' + typeof ext.type + ' given';
                return ret;
            }

            var type = ext.type = ext.type.toLowerCase();

            // normalize extension type
            if (type === 'language') {
                type = ext.type = 'lang';
            }

            if (type === 'html') {
                type = ext.type = 'output';
            }

            if (type !== 'lang' && type !== 'output' && type !== 'listener') {
                ret.valid = false;
                ret.error = baseMsg + 'type ' + type + ' is not recognized. Valid values: "lang/language", "output/html" or "listener"';
                return ret;
            }

            if (type === 'listener') {
                if (showdown.helper.isUndefined(ext.listeners)) {
                    ret.valid = false;
                    ret.error = baseMsg + '. Extensions of type "listener" must have a property called "listeners"';
                    return ret;
                }
            } else {
                if (showdown.helper.isUndefined(ext.filter) && showdown.helper.isUndefined(ext.regex)) {
                    ret.valid = false;
                    ret.error = baseMsg + type + ' extensions must define either a "regex" property or a "filter" method';
                    return ret;
                }
            }

            if (ext.listeners) {
                if (typeof ext.listeners !== 'object') {
                    ret.valid = false;
                    ret.error = baseMsg + '"listeners" property must be an object but ' + typeof ext.listeners + ' given';
                    return ret;
                }
                for (var ln in ext.listeners) {
                    if (ext.listeners.hasOwnProperty(ln)) {
                        if (typeof ext.listeners[ln] !== 'function') {
                            ret.valid = false;
                            ret.error = baseMsg + '"listeners" property must be an hash of [event name]: [callback]. listeners.' + ln +
                                ' must be a function but ' + typeof ext.listeners[ln] + ' given';
                            return ret;
                        }
                    }
                }
            }

            if (ext.filter) {
                if (typeof ext.filter !== 'function') {
                    ret.valid = false;
                    ret.error = baseMsg + '"filter" must be a function, but ' + typeof ext.filter + ' given';
                    return ret;
                }
            } else if (ext.regex) {
                if (showdown.helper.isString(ext.regex)) {
                    ext.regex = new RegExp(ext.regex, 'g');
                }
                if (!(ext.regex instanceof RegExp)) {
                    ret.valid = false;
                    ret.error = baseMsg + '"regex" property must either be a string or a RegExp object, but ' + typeof ext.regex + ' given';
                    return ret;
                }
                if (showdown.helper.isUndefined(ext.replace)) {
                    ret.valid = false;
                    ret.error = baseMsg + '"regex" extensions must implement a replace string or function';
                    return ret;
                }
            }
        }
        return ret;
    }

    /**
     * Validate extension
     * @param {object} ext
     * @returns {boolean}
     */
    showdown.validateExtension = function (ext) {
        'use strict';

        var validateExtension = validate(ext, null);
        if (!validateExtension.valid) {
            console.warn(validateExtension.error);
            return false;
        }
        return true;
    };

    /**
     * showdownjs helper functions
     */

    if (!showdown.hasOwnProperty('helper')) {
        showdown.helper = {};
    }

    /**
     * Check if var is string
     * @static
     * @param {string} a
     * @returns {boolean}
     */
    showdown.helper.isString = function (a) {
        'use strict';
        return (typeof a === 'string' || a instanceof String);
    };

    /**
     * Check if var is a function
     * @static
     * @param {*} a
     * @returns {boolean}
     */
    showdown.helper.isFunction = function (a) {
        'use strict';
        var getType = {};
        return a && getType.toString.call(a) === '[object Function]';
    };

    /**
     * isArray helper function
     * @static
     * @param {*} a
     * @returns {boolean}
     */
    showdown.helper.isArray = function (a) {
        'use strict';
        return a.constructor === Array;
    };

    /**
     * Check if value is undefined
     * @static
     * @param {*} value The value to check.
     * @returns {boolean} Returns `true` if `value` is `undefined`, else `false`.
     */
    showdown.helper.isUndefined = function (value) {
        'use strict';
        return typeof value === 'undefined';
    };

    /**
     * ForEach helper function
     * Iterates over Arrays and Objects (own properties only)
     * @static
     * @param {*} obj
     * @param {function} callback Accepts 3 params: 1. value, 2. key, 3. the original array/object
     */
    showdown.helper.forEach = function (obj, callback) {
        'use strict';
        // check if obj is defined
        if (showdown.helper.isUndefined(obj)) {
            throw new Error('obj param is required');
        }

        if (showdown.helper.isUndefined(callback)) {
            throw new Error('callback param is required');
        }

        if (!showdown.helper.isFunction(callback)) {
            throw new Error('callback param must be a function/closure');
        }

        if (typeof obj.forEach === 'function') {
            obj.forEach(callback);
        } else if (showdown.helper.isArray(obj)) {
            for (var i = 0; i < obj.length; i++) {
                callback(obj[i], i, obj);
            }
        } else if (typeof (obj) === 'object') {
            for (var prop in obj) {
                if (obj.hasOwnProperty(prop)) {
                    callback(obj[prop], prop, obj);
                }
            }
        } else {
            throw new Error('obj does not seem to be an array or an iterable object');
        }
    };

    /**
     * Standardidize extension name
     * @static
     * @param {string} s extension name
     * @returns {string}
     */
    showdown.helper.stdExtName = function (s) {
        'use strict';
        return s.replace(/[_?*+\/\\.^-]/g, '').replace(/\s/g, '').toLowerCase();
    };

    function escapeCharactersCallback(wholeMatch, m1) {
        'use strict';
        var charCodeToEscape = m1.charCodeAt(0);
        return '¨E' + charCodeToEscape + 'E';
    }

    /**
     * Callback used to escape characters when passing through String.replace
     * @static
     * @param {string} wholeMatch
     * @param {string} m1
     * @returns {string}
     */
    showdown.helper.escapeCharactersCallback = escapeCharactersCallback;

    /**
     * Escape characters in a string
     * @static
     * @param {string} text
     * @param {string} charsToEscape
     * @param {boolean} afterBackslash
     * @returns {XML|string|void|*}
     */
    showdown.helper.escapeCharacters = function (text, charsToEscape, afterBackslash) {
        'use strict';
        // First we have to escape the escape characters so that
        // we can build a character class out of them
        var regexString = '([' + charsToEscape.replace(/([\[\]\\])/g, '\\$1') + '])';

        if (afterBackslash) {
            regexString = '\\\\' + regexString;
        }

        var regex = new RegExp(regexString, 'g');
        text = text.replace(regex, escapeCharactersCallback);

        return text;
    };

    var rgxFindMatchPos = function (str, left, right, flags) {
        'use strict';
        var f = flags || '',
            g = f.indexOf('g') > -1,
            x = new RegExp(left + '|' + right, 'g' + f.replace(/g/g, '')),
            l = new RegExp(left, f.replace(/g/g, '')),
            pos = [],
            t, s, m, start, end;

        do {
            t = 0;
            while ((m = x.exec(str))) {
                if (l.test(m[0])) {
                    if (!(t++)) {
                        s = x.lastIndex;
                        start = s - m[0].length;
                    }
                } else if (t) {
                    if (!--t) {
                        end = m.index + m[0].length;
                        var obj = {
                            left: { start: start, end: s },
                            match: { start: s, end: m.index },
                            right: { start: m.index, end: end },
                            wholeMatch: { start: start, end: end }
                        };
                        pos.push(obj);
                        if (!g) {
                            return pos;
                        }
                    }
                }
            }
        } while (t && (x.lastIndex = s));

        return pos;
    };

    /**
     * matchRecursiveRegExp
     *
     * (c) 2007 Steven Levithan <stevenlevithan.com>
     * MIT License
     *
     * Accepts a string to search, a left and right format delimiter
     * as regex patterns, and optional regex flags. Returns an array
     * of matches, allowing nested instances of left/right delimiters.
     * Use the "g" flag to return all matches, otherwise only the
     * first is returned. Be careful to ensure that the left and
     * right format delimiters produce mutually exclusive matches.
     * Backreferences are not supported within the right delimiter
     * due to how it is internally combined with the left delimiter.
     * When matching strings whose format delimiters are unbalanced
     * to the left or right, the output is intentionally as a
     * conventional regex library with recursion support would
     * produce, e.g. "<<x>" and "<x>>" both produce ["x"] when using
     * "<" and ">" as the delimiters (both strings contain a single,
     * balanced instance of "<x>").
     *
     * examples:
     * matchRecursiveRegExp("test", "\\(", "\\)")
     * returns: []
     * matchRecursiveRegExp("<t<<e>><s>>t<>", "<", ">", "g")
     * returns: ["t<<e>><s>", ""]
     * matchRecursiveRegExp("<div id=\"x\">test</div>", "<div\\b[^>]*>", "</div>", "gi")
     * returns: ["test"]
     */
    showdown.helper.matchRecursiveRegExp = function (str, left, right, flags) {
        'use strict';

        var matchPos = rgxFindMatchPos(str, left, right, flags),
            results = [];

        for (var i = 0; i < matchPos.length; ++i) {
            results.push([
                str.slice(matchPos[i].wholeMatch.start, matchPos[i].wholeMatch.end),
                str.slice(matchPos[i].match.start, matchPos[i].match.end),
                str.slice(matchPos[i].left.start, matchPos[i].left.end),
                str.slice(matchPos[i].right.start, matchPos[i].right.end)
            ]);
        }
        return results;
    };

    /**
     *
     * @param {string} str
     * @param {string|function} replacement
     * @param {string} left
     * @param {string} right
     * @param {string} flags
     * @returns {string}
     */
    showdown.helper.replaceRecursiveRegExp = function (str, replacement, left, right, flags) {
        'use strict';

        if (!showdown.helper.isFunction(replacement)) {
            var repStr = replacement;
            replacement = function () {
                return repStr;
            };
        }

        var matchPos = rgxFindMatchPos(str, left, right, flags),
            finalStr = str,
            lng = matchPos.length;

        if (lng > 0) {
            var bits = [];
            if (matchPos[0].wholeMatch.start !== 0) {
                bits.push(str.slice(0, matchPos[0].wholeMatch.start));
            }
            for (var i = 0; i < lng; ++i) {
                bits.push(
                    replacement(
                        str.slice(matchPos[i].wholeMatch.start, matchPos[i].wholeMatch.end),
                        str.slice(matchPos[i].match.start, matchPos[i].match.end),
                        str.slice(matchPos[i].left.start, matchPos[i].left.end),
                        str.slice(matchPos[i].right.start, matchPos[i].right.end)
                    )
                );
                if (i < lng - 1) {
                    bits.push(str.slice(matchPos[i].wholeMatch.end, matchPos[i + 1].wholeMatch.start));
                }
            }
            if (matchPos[lng - 1].wholeMatch.end < str.length) {
                bits.push(str.slice(matchPos[lng - 1].wholeMatch.end));
            }
            finalStr = bits.join('');
        }
        return finalStr;
    };

    /**
     * Returns the index within the passed String object of the first occurrence of the specified regex,
     * starting the search at fromIndex. Returns -1 if the value is not found.
     *
     * @param {string} str string to search
     * @param {RegExp} regex Regular expression to search
     * @param {int} [fromIndex = 0] Index to start the search
     * @returns {Number}
     * @throws InvalidArgumentError
     */
    showdown.helper.regexIndexOf = function (str, regex, fromIndex) {
        'use strict';
        if (!showdown.helper.isString(str)) {
            throw 'InvalidArgumentError: first parameter of showdown.helper.regexIndexOf function must be a string';
        }
        if (regex instanceof RegExp === false) {
            throw 'InvalidArgumentError: second parameter of showdown.helper.regexIndexOf function must be an instance of RegExp';
        }
        var indexOf = str.substring(fromIndex || 0).search(regex);
        return (indexOf >= 0) ? (indexOf + (fromIndex || 0)) : indexOf;
    };

    /**
     * Splits the passed string object at the defined index, and returns an array composed of the two substrings
     * @param {string} str string to split
     * @param {int} index index to split string at
     * @returns {[string,string]}
     * @throws InvalidArgumentError
     */
    showdown.helper.splitAtIndex = function (str, index) {
        'use strict';
        if (!showdown.helper.isString(str)) {
            throw 'InvalidArgumentError: first parameter of showdown.helper.regexIndexOf function must be a string';
        }
        return [str.substring(0, index), str.substring(index)];
    };

    /**
     * Obfuscate an e-mail address through the use of Character Entities,
     * transforming ASCII characters into their equivalent decimal or hex entities.
     *
     * Since it has a random component, subsequent calls to this function produce different results
     *
     * @param {string} mail
     * @returns {string}
     */
    showdown.helper.encodeEmailAddress = function (mail) {
        'use strict';
        var encode = [
            function (ch) {
                return '&#' + ch.charCodeAt(0) + ';';
            },
            function (ch) {
                return '&#x' + ch.charCodeAt(0).toString(16) + ';';
            },
            function (ch) {
                return ch;
            }
        ];

        mail = mail.replace(/./g, function (ch) {
            if (ch === '@') {
                // this *must* be encoded. I insist.
                ch = encode[Math.floor(Math.random() * 2)](ch);
            } else {
                var r = Math.random();
                // roughly 10% raw, 45% hex, 45% dec
                ch = (
                    r > 0.9 ? encode[2](ch) : r > 0.45 ? encode[1](ch) : encode[0](ch)
                );
            }
            return ch;
        });

        return mail;
    };

    /**
     * POLYFILLS
     */
    // use this instead of builtin is undefined for IE8 compatibility
    if (typeof (console) === 'undefined') {
        console = {
            warn: function (msg) {
                'use strict';
                alert(msg);
            },
            log: function (msg) {
                'use strict';
                alert(msg);
            },
            error: function (msg) {
                'use strict';
                throw msg;
            }
        };
    }

    /**
     * Common regexes.
     * We declare some common regexes to improve performance
     */
    showdown.helper.regexes = {
        asteriskAndDash: /([*_])/g
    };

    /**
     * Created by Estevao on 31-05-2015.
     */

    /**
     * Showdown Converter class
     * @class
     * @param {object} [converterOptions]
     * @returns {Converter}
     */
    showdown.Converter = function (converterOptions) {
        'use strict';

        var
            /**
             * Options used by this converter
             * @private
             * @type {{}}
             */
            options = {},

            /**
             * Language extensions used by this converter
             * @private
             * @type {Array}
             */
            langExtensions = [],

            /**
             * Output modifiers extensions used by this converter
             * @private
             * @type {Array}
             */
            outputModifiers = [],

            /**
             * Event listeners
             * @private
             * @type {{}}
             */
            listeners = {},

            /**
             * The flavor set in this converter
             */
            setConvFlavor = setFlavor;

        _constructor();

        /**
         * Converter constructor
         * @private
         */
        function _constructor() {
            converterOptions = converterOptions || {};

            for (var gOpt in globalOptions) {
                if (globalOptions.hasOwnProperty(gOpt)) {
                    options[gOpt] = globalOptions[gOpt];
                }
            }

            // Merge options
            if (typeof converterOptions === 'object') {
                for (var opt in converterOptions) {
                    if (converterOptions.hasOwnProperty(opt)) {
                        options[opt] = converterOptions[opt];
                    }
                }
            } else {
                throw Error('Converter expects the passed parameter to be an object, but ' + typeof converterOptions +
                    ' was passed instead.');
            }

            if (options.extensions) {
                showdown.helper.forEach(options.extensions, _parseExtension);
            }
        }

        /**
         * Parse extension
         * @param {*} ext
         * @param {string} [name='']
         * @private
         */
        function _parseExtension(ext, name) {

            name = name || null;
            // If it's a string, the extension was previously loaded
            if (showdown.helper.isString(ext)) {
                ext = showdown.helper.stdExtName(ext);
                name = ext;

                // LEGACY_SUPPORT CODE
                if (showdown.extensions[ext]) {
                    console.warn('DEPRECATION WARNING: ' + ext + ' is an old extension that uses a deprecated loading method.' +
                        'Please inform the developer that the extension should be updated!');
                    legacyExtensionLoading(showdown.extensions[ext], ext);
                    return;
                    // END LEGACY SUPPORT CODE

                } else if (!showdown.helper.isUndefined(extensions[ext])) {
                    ext = extensions[ext];

                } else {
                    throw Error('Extension "' + ext + '" could not be loaded. It was either not found or is not a valid extension.');
                }
            }

            if (typeof ext === 'function') {
                ext = ext();
            }

            if (!showdown.helper.isArray(ext)) {
                ext = [ext];
            }

            var validExt = validate(ext, name);
            if (!validExt.valid) {
                throw Error(validExt.error);
            }

            for (var i = 0; i < ext.length; ++i) {
                switch (ext[i].type) {

                    case 'lang':
                        langExtensions.push(ext[i]);
                        break;

                    case 'output':
                        outputModifiers.push(ext[i]);
                        break;
                }
                if (ext[i].hasOwnProperty('listeners')) {
                    for (var ln in ext[i].listeners) {
                        if (ext[i].listeners.hasOwnProperty(ln)) {
                            listen(ln, ext[i].listeners[ln]);
                        }
                    }
                }
            }

        }

        /**
         * LEGACY_SUPPORT
         * @param {*} ext
         * @param {string} name
         */
        function legacyExtensionLoading(ext, name) {
            if (typeof ext === 'function') {
                ext = ext(new showdown.Converter());
            }
            if (!showdown.helper.isArray(ext)) {
                ext = [ext];
            }
            var valid = validate(ext, name);

            if (!valid.valid) {
                throw Error(valid.error);
            }

            for (var i = 0; i < ext.length; ++i) {
                switch (ext[i].type) {
                    case 'lang':
                        langExtensions.push(ext[i]);
                        break;
                    case 'output':
                        outputModifiers.push(ext[i]);
                        break;
                    default:// should never reach here
                        throw Error('Extension loader error: Type unrecognized!!!');
                }
            }
        }

        /**
         * Listen to an event
         * @param {string} name
         * @param {function} callback
         */
        function listen(name, callback) {
            if (!showdown.helper.isString(name)) {
                throw Error('Invalid argument in converter.listen() method: name must be a string, but ' + typeof name + ' given');
            }

            if (typeof callback !== 'function') {
                throw Error('Invalid argument in converter.listen() method: callback must be a function, but ' + typeof callback + ' given');
            }

            if (!listeners.hasOwnProperty(name)) {
                listeners[name] = [];
            }
            listeners[name].push(callback);
        }

        function rTrimInputText(text) {
            var rsp = text.match(/^\s*/)[0].length,
                rgx = new RegExp('^\\s{0,' + rsp + '}', 'gm');
            return text.replace(rgx, '');
        }

        /**
         * Dispatch an event
         * @private
         * @param {string} evtName Event name
         * @param {string} text Text
         * @param {{}} options Converter Options
         * @param {{}} globals
         * @returns {string}
         */
        this._dispatch = function dispatch(evtName, text, options, globals) {
            if (listeners.hasOwnProperty(evtName)) {
                for (var ei = 0; ei < listeners[evtName].length; ++ei) {
                    var nText = listeners[evtName][ei](evtName, text, this, options, globals);
                    if (nText && typeof nText !== 'undefined') {
                        text = nText;
                    }
                }
            }
            return text;
        };

        /**
         * Listen to an event
         * @param {string} name
         * @param {function} callback
         * @returns {showdown.Converter}
         */
        this.listen = function (name, callback) {
            listen(name, callback);
            return this;
        };

        /**
         * Converts a markdown string into HTML
         * @param {string} text
         * @returns {*}
         */
        this.makeHtml = function (text) {
            //check if text is not falsy
            if (!text) {
                return text;
            }

            var globals = {
                gHtmlBlocks: [],
                gHtmlMdBlocks: [],
                gHtmlSpans: [],
                gUrls: {},
                gTitles: {},
                gDimensions: {},
                gListLevel: 0,
                hashLinkCounts: {},
                langExtensions: langExtensions,
                outputModifiers: outputModifiers,
                converter: this,
                ghCodeBlocks: []
            };

            // This lets us use ¨ trema as an escape char to avoid md5 hashes
            // The choice of character is arbitrary; anything that isn't
            // magic in Markdown will work.
            text = text.replace(/¨/g, '¨T');

            // Replace $ with ¨D
            // RegExp interprets $ as a special character
            // when it's in a replacement string
            text = text.replace(/\$/g, '¨D');

            // Standardize line endings
            text = text.replace(/\r\n/g, '\n'); // DOS to Unix
            text = text.replace(/\r/g, '\n'); // Mac to Unix

            // Stardardize line spaces (nbsp causes trouble in older browsers and some regex flavors)
            text = text.replace(/\u00A0/g, ' ');

            if (options.smartIndentationFix) {
                text = rTrimInputText(text);
            }

            // Make sure text begins and ends with a couple of newlines:
            text = '\n\n' + text + '\n\n';

            // detab
            text = showdown.subParser('detab')(text, options, globals);

            /**
             * Strip any lines consisting only of spaces and tabs.
             * This makes subsequent regexs easier to write, because we can
             * match consecutive blank lines with /\n+/ instead of something
             * contorted like /[ \t]*\n+/
             */
            text = text.replace(/^[ \t]+$/mg, '');

            //run languageExtensions
            showdown.helper.forEach(langExtensions, function (ext) {
                text = showdown.subParser('runExtension')(ext, text, options, globals);
            });

            // run the sub parsers
            text = showdown.subParser('hashPreCodeTags')(text, options, globals);
            text = showdown.subParser('githubCodeBlocks')(text, options, globals);
            text = showdown.subParser('hashHTMLBlocks')(text, options, globals);
            text = showdown.subParser('hashCodeTags')(text, options, globals);
            text = showdown.subParser('stripLinkDefinitions')(text, options, globals);
            text = showdown.subParser('blockGamut')(text, options, globals);
            text = showdown.subParser('unhashHTMLSpans')(text, options, globals);
            text = showdown.subParser('unescapeSpecialChars')(text, options, globals);

            // attacklab: Restore dollar signs
            text = text.replace(/¨D/g, '$$');

            // attacklab: Restore tremas
            text = text.replace(/¨T/g, '¨');

            // Run output modifiers
            showdown.helper.forEach(outputModifiers, function (ext) {
                text = showdown.subParser('runExtension')(ext, text, options, globals);
            });

            return text;
        };

        /**
         * Set an option of this Converter instance
         * @param {string} key
         * @param {*} value
         */
        this.setOption = function (key, value) {
            options[key] = value;
        };

        /**
         * Get the option of this Converter instance
         * @param {string} key
         * @returns {*}
         */
        this.getOption = function (key) {
            return options[key];
        };

        /**
         * Get the options of this Converter instance
         * @returns {{}}
         */
        this.getOptions = function () {
            return options;
        };

        /**
         * Add extension to THIS converter
         * @param {{}} extension
         * @param {string} [name=null]
         */
        this.addExtension = function (extension, name) {
            name = name || null;
            _parseExtension(extension, name);
        };

        /**
         * Use a global registered extension with THIS converter
         * @param {string} extensionName Name of the previously registered extension
         */
        this.useExtension = function (extensionName) {
            _parseExtension(extensionName);
        };

        /**
         * Set the flavor THIS converter should use
         * @param {string} name
         */
        this.setFlavor = function (name) {
            if (!flavor.hasOwnProperty(name)) {
                throw Error(name + ' flavor was not found');
            }
            var preset = flavor[name];
            setConvFlavor = name;
            for (var option in preset) {
                if (preset.hasOwnProperty(option)) {
                    options[option] = preset[option];
                }
            }
        };

        /**
         * Get the currently set flavor of this converter
         * @returns {string}
         */
        this.getFlavor = function () {
            return setConvFlavor;
        };

        /**
         * Remove an extension from THIS converter.
         * Note: This is a costly operation. It's better to initialize a new converter
         * and specify the extensions you wish to use
         * @param {Array} extension
         */
        this.removeExtension = function (extension) {
            if (!showdown.helper.isArray(extension)) {
                extension = [extension];
            }
            for (var a = 0; a < extension.length; ++a) {
                var ext = extension[a];
                for (var i = 0; i < langExtensions.length; ++i) {
                    if (langExtensions[i] === ext) {
                        langExtensions[i].splice(i, 1);
                    }
                }
                for (var ii = 0; ii < outputModifiers.length; ++i) {
                    if (outputModifiers[ii] === ext) {
                        outputModifiers[ii].splice(i, 1);
                    }
                }
            }
        };

        /**
         * Get all extension of THIS converter
         * @returns {{language: Array, output: Array}}
         */
        this.getAllExtensions = function () {
            return {
                language: langExtensions,
                output: outputModifiers
            };
        };
    };

    /**
     * Turn Markdown link shortcuts into XHTML <a> tags.
     */
    showdown.subParser('anchors', function (text, options, globals) {
        'use strict';

        text = globals.converter._dispatch('anchors.before', text, options, globals);

        var writeAnchorTag = function (wholeMatch, linkText, linkId, url, m5, m6, title) {
            if (showdown.helper.isUndefined(title)) {
                title = '';
            }
            linkId = linkId.toLowerCase();

            // Special case for explicit empty url
            if (wholeMatch.search(/\(<?\s*>? ?(['"].*['"])?\)$/m) > -1) {
                url = '';
            } else if (!url) {
                if (!linkId) {
                    // lower-case and turn embedded newlines into spaces
                    linkId = linkText.toLowerCase().replace(/ ?\n/g, ' ');
                }
                url = '#' + linkId;

                if (!showdown.helper.isUndefined(globals.gUrls[linkId])) {
                    url = globals.gUrls[linkId];
                    if (!showdown.helper.isUndefined(globals.gTitles[linkId])) {
                        title = globals.gTitles[linkId];
                    }
                } else {
                    return wholeMatch;
                }
            }

            //url = showdown.helper.escapeCharacters(url, '*_', false); // replaced line to improve performance
            url = url.replace(showdown.helper.regexes.asteriskAndDash, showdown.helper.escapeCharactersCallback);

            var result = '<a href="' + url + '"';

            if (title !== '' && title !== null) {
                title = title.replace(/"/g, '&quot;');
                //title = showdown.helper.escapeCharacters(title, '*_', false); // replaced line to improve performance
                title = title.replace(showdown.helper.regexes.asteriskAndDash, showdown.helper.escapeCharactersCallback);
                result += ' title="' + title + '"';
            }

            if (options.openLinksInNewWindow) {
                // escaped _
                result += ' target="¨E95Eblank"';
            }

            result += '>' + linkText + '</a>';

            return result;
        };

        // First, handle reference-style links: [link text] [id]
        text = text.replace(/\[((?:\[[^\]]*]|[^\[\]])*)] ?(?:\n *)?\[(.*?)]()()()()/g, writeAnchorTag);

        // Next, inline-style links: [link text](url "optional title")
        // cases with crazy urls like ./image/cat1).png
        text = text.replace(/\[((?:\[[^\]]*]|[^\[\]])*)]()[ \t]*\([ \t]?<([^>]*)>(?:[ \t]*((["'])([^"]*?)\5))?[ \t]?\)/g,
            writeAnchorTag);

        // normal cases
        text = text.replace(/\[((?:\[[^\]]*]|[^\[\]])*)]()[ \t]*\([ \t]?<?([\S]+?(?:\([\S]*?\)[\S]*?)?)>?(?:[ \t]*((["'])([^"]*?)\5))?[ \t]?\)/g,
            writeAnchorTag);

        // handle reference-style shortcuts: [link text]
        // These must come last in case you've also got [link test][1]
        // or [link test](/foo)
        text = text.replace(/\[([^\[\]]+)]()()()()()/g, writeAnchorTag);

        // Lastly handle GithubMentions if option is enabled
        if (options.ghMentions) {
            text = text.replace(/(^|\s)(\\)?(@([a-z\d\-]+))(?=[.!?;,[\]()]|\s|$)/gmi, function (wm, st, escape, mentions, username) {
                if (escape === '\\') {
                    return st + mentions;
                }

                //check if options.ghMentionsLink is a string
                if (!showdown.helper.isString(options.ghMentionsLink)) {
                    throw new Error('ghMentionsLink option must be a string');
                }
                var lnk = options.ghMentionsLink.replace(/\{u}/g, username);
                return st + '<a href="' + lnk + '">' + mentions + '</a>';
            });
        }

        text = globals.converter._dispatch('anchors.after', text, options, globals);
        return text;
    });

    // url allowed chars [a-z\d_.~:/?#[]@!$&'()*+,;=-]

    var simpleURLRegex = /\b(((https?|ftp|dict):\/\/|www\.)[^'">\s]+\.[^'">\s]+)()(?=\s|$)(?!["<>])/gi,
        simpleURLRegex2 = /\b(((https?|ftp|dict):\/\/|www\.)[^'">\s]+\.[^'">\s]+?)([.!?,()\[\]]?)(?=\s|$)(?!["<>])/gi,
        //simpleURLRegex3 = /\b(((https?|ftp):\/\/|www\.)[a-z\d.-]+\.[a-z\d_.~:/?#\[\]@!$&'()*+,;=-]+?)([.!?()]?)(?=\s|$)(?!["<>])/gi,
        delimUrlRegex = /<(((https?|ftp|dict):\/\/|www\.)[^'">\s]+)()>/gi,
        simpleMailRegex = /(^|\s)(?:mailto:)?([A-Za-z0-9!#$%&'*+-/=?^_`{|}~.]+@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)(?=$|\s)/gmi,
        delimMailRegex = /<()(?:mailto:)?([-.\w]+@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)>/gi,

        replaceLink = function (options) {
            'use strict';

            return function (wm, link, m2, m3, trailingPunctuation) {
                var lnkTxt = link,
                    append = '',
                    target = '';
                if (/^www\./i.test(link)) {
                    link = link.replace(/^www\./i, 'http://www.');
                }
                if (options.excludeTrailingPunctuationFromURLs && trailingPunctuation) {
                    append = trailingPunctuation;
                }
                if (options.openLinksInNewWindow) {
                    target = ' target="¨E95Eblank"';
                }
                return '<a href="' + link + '"' + target + '>' + lnkTxt + '</a>' + append;
            };
        },

        replaceMail = function (options, globals) {
            'use strict';
            return function (wholeMatch, b, mail) {
                var href = 'mailto:';
                b = b || '';
                mail = showdown.subParser('unescapeSpecialChars')(mail, options, globals);
                if (options.encodeEmails) {
                    href = showdown.helper.encodeEmailAddress(href + mail);
                    mail = showdown.helper.encodeEmailAddress(mail);
                } else {
                    href = href + mail;
                }
                return b + '<a href="' + href + '">' + mail + '</a>';
            };
        };

    showdown.subParser('autoLinks', function (text, options, globals) {
        'use strict';

        text = globals.converter._dispatch('autoLinks.before', text, options, globals);

        text = text.replace(delimUrlRegex, replaceLink(options));
        text = text.replace(delimMailRegex, replaceMail(options, globals));

        text = globals.converter._dispatch('autoLinks.after', text, options, globals);

        return text;
    });

    showdown.subParser('simplifiedAutoLinks', function (text, options, globals) {
        'use strict';

        if (!options.simplifiedAutoLink) {
            return text;
        }

        text = globals.converter._dispatch('simplifiedAutoLinks.before', text, options, globals);

        if (options.excludeTrailingPunctuationFromURLs) {
            text = text.replace(simpleURLRegex2, replaceLink(options));
        } else {
            text = text.replace(simpleURLRegex, replaceLink(options));
        }
        text = text.replace(simpleMailRegex, replaceMail(options, globals));

        text = globals.converter._dispatch('simplifiedAutoLinks.after', text, options, globals);

        return text;
    });

    /**
     * These are all the transformations that form block-level
     * tags like paragraphs, headers, and list items.
     */
    showdown.subParser('blockGamut', function (text, options, globals) {
        'use strict';

        text = globals.converter._dispatch('blockGamut.before', text, options, globals);

        // we parse blockquotes first so that we can have headings and hrs
        // inside blockquotes
        text = showdown.subParser('blockQuotes')(text, options, globals);
        text = showdown.subParser('headers')(text, options, globals);

        // Do Horizontal Rules:
        text = showdown.subParser('horizontalRule')(text, options, globals);

        text = showdown.subParser('lists')(text, options, globals);
        text = showdown.subParser('codeBlocks')(text, options, globals);
        text = showdown.subParser('tables')(text, options, globals);

        // We already ran _HashHTMLBlocks() before, in Markdown(), but that
        // was to escape raw HTML in the original Markdown source. This time,
        // we're escaping the markup we've just created, so that we don't wrap
        // <p> tags around block-level tags.
        text = showdown.subParser('hashHTMLBlocks')(text, options, globals);
        text = showdown.subParser('paragraphs')(text, options, globals);

        text = globals.converter._dispatch('blockGamut.after', text, options, globals);

        return text;
    });

    showdown.subParser('blockQuotes', function (text, options, globals) {
        'use strict';

        text = globals.converter._dispatch('blockQuotes.before', text, options, globals);

        text = text.replace(/((^ {0,3}>[ \t]?.+\n(.+\n)*\n*)+)/gm, function (wholeMatch, m1) {
            var bq = m1;

            // attacklab: hack around Konqueror 3.5.4 bug:
            // "----------bug".replace(/^-/g,"") == "bug"
            bq = bq.replace(/^[ \t]*>[ \t]?/gm, '¨0'); // trim one level of quoting

            // attacklab: clean up hack
            bq = bq.replace(/¨0/g, '');

            bq = bq.replace(/^[ \t]+$/gm, ''); // trim whitespace-only lines
            bq = showdown.subParser('githubCodeBlocks')(bq, options, globals);
            bq = showdown.subParser('blockGamut')(bq, options, globals); // recurse

            bq = bq.replace(/(^|\n)/g, '$1  ');
            // These leading spaces screw with <pre> content, so we need to fix that:
            bq = bq.replace(/(\s*<pre>[^\r]+?<\/pre>)/gm, function (wholeMatch, m1) {
                var pre = m1;
                // attacklab: hack around Konqueror 3.5.4 bug:
                pre = pre.replace(/^  /mg, '¨0');
                pre = pre.replace(/¨0/g, '');
                return pre;
            });

            return showdown.subParser('hashBlock')('<blockquote>\n' + bq + '\n</blockquote>', options, globals);
        });

        text = globals.converter._dispatch('blockQuotes.after', text, options, globals);
        return text;
    });

    /**
     * Process Markdown `<pre><code>` blocks.
     */
    showdown.subParser('codeBlocks', function (text, options, globals) {
        'use strict';

        text = globals.converter._dispatch('codeBlocks.before', text, options, globals);

        // sentinel workarounds for lack of \A and \Z, safari\khtml bug
        text += '¨0';

        var pattern = /(?:\n\n|^)((?:(?:[ ]{4}|\t).*\n+)+)(\n*[ ]{0,3}[^ \t\n]|(?=¨0))/g;
        text = text.replace(pattern, function (wholeMatch, m1, m2) {
            var codeblock = m1,
                nextChar = m2,
                end = '\n';

            codeblock = showdown.subParser('outdent')(codeblock, options, globals);
            codeblock = showdown.subParser('encodeCode')(codeblock, options, globals);
            codeblock = showdown.subParser('detab')(codeblock, options, globals);
            codeblock = codeblock.replace(/^\n+/g, ''); // trim leading newlines
            codeblock = codeblock.replace(/\n+$/g, ''); // trim trailing newlines

            if (options.omitExtraWLInCodeBlocks) {
                end = '';
            }

            codeblock = '<pre><code>' + codeblock + end + '</code></pre>';

            return showdown.subParser('hashBlock')(codeblock, options, globals) + nextChar;
        });

        // strip sentinel
        text = text.replace(/¨0/, '');

        text = globals.converter._dispatch('codeBlocks.after', text, options, globals);
        return text;
    });

    /**
     *
     *   *  Backtick quotes are used for <code></code> spans.
     *
     *   *  You can use multiple backticks as the delimiters if you want to
     *     include literal backticks in the code span. So, this input:
     *
     *         Just type ``foo `bar` baz`` at the prompt.
     *
     *       Will translate to:
     *
     *         <p>Just type <code>foo `bar` baz</code> at the prompt.</p>
     *
     *    There's no arbitrary limit to the number of backticks you
     *    can use as delimters. If you need three consecutive backticks
     *    in your code, use four for delimiters, etc.
     *
     *  *  You can use spaces to get literal backticks at the edges:
     *
     *         ... type `` `bar` `` ...
     *
     *       Turns to:
     *
     *         ... type <code>`bar`</code> ...
     */
    showdown.subParser('codeSpans', function (text, options, globals) {
        'use strict';

        text = globals.converter._dispatch('codeSpans.before', text, options, globals);

        if (typeof (text) === 'undefined') {
            text = '';
        }
        text = text.replace(/(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/gm,
            function (wholeMatch, m1, m2, m3) {
                var c = m3;
                c = c.replace(/^([ \t]*)/g, '');	// leading whitespace
                c = c.replace(/[ \t]*$/g, '');	// trailing whitespace
                c = showdown.subParser('encodeCode')(c, options, globals);
                return m1 + '<code>' + c + '</code>';
            }
        );

        text = globals.converter._dispatch('codeSpans.after', text, options, globals);
        return text;
    });

    /**
     * Convert all tabs to spaces
     */
    showdown.subParser('detab', function (text, options, globals) {
        'use strict';
        text = globals.converter._dispatch('detab.before', text, options, globals);

        // expand first n-1 tabs
        text = text.replace(/\t(?=\t)/g, '    '); // g_tab_width

        // replace the nth with two sentinels
        text = text.replace(/\t/g, '¨A¨B');

        // use the sentinel to anchor our regex so it doesn't explode
        text = text.replace(/¨B(.+?)¨A/g, function (wholeMatch, m1) {
            var leadingText = m1,
                numSpaces = 4 - leadingText.length % 4;  // g_tab_width

            // there *must* be a better way to do this:
            for (var i = 0; i < numSpaces; i++) {
                leadingText += ' ';
            }

            return leadingText;
        });

        // clean up sentinels
        text = text.replace(/¨A/g, '    ');  // g_tab_width
        text = text.replace(/¨B/g, '');

        text = globals.converter._dispatch('detab.after', text, options, globals);
        return text;
    });

    /**
     * Smart processing for ampersands and angle brackets that need to be encoded.
     */
    showdown.subParser('encodeAmpsAndAngles', function (text, options, globals) {
        'use strict';
        text = globals.converter._dispatch('encodeAmpsAndAngles.before', text, options, globals);

        // Ampersand-encoding based entirely on Nat Irons's Amputator MT plugin:
        // http://bumppo.net/projects/amputator/
        text = text.replace(/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/g, '&amp;');

        // Encode naked <'s
        text = text.replace(/<(?![a-z\/?$!])/gi, '&lt;');

        // Encode <
        text = text.replace(/</g, '&lt;');

        // Encode >
        text = text.replace(/>/g, '&gt;');

        text = globals.converter._dispatch('encodeAmpsAndAngles.after', text, options, globals);
        return text;
    });

    /**
     * Returns the string, with after processing the following backslash escape sequences.
     *
     * attacklab: The polite way to do this is with the new escapeCharacters() function:
     *
     *    text = escapeCharacters(text,"\\",true);
     *    text = escapeCharacters(text,"`*_{}[]()>#+-.!",true);
     *
     * ...but we're sidestepping its use of the (slow) RegExp constructor
     * as an optimization for Firefox.  This function gets called a LOT.
     */
    showdown.subParser('encodeBackslashEscapes', function (text, options, globals) {
        'use strict';
        text = globals.converter._dispatch('encodeBackslashEscapes.before', text, options, globals);

        text = text.replace(/\\(\\)/g, showdown.helper.escapeCharactersCallback);
        text = text.replace(/\\([`*_{}\[\]()>#+.!~=|-])/g, showdown.helper.escapeCharactersCallback);

        text = globals.converter._dispatch('encodeBackslashEscapes.after', text, options, globals);
        return text;
    });

    /**
     * Encode/escape certain characters inside Markdown code runs.
     * The point is that in code, these characters are literals,
     * and lose their special Markdown meanings.
     */
    showdown.subParser('encodeCode', function (text, options, globals) {
        'use strict';

        text = globals.converter._dispatch('encodeCode.before', text, options, globals);

        // Encode all ampersands; HTML entities are not
        // entities within a Markdown code span.
        text = text
            .replace(/&/g, '&amp;')
            // Do the angle bracket song and dance:
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;')
            // Now, escape characters that are magic in Markdown:
            .replace(/([*_{}\[\]\\=~-])/g, showdown.helper.escapeCharactersCallback);

        text = globals.converter._dispatch('encodeCode.after', text, options, globals);
        return text;
    });

    /**
     * Within tags -- meaning between < and > -- encode [\ ` * _ ~ =] so they
     * don't conflict with their use in Markdown for code, italics and strong.
     */
    showdown.subParser('escapeSpecialCharsWithinTagAttributes', function (text, options, globals) {
        'use strict';
        text = globals.converter._dispatch('escapeSpecialCharsWithinTagAttributes.before', text, options, globals);

        // Build a regex to find HTML tags and comments.  See Friedl's
        // "Mastering Regular Expressions", 2nd Ed., pp. 200-201.
        var regex = /(<[a-z\/!$]("[^"]*"|'[^']*'|[^'">])*>|<!(--.*?--\s*)+>)/gi;

        text = text.replace(regex, function (wholeMatch) {
            return wholeMatch
                .replace(/(.)<\/?code>(?=.)/g, '$1`')
                .replace(/([\\`*_~=|])/g, showdown.helper.escapeCharactersCallback);
        });

        text = globals.converter._dispatch('escapeSpecialCharsWithinTagAttributes.after', text, options, globals);
        return text;
    });

    /**
     * Handle github codeblocks prior to running HashHTML so that
     * HTML contained within the codeblock gets escaped properly
     * Example:
     * ```ruby
     *     def hello_world(x)
     *       puts "Hello, #{x}"
     *     end
     * ```
     */
    showdown.subParser('githubCodeBlocks', function (text, options, globals) {
        'use strict';

        // early exit if option is not enabled
        if (!options.ghCodeBlocks) {
            return text;
        }

        text = globals.converter._dispatch('githubCodeBlocks.before', text, options, globals);

        text += '¨0';

        text = text.replace(/(?:^|\n)```(.*)\n([\s\S]*?)\n```/g, function (wholeMatch, language, codeblock) {
            var end = (options.omitExtraWLInCodeBlocks) ? '' : '\n';

            // First parse the github code block
            codeblock = showdown.subParser('encodeCode')(codeblock, options, globals);
            codeblock = showdown.subParser('detab')(codeblock, options, globals);
            codeblock = codeblock.replace(/^\n+/g, ''); // trim leading newlines
            codeblock = codeblock.replace(/\n+$/g, ''); // trim trailing whitespace

            codeblock = '<pre><code' + (language ? ' class="' + language + ' language-' + language + '"' : '') + '>' + codeblock + end + '</code></pre>';

            codeblock = showdown.subParser('hashBlock')(codeblock, options, globals);

            // Since GHCodeblocks can be false positives, we need to
            // store the primitive text and the parsed text in a global var,
            // and then return a token
            return '\n\n¨G' + (globals.ghCodeBlocks.push({ text: wholeMatch, codeblock: codeblock }) - 1) + 'G\n\n';
        });

        // attacklab: strip sentinel
        text = text.replace(/¨0/, '');

        return globals.converter._dispatch('githubCodeBlocks.after', text, options, globals);
    });

    showdown.subParser('hashBlock', function (text, options, globals) {
        'use strict';
        text = globals.converter._dispatch('hashBlock.before', text, options, globals);
        text = text.replace(/(^\n+|\n+$)/g, '');
        text = '\n\n¨K' + (globals.gHtmlBlocks.push(text) - 1) + 'K\n\n';
        text = globals.converter._dispatch('hashBlock.after', text, options, globals);
        return text;
    });

    /**
     * Hash and escape <code> elements that should not be parsed as markdown
     */
    showdown.subParser('hashCodeTags', function (text, options, globals) {
        'use strict';
        text = globals.converter._dispatch('hashCodeTags.before', text, options, globals);

        var repFunc = function (wholeMatch, match, left, right) {
            var codeblock = left + showdown.subParser('encodeCode')(match, options, globals) + right;
            return '¨C' + (globals.gHtmlSpans.push(codeblock) - 1) + 'C';
        };

        // Hash naked <code>
        text = showdown.helper.replaceRecursiveRegExp(text, repFunc, '<code\\b[^>]*>', '</code>', 'gim');

        text = globals.converter._dispatch('hashCodeTags.after', text, options, globals);
        return text;
    });

    showdown.subParser('hashElement', function (text, options, globals) {
        'use strict';

        return function (wholeMatch, m1) {
            var blockText = m1;

            // Undo double lines
            blockText = blockText.replace(/\n\n/g, '\n');
            blockText = blockText.replace(/^\n/, '');

            // strip trailing blank lines
            blockText = blockText.replace(/\n+$/g, '');

            // Replace the element text with a marker ("¨KxK" where x is its key)
            blockText = '\n\n¨K' + (globals.gHtmlBlocks.push(blockText) - 1) + 'K\n\n';

            return blockText;
        };
    });

    showdown.subParser('hashHTMLBlocks', function (text, options, globals) {
        'use strict';
        text = globals.converter._dispatch('hashHTMLBlocks.before', text, options, globals);

        var blockTags = [
            'pre',
            'div',
            'h1',
            'h2',
            'h3',
            'h4',
            'h5',
            'h6',
            'blockquote',
            'table',
            'dl',
            'ol',
            'ul',
            'script',
            'noscript',
            'form',
            'fieldset',
            'iframe',
            'math',
            'style',
            'section',
            'header',
            'footer',
            'nav',
            'article',
            'aside',
            'address',
            'audio',
            'canvas',
            'figure',
            'hgroup',
            'output',
            'video',
            'p'
        ],
            repFunc = function (wholeMatch, match, left, right) {
                var txt = wholeMatch;
                // check if this html element is marked as markdown
                // if so, it's contents should be parsed as markdown
                if (left.search(/\bmarkdown\b/) !== -1) {
                    txt = left + globals.converter.makeHtml(match) + right;
                }
                return '\n\n¨K' + (globals.gHtmlBlocks.push(txt) - 1) + 'K\n\n';
            };

        for (var i = 0; i < blockTags.length; ++i) {

            var opTagPos,
                rgx1 = new RegExp('^ {0,3}<' + blockTags[i] + '\\b[^>]*>', 'im'),
                patLeft = '<' + blockTags[i] + '\\b[^>]*>',
                patRight = '</' + blockTags[i] + '>';
            // 1. Look for the first position of the first opening HTML tag in the text
            while ((opTagPos = showdown.helper.regexIndexOf(text, rgx1)) !== -1) {
                //2. Split the text in that position
                var subTexts = showdown.helper.splitAtIndex(text, opTagPos),
                    //3. Match recursively
                    newSubText1 = showdown.helper.replaceRecursiveRegExp(subTexts[1], repFunc, patLeft, patRight, 'im');

                // prevent an infinite loop
                if (newSubText1 === subTexts[1]) {
                    break;
                }
                text = subTexts[0].concat(newSubText1);
            }
        }
        // HR SPECIAL CASE
        text = text.replace(/(\n {0,3}(<(hr)\b([^<>])*?\/?>)[ \t]*(?=\n{2,}))/g,
            showdown.subParser('hashElement')(text, options, globals));

        // Special case for standalone HTML comments
        text = showdown.helper.replaceRecursiveRegExp(text, function (txt) {
            return '\n\n¨K' + (globals.gHtmlBlocks.push(txt) - 1) + 'K\n\n';
        }, '^ {0,3}<!--', '-->', 'gm');

        // PHP and ASP-style processor instructions (<?...?> and <%...%>)
        text = text.replace(/(?:\n\n)( {0,3}(?:<([?%])[^\r]*?\2>)[ \t]*(?=\n{2,}))/g,
            showdown.subParser('hashElement')(text, options, globals));

        text = globals.converter._dispatch('hashHTMLBlocks.after', text, options, globals);
        return text;
    });

    /**
     * Hash span elements that should not be parsed as markdown
     */
    showdown.subParser('hashHTMLSpans', function (text, options, globals) {
        'use strict';
        text = globals.converter._dispatch('hashHTMLSpans.before', text, options, globals);

        function hashHTMLSpan(html) {
            return '¨C' + (globals.gHtmlSpans.push(html) - 1) + 'C';
        }

        // Hash Self Closing tags
        text = text.replace(/<[^>]+?\/>/gi, function (wm) {
            return hashHTMLSpan(wm);
        });

        // Hash tags without properties
        text = text.replace(/<([^>]+?)>[\s\S]*?<\/\1>/g, function (wm) {
            return hashHTMLSpan(wm);
        });

        // Hash tags with properties
        text = text.replace(/<([^>]+?)\s[^>]+?>[\s\S]*?<\/\1>/g, function (wm) {
            return hashHTMLSpan(wm);
        });

        // Hash self closing tags without />
        text = text.replace(/<[^>]+?>/gi, function (wm) {
            return hashHTMLSpan(wm);
        });

        /*showdown.helper.matchRecursiveRegExp(text, '<code\\b[^>]*>', '</code>', 'gi');*/

        text = globals.converter._dispatch('hashHTMLSpans.after', text, options, globals);
        return text;
    });

    /**
     * Unhash HTML spans
     */
    showdown.subParser('unhashHTMLSpans', function (text, options, globals) {
        'use strict';
        text = globals.converter._dispatch('unhashHTMLSpans.before', text, options, globals);

        for (var i = 0; i < globals.gHtmlSpans.length; ++i) {
            var repText = globals.gHtmlSpans[i],
                // limiter to prevent infinite loop (assume 10 as limit for recurse)
                limit = 0;

            while (/¨C(\d+)C/.test(repText)) {
                var num = RegExp.$1;
                repText = repText.replace('¨C' + num + 'C', globals.gHtmlSpans[num]);
                if (limit === 10) {
                    break;
                }
                ++limit;
            }
            text = text.replace('¨C' + i + 'C', repText);
        }

        text = globals.converter._dispatch('unhashHTMLSpans.after', text, options, globals);
        return text;
    });

    /**
     * Hash and escape <pre><code> elements that should not be parsed as markdown
     */
    showdown.subParser('hashPreCodeTags', function (text, options, globals) {
        'use strict';
        text = globals.converter._dispatch('hashPreCodeTags.before', text, options, globals);

        var repFunc = function (wholeMatch, match, left, right) {
            // encode html entities
            var codeblock = left + showdown.subParser('encodeCode')(match, options, globals) + right;
            return '\n\n¨G' + (globals.ghCodeBlocks.push({ text: wholeMatch, codeblock: codeblock }) - 1) + 'G\n\n';
        };

        // Hash <pre><code>
        text = showdown.helper.replaceRecursiveRegExp(text, repFunc, '^ {0,3}<pre\\b[^>]*>\\s*<code\\b[^>]*>', '^ {0,3}</code>\\s*</pre>', 'gim');

        text = globals.converter._dispatch('hashPreCodeTags.after', text, options, globals);
        return text;
    });

    showdown.subParser('headers', function (text, options, globals) {
        'use strict';

        text = globals.converter._dispatch('headers.before', text, options, globals);

        var headerLevelStart = (isNaN(parseInt(options.headerLevelStart))) ? 1 : parseInt(options.headerLevelStart),
            ghHeaderId = options.ghCompatibleHeaderId,

            // Set text-style headers:
            //	Header 1
            //	========
            //
            //	Header 2
            //	--------
            //
            setextRegexH1 = (options.smoothLivePreview) ? /^(.+)[ \t]*\n={2,}[ \t]*\n+/gm : /^(.+)[ \t]*\n=+[ \t]*\n+/gm,
            setextRegexH2 = (options.smoothLivePreview) ? /^(.+)[ \t]*\n-{2,}[ \t]*\n+/gm : /^(.+)[ \t]*\n-+[ \t]*\n+/gm;

        text = text.replace(setextRegexH1, function (wholeMatch, m1) {

            var spanGamut = showdown.subParser('spanGamut')(m1, options, globals),
                hID = (options.noHeaderId) ? '' : ' id="' + headerId(m1) + '"',
                hLevel = headerLevelStart,
                hashBlock = '<h' + hLevel + hID + '>' + spanGamut + '</h' + hLevel + '>';
            return showdown.subParser('hashBlock')(hashBlock, options, globals);
        });

        text = text.replace(setextRegexH2, function (matchFound, m1) {
            var spanGamut = showdown.subParser('spanGamut')(m1, options, globals),
                hID = (options.noHeaderId) ? '' : ' id="' + headerId(m1) + '"',
                hLevel = headerLevelStart + 1,
                hashBlock = '<h' + hLevel + hID + '>' + spanGamut + '</h' + hLevel + '>';
            return showdown.subParser('hashBlock')(hashBlock, options, globals);
        });

        // atx-style headers:
        //  # Header 1
        //  ## Header 2
        //  ## Header 2 with closing hashes ##
        //  ...
        //  ###### Header 6
        //
        var atxStyle = (options.requireSpaceBeforeHeadingText) ? /^(#{1,6})[ \t]+(.+?)[ \t]*#*\n+/gm : /^(#{1,6})[ \t]*(.+?)[ \t]*#*\n+/gm;

        text = text.replace(atxStyle, function (wholeMatch, m1, m2) {
            var hText = m2;
            if (options.customizedHeaderId) {
                hText = m2.replace(/\s?\{([^{]+?)}\s*$/, '');
            }

            var span = showdown.subParser('spanGamut')(hText, options, globals),
                hID = (options.noHeaderId) ? '' : ' id="' + headerId(m2) + '"',
                hLevel = headerLevelStart - 1 + m1.length,
                header = '<h' + hLevel + hID + '>' + span + '</h' + hLevel + '>';

            return showdown.subParser('hashBlock')(header, options, globals);
        });

        function headerId(m) {
            var title;

            // It is separate from other options to allow combining prefix and customized
            if (options.customizedHeaderId) {
                var match = m.match(/\{([^{]+?)}\s*$/);
                if (match && match[1]) {
                    m = match[1];
                }
            }

            // Prefix id to prevent causing inadvertent pre-existing style matches.
            if (showdown.helper.isString(options.prefixHeaderId)) {
                title = options.prefixHeaderId + m;
            } else if (options.prefixHeaderId === true) {
                title = 'section ' + m;
            } else {
                title = m;
            }

            if (ghHeaderId) {
                title = title
                    .replace(/ /g, '-')
                    // replace previously escaped chars (&, ¨ and $)
                    .replace(/&amp;/g, '')
                    .replace(/¨T/g, '')
                    .replace(/¨D/g, '')
                    // replace rest of the chars (&~$ are repeated as they might have been escaped)
                    // borrowed from github's redcarpet (some they should produce similar results)
                    .replace(/[&+$,\/:;=?@"#{}|^¨~\[\]`\\*)(%.!'<>]/g, '')
                    .toLowerCase();
            } else {
                title = title
                    .replace(/[^\w]/g, '')
                    .toLowerCase();
            }

            if (globals.hashLinkCounts[title]) {
                title = title + '-' + (globals.hashLinkCounts[title]++);
            } else {
                globals.hashLinkCounts[title] = 1;
            }
            return title;
        }

        text = globals.converter._dispatch('headers.after', text, options, globals);
        return text;
    });

    /**
     * Turn Markdown link shortcuts into XHTML <a> tags.
     */
    showdown.subParser('horizontalRule', function (text, options, globals) {
        'use strict';
        text = globals.converter._dispatch('horizontalRule.before', text, options, globals);

        var key = showdown.subParser('hashBlock')('<hr />', options, globals);
        text = text.replace(/^ {0,2}( ?-){3,}[ \t]*$/gm, key);
        text = text.replace(/^ {0,2}( ?\*){3,}[ \t]*$/gm, key);
        text = text.replace(/^ {0,2}( ?_){3,}[ \t]*$/gm, key);

        text = globals.converter._dispatch('horizontalRule.after', text, options, globals);
        return text;
    });

    /**
     * Turn Markdown image shortcuts into <img> tags.
     */
    showdown.subParser('images', function (text, options, globals) {
        'use strict';

        text = globals.converter._dispatch('images.before', text, options, globals);

        var inlineRegExp = /!\[([^\]]*?)][ \t]*()\([ \t]?<?([\S]+?(?:\([\S]*?\)[\S]*?)?)>?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(["'])([^"]*?)\6)?[ \t]?\)/g,
            crazyRegExp = /!\[([^\]]*?)][ \t]*()\([ \t]?<([^>]*)>(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(?:(["'])([^"]*?)\6))?[ \t]?\)/g,
            referenceRegExp = /!\[([^\]]*?)] ?(?:\n *)?\[(.*?)]()()()()()/g,
            refShortcutRegExp = /!\[([^\[\]]+)]()()()()()/g;

        function writeImageTag(wholeMatch, altText, linkId, url, width, height, m5, title) {

            var gUrls = globals.gUrls,
                gTitles = globals.gTitles,
                gDims = globals.gDimensions;

            linkId = linkId.toLowerCase();

            if (!title) {
                title = '';
            }
            // Special case for explicit empty url
            if (wholeMatch.search(/\(<?\s*>? ?(['"].*['"])?\)$/m) > -1) {
                url = '';

            } else if (url === '' || url === null) {
                if (linkId === '' || linkId === null) {
                    // lower-case and turn embedded newlines into spaces
                    linkId = altText.toLowerCase().replace(/ ?\n/g, ' ');
                }
                url = '#' + linkId;

                if (!showdown.helper.isUndefined(gUrls[linkId])) {
                    url = gUrls[linkId];
                    if (!showdown.helper.isUndefined(gTitles[linkId])) {
                        title = gTitles[linkId];
                    }
                    if (!showdown.helper.isUndefined(gDims[linkId])) {
                        width = gDims[linkId].width;
                        height = gDims[linkId].height;
                    }
                } else {
                    return wholeMatch;
                }
            }

            altText = altText
                .replace(/"/g, '&quot;')
                //altText = showdown.helper.escapeCharacters(altText, '*_', false);
                .replace(showdown.helper.regexes.asteriskAndDash, showdown.helper.escapeCharactersCallback);
            //url = showdown.helper.escapeCharacters(url, '*_', false);
            url = url.replace(showdown.helper.regexes.asteriskAndDash, showdown.helper.escapeCharactersCallback);
            var result = '<img src="' + url + '" alt="' + altText + '"';

            if (title) {
                title = title
                    .replace(/"/g, '&quot;')
                    //title = showdown.helper.escapeCharacters(title, '*_', false);
                    .replace(showdown.helper.regexes.asteriskAndDash, showdown.helper.escapeCharactersCallback);
                result += ' title="' + title + '"';
            }

            if (width && height) {
                width = (width === '*') ? 'auto' : width;
                height = (height === '*') ? 'auto' : height;

                result += ' width="' + width + '"';
                result += ' height="' + height + '"';
            }

            result += ' />';

            return result;
        }

        // First, handle reference-style labeled images: ![alt text][id]
        text = text.replace(referenceRegExp, writeImageTag);

        // Next, handle inline images:  ![alt text](url =<width>x<height> "optional title")
        // cases with crazy urls like ./image/cat1).png
        text = text.replace(crazyRegExp, writeImageTag);

        // normal cases
        text = text.replace(inlineRegExp, writeImageTag);

        // handle reference-style shortcuts: |[img text]
        text = text.replace(refShortcutRegExp, writeImageTag);

        text = globals.converter._dispatch('images.after', text, options, globals);
        return text;
    });

    showdown.subParser('italicsAndBold', function (text, options, globals) {
        'use strict';

        text = globals.converter._dispatch('italicsAndBold.before', text, options, globals);

        // it's faster to have 3 separate regexes for each case than have just one
        // because of backtracing, in some cases, it could lead to an exponential effect
        // called "catastrophic backtrace". Ominous!

        function parseInside(txt, left, right) {
            if (options.simplifiedAutoLink) {
                txt = showdown.subParser('simplifiedAutoLinks')(txt, options, globals);
            }
            return left + txt + right;
        }

        // Parse underscores
        if (options.literalMidWordUnderscores) {
            text = text.replace(/\b___(\S[\s\S]*)___\b/g, function (wm, txt) {
                return parseInside(txt, '<strong><em>', '</em></strong>');
            });
            text = text.replace(/\b__(\S[\s\S]*)__\b/g, function (wm, txt) {
                return parseInside(txt, '<strong>', '</strong>');
            });
            text = text.replace(/\b_(\S[\s\S]*?)_\b/g, function (wm, txt) {
                return parseInside(txt, '<em>', '</em>');
            });
        } else {
            text = text.replace(/___(\S[\s\S]*?)___/g, function (wm, m) {
                return (/\S$/.test(m)) ? parseInside(m, '<strong><em>', '</em></strong>') : wm;
            });
            text = text.replace(/__(\S[\s\S]*?)__/g, function (wm, m) {
                return (/\S$/.test(m)) ? parseInside(m, '<strong>', '</strong>') : wm;
            });
            text = text.replace(/_([^\s_][\s\S]*?)_/g, function (wm, m) {
                // !/^_[^_]/.test(m) - test if it doesn't start with __ (since it seems redundant, we removed it)
                return (/\S$/.test(m)) ? parseInside(m, '<em>', '</em>') : wm;
            });
        }

        // Now parse asterisks
        if (options.literalMidWordAsterisks) {
            text = text.trim().replace(/(?:^| +)\*{3}(\S[\s\S]*?)\*{3}(?: +|$)/g, function (wm, txt) {
                return parseInside(txt, ' <strong><em>', '</em></strong> ');
            });
            text = text.trim().replace(/(?:^| +)\*{2}(\S[\s\S]*?)\*{2}(?: +|$)/g, function (wm, txt) {
                return parseInside(txt, ' <strong>', '</strong> ');
            });
            text = text.trim().replace(/(?:^| +)\*{1}(\S[\s\S]*?)\*{1}(?: +|$)/g, function (wm, txt) {
                return parseInside(txt, ' <em>', '</em>' + (wm.slice(-1) === ' ' ? ' ' : ''));
            });
        } else {
            text = text.replace(/\*\*\*(\S[\s\S]*?)\*\*\*/g, function (wm, m) {
                return (/\S$/.test(m)) ? parseInside(m, '<strong><em>', '</em></strong>') : wm;
            });
            text = text.replace(/\*\*(\S[\s\S]*?)\*\*/g, function (wm, m) {
                return (/\S$/.test(m)) ? parseInside(m, '<strong>', '</strong>') : wm;
            });
            text = text.replace(/\*([^\s*][\s\S]*?)\*/g, function (wm, m) {
                // !/^\*[^*]/.test(m) - test if it doesn't start with ** (since it seems redundant, we removed it)
                return (/\S$/.test(m)) ? parseInside(m, '<em>', '</em>') : wm;
            });
        }


        text = globals.converter._dispatch('italicsAndBold.after', text, options, globals);
        return text;
    });

    /**
     * Form HTML ordered (numbered) and unordered (bulleted) lists.
     */
    showdown.subParser('lists', function (text, options, globals) {
        'use strict';
        text = globals.converter._dispatch('lists.before', text, options, globals);

        /**
         * Process the contents of a single ordered or unordered list, splitting it
         * into individual list items.
         * @param {string} listStr
         * @param {boolean} trimTrailing
         * @returns {string}
         */
        function processListItems(listStr, trimTrailing) {
            // The $g_list_level global keeps track of when we're inside a list.
            // Each time we enter a list, we increment it; when we leave a list,
            // we decrement. If it's zero, we're not in a list anymore.
            //
            // We do this because when we're not inside a list, we want to treat
            // something like this:
            //
            //    I recommend upgrading to version
            //    8. Oops, now this line is treated
            //    as a sub-list.
            //
            // As a single paragraph, despite the fact that the second line starts
            // with a digit-period-space sequence.
            //
            // Whereas when we're inside a list (or sub-list), that line will be
            // treated as the start of a sub-list. What a kludge, huh? This is
            // an aspect of Markdown's syntax that's hard to parse perfectly
            // without resorting to mind-reading. Perhaps the solution is to
            // change the syntax rules such that sub-lists must start with a
            // starting cardinal number; e.g. "1." or "a.".
            globals.gListLevel++;

            // trim trailing blank lines:
            listStr = listStr.replace(/\n{2,}$/, '\n');

            // attacklab: add sentinel to emulate \z
            listStr += '¨0';

            var rgx = /(\n)?(^ {0,3})([*+-]|\d+[.])[ \t]+((\[(x|X| )?])?[ \t]*[^\r]+?(\n{1,2}))(?=\n*(¨0| {0,3}([*+-]|\d+[.])[ \t]+))/gm,
                isParagraphed = (/\n[ \t]*\n(?!¨0)/.test(listStr));

            // Since version 1.5, nesting sublists requires 4 spaces (or 1 tab) indentation,
            // which is a syntax breaking change
            // activating this option reverts to old behavior
            if (options.disableForced4SpacesIndentedSublists) {
                rgx = /(\n)?(^ {0,3})([*+-]|\d+[.])[ \t]+((\[(x|X| )?])?[ \t]*[^\r]+?(\n{1,2}))(?=\n*(¨0|\2([*+-]|\d+[.])[ \t]+))/gm;
            }

            listStr = listStr.replace(rgx, function (wholeMatch, m1, m2, m3, m4, taskbtn, checked) {
                checked = (checked && checked.trim() !== '');

                var item = showdown.subParser('outdent')(m4, options, globals),
                    bulletStyle = '';

                // Support for github tasklists
                if (taskbtn && options.tasklists) {
                    bulletStyle = ' class="task-list-item" style="list-style-type: none;"';
                    item = item.replace(/^[ \t]*\[(x|X| )?]/m, function () {
                        var otp = '<input type="checkbox" disabled style="margin: 0px 0.35em 0.25em -1.6em; vertical-align: middle;"';
                        if (checked) {
                            otp += ' checked';
                        }
                        otp += '>';
                        return otp;
                    });
                }

                // ISSUE #312
                // This input: - - - a
                // causes trouble to the parser, since it interprets it as:
                // <ul><li><li><li>a</li></li></li></ul>
                // instead of:
                // <ul><li>- - a</li></ul>
                // So, to prevent it, we will put a marker (¨A)in the beginning of the line
                // Kind of hackish/monkey patching, but seems more effective than overcomplicating the list parser
                item = item.replace(/^([-*+]|\d\.)[ \t]+[\S\n ]*/g, function (wm2) {
                    return '¨A' + wm2;
                });

                // m1 - Leading line or
                // Has a double return (multi paragraph) or
                // Has sublist
                if (m1 || (item.search(/\n{2,}/) > -1)) {
                    item = showdown.subParser('githubCodeBlocks')(item, options, globals);
                    item = showdown.subParser('blockGamut')(item, options, globals);
                } else {
                    // Recursion for sub-lists:
                    item = showdown.subParser('lists')(item, options, globals);
                    item = item.replace(/\n$/, ''); // chomp(item)
                    item = showdown.subParser('hashHTMLBlocks')(item, options, globals);
                    // Colapse double linebreaks
                    item = item.replace(/\n\n+/g, '\n\n');
                    // replace double linebreaks with a placeholder
                    item = item.replace(/\n\n/g, '¨B');
                    if (isParagraphed) {
                        item = showdown.subParser('paragraphs')(item, options, globals);
                    } else {
                        item = showdown.subParser('spanGamut')(item, options, globals);
                    }
                    item = item.replace(/¨B/g, '\n\n');
                }

                // now we need to remove the marker (¨A)
                item = item.replace('¨A', '');
                // we can finally wrap the line in list item tags
                item = '<li' + bulletStyle + '>' + item + '</li>\n';

                return item;
            });

            // attacklab: strip sentinel
            listStr = listStr.replace(/¨0/g, '');

            globals.gListLevel--;

            if (trimTrailing) {
                listStr = listStr.replace(/\s+$/, '');
            }

            return listStr;
        }

        /**
         * Check and parse consecutive lists (better fix for issue #142)
         * @param {string} list
         * @param {string} listType
         * @param {boolean} trimTrailing
         * @returns {string}
         */
        function parseConsecutiveLists(list, listType, trimTrailing) {
            // check if we caught 2 or more consecutive lists by mistake
            // we use the counterRgx, meaning if listType is UL we look for OL and vice versa
            var olRgx = (options.disableForced4SpacesIndentedSublists) ? /^ ?\d+\.[ \t]/gm : /^ {0,3}\d+\.[ \t]/gm,
                ulRgx = (options.disableForced4SpacesIndentedSublists) ? /^ ?[*+-][ \t]/gm : /^ {0,3}[*+-][ \t]/gm,
                counterRxg = (listType === 'ul') ? olRgx : ulRgx,
                result = '';

            if (list.search(counterRxg) !== -1) {
                (function parseCL(txt) {
                    var pos = txt.search(counterRxg);
                    if (pos !== -1) {
                        // slice
                        result += '\n<' + listType + '>\n' + processListItems(txt.slice(0, pos), !!trimTrailing) + '</' + listType + '>\n';

                        // invert counterType and listType
                        listType = (listType === 'ul') ? 'ol' : 'ul';
                        counterRxg = (listType === 'ul') ? olRgx : ulRgx;

                        //recurse
                        parseCL(txt.slice(pos));
                    } else {
                        result += '\n<' + listType + '>\n' + processListItems(txt, !!trimTrailing) + '</' + listType + '>\n';
                    }
                })(list);
            } else {
                result = '\n<' + listType + '>\n' + processListItems(list, !!trimTrailing) + '</' + listType + '>\n';
            }

            return result;
        }

        // add sentinel to hack around khtml/safari bug:
        // http://bugs.webkit.org/show_bug.cgi?id=11231
        text += '¨0';

        if (globals.gListLevel) {
            text = text.replace(/^(( {0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(¨0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm,
                function (wholeMatch, list, m2) {
                    var listType = (m2.search(/[*+-]/g) > -1) ? 'ul' : 'ol';
                    return parseConsecutiveLists(list, listType, true);
                }
            );
        } else {
            text = text.replace(/(\n\n|^\n?)(( {0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(¨0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm,
                function (wholeMatch, m1, list, m3) {
                    var listType = (m3.search(/[*+-]/g) > -1) ? 'ul' : 'ol';
                    return parseConsecutiveLists(list, listType, false);
                }
            );
        }

        // strip sentinel
        text = text.replace(/¨0/, '');
        text = globals.converter._dispatch('lists.after', text, options, globals);
        return text;
    });

    /**
     * Remove one level of line-leading tabs or spaces
     */
    showdown.subParser('outdent', function (text, options, globals) {
        'use strict';
        text = globals.converter._dispatch('outdent.before', text, options, globals);

        // attacklab: hack around Konqueror 3.5.4 bug:
        // "----------bug".replace(/^-/g,"") == "bug"
        text = text.replace(/^(\t|[ ]{1,4})/gm, '¨0'); // attacklab: g_tab_width

        // attacklab: clean up hack
        text = text.replace(/¨0/g, '');

        text = globals.converter._dispatch('outdent.after', text, options, globals);
        return text;
    });

    /**
     *
     */
    showdown.subParser('paragraphs', function (text, options, globals) {
        'use strict';

        text = globals.converter._dispatch('paragraphs.before', text, options, globals);
        // Strip leading and trailing lines:
        text = text.replace(/^\n+/g, '');
        text = text.replace(/\n+$/g, '');

        var grafs = text.split(/\n{2,}/g),
            grafsOut = [],
            end = grafs.length; // Wrap <p> tags

        for (var i = 0; i < end; i++) {
            var str = grafs[i];
            // if this is an HTML marker, copy it
            if (str.search(/¨(K|G)(\d+)\1/g) >= 0) {
                grafsOut.push(str);

                // test for presence of characters to prevent empty lines being parsed
                // as paragraphs (resulting in undesired extra empty paragraphs)
            } else if (str.search(/\S/) >= 0) {
                str = showdown.subParser('spanGamut')(str, options, globals);
                str = str.replace(/^([ \t]*)/g, '<p>');
                str += '</p>';
                grafsOut.push(str);
            }
        }

        /** Unhashify HTML blocks */
        end = grafsOut.length;
        for (i = 0; i < end; i++) {
            var blockText = '',
                grafsOutIt = grafsOut[i],
                codeFlag = false;
            // if this is a marker for an html block...
            // use RegExp.test instead of string.search because of QML bug
            while (/¨(K|G)(\d+)\1/.test(grafsOutIt)) {
                var delim = RegExp.$1,
                    num = RegExp.$2;

                if (delim === 'K') {
                    blockText = globals.gHtmlBlocks[num];
                } else {
                    // we need to check if ghBlock is a false positive
                    if (codeFlag) {
                        // use encoded version of all text
                        blockText = showdown.subParser('encodeCode')(globals.ghCodeBlocks[num].text, options, globals);
                    } else {
                        blockText = globals.ghCodeBlocks[num].codeblock;
                    }
                }
                blockText = blockText.replace(/\$/g, '$$$$'); // Escape any dollar signs

                grafsOutIt = grafsOutIt.replace(/(\n\n)?¨(K|G)\d+\2(\n\n)?/, blockText);
                // Check if grafsOutIt is a pre->code
                if (/^<pre\b[^>]*>\s*<code\b[^>]*>/.test(grafsOutIt)) {
                    codeFlag = true;
                }
            }
            grafsOut[i] = grafsOutIt;
        }
        text = grafsOut.join('\n');
        // Strip leading and trailing lines:
        text = text.replace(/^\n+/g, '');
        text = text.replace(/\n+$/g, '');
        return globals.converter._dispatch('paragraphs.after', text, options, globals);
    });

    /**
     * Run extension
     */
    showdown.subParser('runExtension', function (ext, text, options, globals) {
        'use strict';

        if (ext.filter) {
            text = ext.filter(text, globals.converter, options);

        } else if (ext.regex) {
            // TODO remove this when old extension loading mechanism is deprecated
            var re = ext.regex;
            if (!(re instanceof RegExp)) {
                re = new RegExp(re, 'g');
            }
            text = text.replace(re, ext.replace);
        }

        return text;
    });

    /**
     * These are all the transformations that occur *within* block-level
     * tags like paragraphs, headers, and list items.
     */
    showdown.subParser('spanGamut', function (text, options, globals) {
        'use strict';

        text = globals.converter._dispatch('spanGamut.before', text, options, globals);
        text = showdown.subParser('codeSpans')(text, options, globals);
        text = showdown.subParser('escapeSpecialCharsWithinTagAttributes')(text, options, globals);
        text = showdown.subParser('encodeBackslashEscapes')(text, options, globals);

        // Process anchor and image tags. Images must come first,
        // because ![foo][f] looks like an anchor.
        text = showdown.subParser('images')(text, options, globals);
        text = showdown.subParser('anchors')(text, options, globals);

        // Make links out of things like `<http://example.com/>`
        // Must come after anchors, because you can use < and >
        // delimiters in inline links like [this](<url>).
        text = showdown.subParser('autoLinks')(text, options, globals);
        text = showdown.subParser('italicsAndBold')(text, options, globals);
        text = showdown.subParser('strikethrough')(text, options, globals);
        text = showdown.subParser('simplifiedAutoLinks')(text, options, globals);

        // we need to hash HTML tags inside spans
        text = showdown.subParser('hashHTMLSpans')(text, options, globals);

        // now we encode amps and angles
        text = showdown.subParser('encodeAmpsAndAngles')(text, options, globals);

        // Do hard breaks
        if (options.simpleLineBreaks) {
            // GFM style hard breaks
            text = text.replace(/\n/g, '<br />\n');
        } else {
            // Vanilla hard breaks
            text = text.replace(/  +\n/g, '<br />\n');
        }

        text = globals.converter._dispatch('spanGamut.after', text, options, globals);
        return text;
    });

    showdown.subParser('strikethrough', function (text, options, globals) {
        'use strict';

        function parseInside(txt) {
            if (options.simplifiedAutoLink) {
                txt = showdown.subParser('simplifiedAutoLinks')(txt, options, globals);
            }
            return '<del>' + txt + '</del>';
        }

        if (options.strikethrough) {
            text = globals.converter._dispatch('strikethrough.before', text, options, globals);
            text = text.replace(/(?:~){2}([\s\S]+?)(?:~){2}/g, function (wm, txt) { return parseInside(txt); });
            text = globals.converter._dispatch('strikethrough.after', text, options, globals);
        }

        return text;
    });

    /**
     * Strips link definitions from text, stores the URLs and titles in
     * hash references.
     * Link defs are in the form: ^[id]: url "optional title"
     */
    showdown.subParser('stripLinkDefinitions', function (text, options, globals) {
        'use strict';

        var regex = /^ {0,3}\[(.+)]:[ \t]*\n?[ \t]*<?([^>\s]+)>?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*\n?[ \t]*(?:(\n*)["|'(](.+?)["|')][ \t]*)?(?:\n+|(?=¨0))/gm;

        // attacklab: sentinel workarounds for lack of \A and \Z, safari\khtml bug
        text += '¨0';

        text = text.replace(regex, function (wholeMatch, linkId, url, width, height, blankLines, title) {
            linkId = linkId.toLowerCase();
            globals.gUrls[linkId] = showdown.subParser('encodeAmpsAndAngles')(url, options, globals);  // Link IDs are case-insensitive

            if (blankLines) {
                // Oops, found blank lines, so it's not a title.
                // Put back the parenthetical statement we stole.
                return blankLines + title;

            } else {
                if (title) {
                    globals.gTitles[linkId] = title.replace(/"|'/g, '&quot;');
                }
                if (options.parseImgDimensions && width && height) {
                    globals.gDimensions[linkId] = {
                        width: width,
                        height: height
                    };
                }
            }
            // Completely remove the definition from the text
            return '';
        });

        // attacklab: strip sentinel
        text = text.replace(/¨0/, '');

        return text;
    });

    showdown.subParser('tables', function (text, options, globals) {
        'use strict';

        if (!options.tables) {
            return text;
        }

        var tableRgx = /^ {0,3}\|?.+\|.+\n[ \t]{0,3}\|?[ \t]*:?[ \t]*(?:-|=){2,}[ \t]*:?[ \t]*\|[ \t]*:?[ \t]*(?:-|=){2,}[\s\S]+?(?:\n\n|¨0)/gm;

        function parseStyles(sLine) {
            if (/^:[ \t]*--*$/.test(sLine)) {
                return ' style="text-align:left;"';
            } else if (/^--*[ \t]*:[ \t]*$/.test(sLine)) {
                return ' style="text-align:right;"';
            } else if (/^:[ \t]*--*[ \t]*:$/.test(sLine)) {
                return ' style="text-align:center;"';
            } else {
                return '';
            }
        }

        function parseHeaders(header, style) {
            var id = '';
            header = header.trim();
            if (options.tableHeaderId) {
                id = ' id="' + header.replace(/ /g, '_').toLowerCase() + '"';
            }
            header = showdown.subParser('spanGamut')(header, options, globals);

            return '<th' + id + style + '>' + header + '</th>\n';
        }

        function parseCells(cell, style) {
            var subText = showdown.subParser('spanGamut')(cell, options, globals);
            return '<td' + style + '>' + subText + '</td>\n';
        }

        function buildTable(headers, cells) {
            var tb = '<table>\n<thead>\n<tr>\n',
                tblLgn = headers.length;

            for (var i = 0; i < tblLgn; ++i) {
                tb += headers[i];
            }
            tb += '</tr>\n</thead>\n<tbody>\n';

            for (i = 0; i < cells.length; ++i) {
                tb += '<tr>\n';
                for (var ii = 0; ii < tblLgn; ++ii) {
                    tb += cells[i][ii];
                }
                tb += '</tr>\n';
            }
            tb += '</tbody>\n</table>\n';
            return tb;
        }

        text = globals.converter._dispatch('tables.before', text, options, globals);

        // find escaped pipe characters
        text = text.replace(/\\(\|)/g, showdown.helper.escapeCharactersCallback);

        // parse tables
        text = text.replace(tableRgx, function (rawTable) {

            var i, tableLines = rawTable.split('\n');

            // strip wrong first and last column if wrapped tables are used
            for (i = 0; i < tableLines.length; ++i) {
                if (/^ {0,3}\|/.test(tableLines[i])) {
                    tableLines[i] = tableLines[i].replace(/^ {0,3}\|/, '');
                }
                if (/\|[ \t]*$/.test(tableLines[i])) {
                    tableLines[i] = tableLines[i].replace(/\|[ \t]*$/, '');
                }
            }

            var rawHeaders = tableLines[0].split('|').map(function (s) { return s.trim(); }),
                rawStyles = tableLines[1].split('|').map(function (s) { return s.trim(); }),
                rawCells = [],
                headers = [],
                styles = [],
                cells = [];

            tableLines.shift();
            tableLines.shift();

            for (i = 0; i < tableLines.length; ++i) {
                if (tableLines[i].trim() === '') {
                    continue;
                }
                rawCells.push(
                    tableLines[i]
                        .split('|')
                        .map(function (s) {
                            return s.trim();
                        })
                );
            }

            if (rawHeaders.length < rawStyles.length) {
                return rawTable;
            }

            for (i = 0; i < rawStyles.length; ++i) {
                styles.push(parseStyles(rawStyles[i]));
            }

            for (i = 0; i < rawHeaders.length; ++i) {
                if (showdown.helper.isUndefined(styles[i])) {
                    styles[i] = '';
                }
                headers.push(parseHeaders(rawHeaders[i], styles[i]));
            }

            for (i = 0; i < rawCells.length; ++i) {
                var row = [];
                for (var ii = 0; ii < headers.length; ++ii) {
                    if (showdown.helper.isUndefined(rawCells[i][ii])) {

                    }
                    row.push(parseCells(rawCells[i][ii], styles[ii]));
                }
                cells.push(row);
            }

            return buildTable(headers, cells);
        });

        text = globals.converter._dispatch('tables.after', text, options, globals);

        return text;
    });

    /**
     * Swap back in all the special characters we've hidden.
     */
    showdown.subParser('unescapeSpecialChars', function (text, options, globals) {
        'use strict';
        text = globals.converter._dispatch('unescapeSpecialChars.before', text, options, globals);

        text = text.replace(/¨E(\d+)E/g, function (wholeMatch, m1) {
            var charCodeToReplace = parseInt(m1);
            return String.fromCharCode(charCodeToReplace);
        });

        text = globals.converter._dispatch('unescapeSpecialChars.after', text, options, globals);
        return text;
    });

    var root = this;

    // CommonJS/nodeJS Loader
    if (typeof module !== 'undefined' && module.exports) {
        module.exports = showdown;

        // AMD Loader
    } else if (typeof define === 'function' && define.amd) {
        define(function () {
            'use strict';
            return showdown;
        });

        // Regular Browser loader
    } else {
        root.showdown = showdown;
    }
}).call(this);;
(function (root, factory) {
    if (typeof define === 'function' && define.amd) {
        define([], factory(root));
    }
    else if (typeof exports === 'object') {
        module.exports = factory(root);
    }
    else {
        root.smoothScroll = factory(root);
    }
})(typeof global !== 'undefined' ? global : this.window || this.global, function (root) {
    'use strict';
    //
    // Variables
    //
    var smoothScroll = {}; // Object for public APIs
    var supports = 'querySelector' in document && 'addEventListener' in root; // Feature test
    var settings, anchor, toggle, fixedHeader, headerHeight, eventTimeout, animationInterval;
    // Default settings
    var defaults = {
        selector: '[data-scroll]',
        selectorHeader: null,
        speed: 500,
        easing: 'easeInOutCubic',
        offset: 0,
        callback: function () { }
    };
    //
    // Methods
    //
    /**
     * Merge two or more objects. Returns a new object.
     * @private
     * @param {Boolean}  deep     If true, do a deep (or recursive) merge [optional]
     * @param {Object}   objects  The objects to merge together
     * @returns {Object}          Merged values of defaults and options
     */
    var extend = function () {
        // Variables
        var extended = {};
        var deep = false;
        var i = 0;
        var length = arguments.length;
        // Check if a deep merge
        if (Object.prototype.toString.call(arguments[0]) === '[object Boolean]') {
            deep = arguments[0];
            i++;
        }
        // Merge the object into the extended object
        var merge = function (obj) {
            for (var prop in obj) {
                if (Object.prototype.hasOwnProperty.call(obj, prop)) {
                    // If deep merge and property is an object, merge properties
                    if (deep && Object.prototype.toString.call(obj[prop]) === '[object Object]') {
                        extended[prop] = extend(true, extended[prop], obj[prop]);
                    }
                    else {
                        extended[prop] = obj[prop];
                    }
                }
            }
        };
        // Loop through each object and conduct a merge
        for (; i < length; i++) {
            var obj = arguments[i];
            merge(obj);
        }
        return extended;
    };
    /**
     * Get the height of an element.
     * @private
     * @param  {Node} elem The element to get the height of
     * @return {Number}    The element's height in pixels
     */
    var getHeight = function (elem) {
        return Math.max(elem.scrollHeight, elem.offsetHeight, elem.clientHeight);
    };
    /**
     * Get the closest matching element up the DOM tree.
     * @private
     * @param  {Element} elem     Starting element
     * @param  {String}  selector Selector to match against
     * @return {Boolean|Element}  Returns null if not match found
     */
    var getClosest = function (elem, selector) {
        // Element.matches() polyfill
        if (!Element.prototype.matches) {
            Element.prototype.matches =
                Element.prototype.matchesSelector ||
                    Element.prototype.mozMatchesSelector ||
                    Element.prototype.msMatchesSelector ||
                    Element.prototype.oMatchesSelector ||
                    Element.prototype.webkitMatchesSelector ||
                    function (s) {
                        var matches = (this.document || this.ownerDocument).querySelectorAll(s), i = matches.length;
                        while (--i >= 0 && matches.item(i) !== this) { }
                        return i > -1;
                    };
        }
        // Get closest match
        for (; elem && elem !== document; elem = elem.parentNode) {
            if (elem.matches(selector))
                return elem;
        }
        return null;
    };
    /**
     * Escape special characters for use with querySelector
     * @private
     * @param {String} id The anchor ID to escape
     * @author Mathias Bynens
     * @link https://github.com/mathiasbynens/CSS.escape
     */
    var escapeCharacters = function (id) {
        // Remove leading hash
        if (id.charAt(0) === '#') {
            id = id.substr(1);
        }
        var string = String(id);
        var length = string.length;
        var index = -1;
        var codeUnit;
        var result = '';
        var firstCodeUnit = string.charCodeAt(0);
        while (++index < length) {
            codeUnit = string.charCodeAt(index);
            // Note: there’s no need to special-case astral symbols, surrogate
            // pairs, or lone surrogates.
            // If the character is NULL (U+0000), then throw an
            // `InvalidCharacterError` exception and terminate these steps.
            if (codeUnit === 0x0000) {
                throw new InvalidCharacterError('Invalid character: the input contains U+0000.');
            }
            if (
            // If the character is in the range [\1-\1F] (U+0001 to U+001F) or is
            // U+007F, […]
            (codeUnit >= 0x0001 && codeUnit <= 0x001F) || codeUnit == 0x007F ||
                // If the character is the first character and is in the range [0-9]
                // (U+0030 to U+0039), […]
                (index === 0 && codeUnit >= 0x0030 && codeUnit <= 0x0039) ||
                // If the character is the second character and is in the range [0-9]
                // (U+0030 to U+0039) and the first character is a `-` (U+002D), […]
                (index === 1 &&
                    codeUnit >= 0x0030 && codeUnit <= 0x0039 &&
                    firstCodeUnit === 0x002D)) {
                // http://dev.w3.org/csswg/cssom/#escape-a-character-as-code-point
                result += '\\' + codeUnit.toString(16) + ' ';
                continue;
            }
            // If the character is not handled by one of the above rules and is
            // greater than or equal to U+0080, is `-` (U+002D) or `_` (U+005F), or
            // is in one of the ranges [0-9] (U+0030 to U+0039), [A-Z] (U+0041 to
            // U+005A), or [a-z] (U+0061 to U+007A), […]
            if (codeUnit >= 0x0080 ||
                codeUnit === 0x002D ||
                codeUnit === 0x005F ||
                codeUnit >= 0x0030 && codeUnit <= 0x0039 ||
                codeUnit >= 0x0041 && codeUnit <= 0x005A ||
                codeUnit >= 0x0061 && codeUnit <= 0x007A) {
                // the character itself
                result += string.charAt(index);
                continue;
            }
            // Otherwise, the escaped character.
            // http://dev.w3.org/csswg/cssom/#escape-a-character
            result += '\\' + string.charAt(index);
        }
        return '#' + result;
    };
    /**
     * Calculate the easing pattern
     * @private
     * @link https://gist.github.com/gre/1650294
     * @param {String} type Easing pattern
     * @param {Number} time Time animation should take to complete
     * @returns {Number}
     */
    var easingPattern = function (type, time) {
        var pattern;
        if (type === 'easeInQuad')
            pattern = time * time; // accelerating from zero velocity
        if (type === 'easeOutQuad')
            pattern = time * (2 - time); // decelerating to zero velocity
        if (type === 'easeInOutQuad')
            pattern = time < 0.5 ? 2 * time * time : -1 + (4 - 2 * time) * time; // acceleration until halfway, then deceleration
        if (type === 'easeInCubic')
            pattern = time * time * time; // accelerating from zero velocity
        if (type === 'easeOutCubic')
            pattern = (--time) * time * time + 1; // decelerating to zero velocity
        if (type === 'easeInOutCubic')
            pattern = time < 0.5 ? 4 * time * time * time : (time - 1) * (2 * time - 2) * (2 * time - 2) + 1; // acceleration until halfway, then deceleration
        if (type === 'easeInQuart')
            pattern = time * time * time * time; // accelerating from zero velocity
        if (type === 'easeOutQuart')
            pattern = 1 - (--time) * time * time * time; // decelerating to zero velocity
        if (type === 'easeInOutQuart')
            pattern = time < 0.5 ? 8 * time * time * time * time : 1 - 8 * (--time) * time * time * time; // acceleration until halfway, then deceleration
        if (type === 'easeInQuint')
            pattern = time * time * time * time * time; // accelerating from zero velocity
        if (type === 'easeOutQuint')
            pattern = 1 + (--time) * time * time * time * time; // decelerating to zero velocity
        if (type === 'easeInOutQuint')
            pattern = time < 0.5 ? 16 * time * time * time * time * time : 1 + 16 * (--time) * time * time * time * time; // acceleration until halfway, then deceleration
        return pattern || time; // no easing, no acceleration
    };
    /**
     * Calculate how far to scroll
     * @private
     * @param {Element} anchor The anchor element to scroll to
     * @param {Number} headerHeight Height of a fixed header, if any
     * @param {Number} offset Number of pixels by which to offset scroll
     * @returns {Number}
     */
    var getEndLocation = function (anchor, headerHeight, offset) {
        var location = 0;
        if (anchor.offsetParent) {
            do {
                location += anchor.offsetTop;
                anchor = anchor.offsetParent;
            } while (anchor);
        }
        location = Math.max(location - headerHeight - offset, 0);
        return Math.min(location, getDocumentHeight() - getViewportHeight());
    };
    /**
     * Determine the viewport's height
     * @private
     * @returns {Number}
     */
    var getViewportHeight = function () {
        return Math.max(document.documentElement.clientHeight, root.innerHeight || 0);
    };
    /**
     * Determine the document's height
     * @private
     * @returns {Number}
     */
    var getDocumentHeight = function () {
        return Math.max(document.body.scrollHeight, document.documentElement.scrollHeight, document.body.offsetHeight, document.documentElement.offsetHeight, document.body.clientHeight, document.documentElement.clientHeight);
    };
    /**
     * Convert data-options attribute into an object of key/value pairs
     * @private
     * @param {String} options Link-specific options as a data attribute string
     * @returns {Object}
     */
    var getDataOptions = function (options) {
        return !options || !(typeof JSON === 'object' && typeof JSON.parse === 'function') ? {} : JSON.parse(options);
    };
    /**
     * Get the height of the fixed header
     * @private
     * @param  {Node}   header The header
     * @return {Number}        The height of the header
     */
    var getHeaderHeight = function (header) {
        return !header ? 0 : (getHeight(header) + header.offsetTop);
    };
    /**
     * Bring the anchored element into focus
     * @private
     */
    var adjustFocus = function (anchor, endLocation, isNum) {
        // Don't run if scrolling to a number on the page
        if (isNum)
            return;
        // Otherwise, bring anchor element into focus
        anchor.focus();
        if (document.activeElement.id !== anchor.id) {
            anchor.setAttribute('tabindex', '-1');
            anchor.focus();
            anchor.style.outline = 'none';
        }
        root.scrollTo(0, endLocation);
    };
    /**
     * Start/stop the scrolling animation
     * @public
     * @param {Node|Number} anchor  The element or position to scroll to
     * @param {Element}     toggle  The element that toggled the scroll event
     * @param {Object}      options
     */
    smoothScroll.animateScroll = function (anchor, toggle, options) {
        // Options and overrides
        var overrides = getDataOptions(toggle ? toggle.getAttribute('data-options') : null);
        var animateSettings = extend(settings || defaults, options || {}, overrides); // Merge user options with defaults
        // Selectors and variables
        var isNum = Object.prototype.toString.call(anchor) === '[object Number]' ? true : false;
        var anchorElem = isNum || !anchor.tagName ? null : anchor;
        if (!isNum && !anchorElem)
            return;
        var startLocation = root.pageYOffset; // Current location on the page
        if (animateSettings.selectorHeader && !fixedHeader) {
            // Get the fixed header if not already set
            fixedHeader = document.querySelector(animateSettings.selectorHeader);
        }
        if (!headerHeight) {
            // Get the height of a fixed header if one exists and not already set
            headerHeight = getHeaderHeight(fixedHeader);
        }
        var endLocation = isNum ? anchor : getEndLocation(anchorElem, headerHeight, parseInt(animateSettings.offset, 10)); // Location to scroll to
        var distance = endLocation - startLocation; // distance to travel
        var documentHeight = getDocumentHeight();
        var timeLapsed = 0;
        var percentage, position;
        /**
         * Stop the scroll animation when it reaches its target (or the bottom/top of page)
         * @private
         * @param {Number} position Current position on the page
         * @param {Number} endLocation Scroll to location
         * @param {Number} animationInterval How much to scroll on this loop
         */
        var stopAnimateScroll = function (position, endLocation, animationInterval) {
            var currentLocation = root.pageYOffset;
            if (position == endLocation || currentLocation == endLocation || ((root.innerHeight + currentLocation) >= documentHeight)) {
                // Clear the animation timer
                clearInterval(animationInterval);
                // Bring the anchored element into focus
                adjustFocus(anchor, endLocation, isNum);
                // Run callback after animation complete
                animateSettings.callback(anchor, toggle);
            }
        };
        /**
         * Loop scrolling animation
         * @private
         */
        var loopAnimateScroll = function () {
            timeLapsed += 16;
            percentage = (timeLapsed / parseInt(animateSettings.speed, 10));
            percentage = (percentage > 1) ? 1 : percentage;
            position = startLocation + (distance * easingPattern(animateSettings.easing, percentage));
            root.scrollTo(0, Math.floor(position));
            stopAnimateScroll(position, endLocation, animationInterval);
        };
        /**
         * Set interval timer
         * @private
         */
        var startAnimateScroll = function () {
            clearInterval(animationInterval);
            animationInterval = setInterval(loopAnimateScroll, 16);
        };
        /**
         * Reset position to fix weird iOS bug
         * @link https://github.com/cferdinandi/smooth-scroll/issues/45
         */
        if (root.pageYOffset === 0) {
            root.scrollTo(0, 0);
        }
        // Start scrolling animation
        startAnimateScroll();
    };
    /**
     * Handle has change event
     * @private
     */
    var hashChangeHandler = function (event) {
        // Get hash from URL
        // var hash = decodeURIComponent( escapeCharacters( root.location.hash ) );
        var hash;
        try {
            hash = escapeCharacters(decodeURIComponent(root.location.hash));
        }
        catch (e) {
            hash = escapeCharacters(root.location.hash);
        }
        // Only run if there's an anchor element to scroll to
        if (!anchor)
            return;
        // Reset the anchor element's ID
        anchor.id = anchor.getAttribute('data-scroll-id');
        // Scroll to the anchored content
        smoothScroll.animateScroll(anchor, toggle);
        // Reset anchor and toggle
        anchor = null;
        toggle = null;
    };
    /**
     * If smooth scroll element clicked, animate scroll
     * @private
     */
    var clickHandler = function (event) {
        // Don't run if right-click or command/control + click
        if (event.button !== 0 || event.metaKey || event.ctrlKey)
            return;
        // Check if a smooth scroll link was clicked
        toggle = getClosest(event.target, settings.selector);
        if (!toggle || toggle.tagName.toLowerCase() !== 'a')
            return;
        // Only run if link is an anchor and points to the current page
        if (toggle.hostname !== root.location.hostname || toggle.pathname !== root.location.pathname || !/#/.test(toggle.href))
            return;
        // Get the sanitized hash
        // var hash = decodeURIComponent( escapeCharacters( toggle.hash ) );
        // console.log(hash);
        var hash;
        try {
            hash = escapeCharacters(decodeURIComponent(toggle.hash));
        }
        catch (e) {
            hash = escapeCharacters(toggle.hash);
        }
        // If the hash is empty, scroll to the top of the page
        if (hash === '#') {
            // Prevent default link behavior
            event.preventDefault();
            // Set the anchored element
            anchor = document.body;
            // Save or create the ID as a data attribute and remove it (prevents scroll jump)
            var id = anchor.id ? anchor.id : 'smooth-scroll-top';
            anchor.setAttribute('data-scroll-id', id);
            anchor.id = '';
            // If no hash change event will happen, fire manually
            // Otherwise, update the hash
            if (root.location.hash.substring(1) === id) {
                hashChangeHandler();
            }
            else {
                root.location.hash = id;
            }
            return;
        }
        // Get the anchored element
        anchor = document.querySelector(hash);
        // If anchored element exists, save the ID as a data attribute and remove it (prevents scroll jump)
        if (!anchor)
            return;
        anchor.setAttribute('data-scroll-id', anchor.id);
        anchor.id = '';
        // If no hash change event will happen, fire manually
        if (toggle.hash === root.location.hash) {
            event.preventDefault();
            hashChangeHandler();
        }
    };
    /**
     * On window scroll and resize, only run events at a rate of 15fps for better performance
     * @private
     * @param  {Function} eventTimeout Timeout function
     * @param  {Object} settings
     */
    var resizeThrottler = function (event) {
        if (!eventTimeout) {
            eventTimeout = setTimeout(function () {
                eventTimeout = null; // Reset timeout
                headerHeight = getHeaderHeight(fixedHeader); // Get the height of a fixed header if one exists
            }, 66);
        }
    };
    /**
     * Destroy the current initialization.
     * @public
     */
    smoothScroll.destroy = function () {
        // If plugin isn't already initialized, stop
        if (!settings)
            return;
        // Remove event listeners
        document.removeEventListener('click', clickHandler, false);
        root.removeEventListener('resize', resizeThrottler, false);
        // Reset varaibles
        settings = null;
        anchor = null;
        toggle = null;
        fixedHeader = null;
        headerHeight = null;
        eventTimeout = null;
        animationInterval = null;
    };
    /**
     * Initialize Smooth Scroll
     * @public
     * @param {Object} options User settings
     */
    smoothScroll.init = function (options) {
        // feature test
        if (!supports)
            return;
        // Destroy any existing initializations
        smoothScroll.destroy();
        // Selectors and variables
        settings = extend(defaults, options || {}); // Merge user options with defaults
        fixedHeader = settings.selectorHeader ? document.querySelector(settings.selectorHeader) : null; // Get the fixed header
        headerHeight = getHeaderHeight(fixedHeader);
        // When a toggle is clicked, run the click handler
        document.addEventListener('click', clickHandler, false);
        // Listen for hash changes
        root.addEventListener('hashchange', hashChangeHandler, false);
        // If window is resized and there's a fixed header, recalculate its size
        if (fixedHeader) {
            root.addEventListener('resize', resizeThrottler, false);
        }
    };
    //
    // Public APIs
    //
    return smoothScroll;
});
//# sourceMappingURL=smoothscroll.js.map 
//# sourceMappingURL=smoothscroll.js.map 
//# sourceMappingURL=smoothscroll.js.map 
//# sourceMappingURL=smoothscroll.js.map 
//# sourceMappingURL=smoothscroll.js.map 
//# sourceMappingURL=smoothscroll.js.map 
//# sourceMappingURL=smoothscroll.js.map;
//     Underscore.js 1.8.3
//     http://underscorejs.org
//     (c) 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
//     Underscore may be freely distributed under the MIT license.
(function () {
    // Baseline setup
    // --------------
    // Establish the root object, `window` in the browser, or `exports` on the server.
    var root = this;
    // Save the previous value of the `_` variable.
    var previousUnderscore = root._;
    // Save bytes in the minified (but not gzipped) version:
    var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;
    // Create quick reference variables for speed access to core prototypes.
    var push = ArrayProto.push, slice = ArrayProto.slice, toString = ObjProto.toString, hasOwnProperty = ObjProto.hasOwnProperty;
    // All **ECMAScript 5** native function implementations that we hope to use
    // are declared here.
    var nativeIsArray = Array.isArray, nativeKeys = Object.keys, nativeBind = FuncProto.bind, nativeCreate = Object.create;
    // Naked function reference for surrogate-prototype-swapping.
    var Ctor = function () { };
    // Create a safe reference to the Underscore object for use below.
    var _ = function (obj) {
        if (obj instanceof _)
            return obj;
        if (!(this instanceof _))
            return new _(obj);
        this._wrapped = obj;
    };
    // Export the Underscore object for **Node.js**, with
    // backwards-compatibility for the old `require()` API. If we're in
    // the browser, add `_` as a global object.
    if (typeof exports !== 'undefined') {
        if (typeof module !== 'undefined' && module.exports) {
            exports = module.exports = _;
        }
        exports._ = _;
    }
    else {
        root._ = _;
    }
    // Current version.
    _.VERSION = '1.8.3';
    // Internal function that returns an efficient (for current engines) version
    // of the passed-in callback, to be repeatedly applied in other Underscore
    // functions.
    var optimizeCb = function (func, context, argCount) {
        if (context === void 0)
            return func;
        switch (argCount == null ? 3 : argCount) {
            case 1: return function (value) {
                return func.call(context, value);
            };
            case 2: return function (value, other) {
                return func.call(context, value, other);
            };
            case 3: return function (value, index, collection) {
                return func.call(context, value, index, collection);
            };
            case 4: return function (accumulator, value, index, collection) {
                return func.call(context, accumulator, value, index, collection);
            };
        }
        return function () {
            return func.apply(context, arguments);
        };
    };
    // A mostly-internal function to generate callbacks that can be applied
    // to each element in a collection, returning the desired result — either
    // identity, an arbitrary callback, a property matcher, or a property accessor.
    var cb = function (value, context, argCount) {
        if (value == null)
            return _.identity;
        if (_.isFunction(value))
            return optimizeCb(value, context, argCount);
        if (_.isObject(value))
            return _.matcher(value);
        return _.property(value);
    };
    _.iteratee = function (value, context) {
        return cb(value, context, Infinity);
    };
    // An internal function for creating assigner functions.
    var createAssigner = function (keysFunc, undefinedOnly) {
        return function (obj) {
            var length = arguments.length;
            if (length < 2 || obj == null)
                return obj;
            for (var index = 1; index < length; index++) {
                var source = arguments[index], keys = keysFunc(source), l = keys.length;
                for (var i = 0; i < l; i++) {
                    var key = keys[i];
                    if (!undefinedOnly || obj[key] === void 0)
                        obj[key] = source[key];
                }
            }
            return obj;
        };
    };
    // An internal function for creating a new object that inherits from another.
    var baseCreate = function (prototype) {
        if (!_.isObject(prototype))
            return {};
        if (nativeCreate)
            return nativeCreate(prototype);
        Ctor.prototype = prototype;
        var result = new Ctor;
        Ctor.prototype = null;
        return result;
    };
    var property = function (key) {
        return function (obj) {
            return obj == null ? void 0 : obj[key];
        };
    };
    // Helper for collection methods to determine whether a collection
    // should be iterated as an array or as an object
    // Related: http://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength
    // Avoids a very nasty iOS 8 JIT bug on ARM-64. #2094
    var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1;
    var getLength = property('length');
    var isArrayLike = function (collection) {
        var length = getLength(collection);
        return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX;
    };
    // Collection Functions
    // --------------------
    // The cornerstone, an `each` implementation, aka `forEach`.
    // Handles raw objects in addition to array-likes. Treats all
    // sparse array-likes as if they were dense.
    _.each = _.forEach = function (obj, iteratee, context) {
        iteratee = optimizeCb(iteratee, context);
        var i, length;
        if (isArrayLike(obj)) {
            for (i = 0, length = obj.length; i < length; i++) {
                iteratee(obj[i], i, obj);
            }
        }
        else {
            var keys = _.keys(obj);
            for (i = 0, length = keys.length; i < length; i++) {
                iteratee(obj[keys[i]], keys[i], obj);
            }
        }
        return obj;
    };
    // Return the results of applying the iteratee to each element.
    _.map = _.collect = function (obj, iteratee, context) {
        iteratee = cb(iteratee, context);
        var keys = !isArrayLike(obj) && _.keys(obj), length = (keys || obj).length, results = Array(length);
        for (var index = 0; index < length; index++) {
            var currentKey = keys ? keys[index] : index;
            results[index] = iteratee(obj[currentKey], currentKey, obj);
        }
        return results;
    };
    // Create a reducing function iterating left or right.
    function createReduce(dir) {
        // Optimized iterator function as using arguments.length
        // in the main function will deoptimize the, see #1991.
        function iterator(obj, iteratee, memo, keys, index, length) {
            for (; index >= 0 && index < length; index += dir) {
                var currentKey = keys ? keys[index] : index;
                memo = iteratee(memo, obj[currentKey], currentKey, obj);
            }
            return memo;
        }
        return function (obj, iteratee, memo, context) {
            iteratee = optimizeCb(iteratee, context, 4);
            var keys = !isArrayLike(obj) && _.keys(obj), length = (keys || obj).length, index = dir > 0 ? 0 : length - 1;
            // Determine the initial value if none is provided.
            if (arguments.length < 3) {
                memo = obj[keys ? keys[index] : index];
                index += dir;
            }
            return iterator(obj, iteratee, memo, keys, index, length);
        };
    }
    // **Reduce** builds up a single result from a list of values, aka `inject`,
    // or `foldl`.
    _.reduce = _.foldl = _.inject = createReduce(1);
    // The right-associative version of reduce, also known as `foldr`.
    _.reduceRight = _.foldr = createReduce(-1);
    // Return the first value which passes a truth test. Aliased as `detect`.
    _.find = _.detect = function (obj, predicate, context) {
        var key;
        if (isArrayLike(obj)) {
            key = _.findIndex(obj, predicate, context);
        }
        else {
            key = _.findKey(obj, predicate, context);
        }
        if (key !== void 0 && key !== -1)
            return obj[key];
    };
    // Return all the elements that pass a truth test.
    // Aliased as `select`.
    _.filter = _.select = function (obj, predicate, context) {
        var results = [];
        predicate = cb(predicate, context);
        _.each(obj, function (value, index, list) {
            if (predicate(value, index, list))
                results.push(value);
        });
        return results;
    };
    // Return all the elements for which a truth test fails.
    _.reject = function (obj, predicate, context) {
        return _.filter(obj, _.negate(cb(predicate)), context);
    };
    // Determine whether all of the elements match a truth test.
    // Aliased as `all`.
    _.every = _.all = function (obj, predicate, context) {
        predicate = cb(predicate, context);
        var keys = !isArrayLike(obj) && _.keys(obj), length = (keys || obj).length;
        for (var index = 0; index < length; index++) {
            var currentKey = keys ? keys[index] : index;
            if (!predicate(obj[currentKey], currentKey, obj))
                return false;
        }
        return true;
    };
    // Determine if at least one element in the object matches a truth test.
    // Aliased as `any`.
    _.some = _.any = function (obj, predicate, context) {
        predicate = cb(predicate, context);
        var keys = !isArrayLike(obj) && _.keys(obj), length = (keys || obj).length;
        for (var index = 0; index < length; index++) {
            var currentKey = keys ? keys[index] : index;
            if (predicate(obj[currentKey], currentKey, obj))
                return true;
        }
        return false;
    };
    // Determine if the array or object contains a given item (using `===`).
    // Aliased as `includes` and `include`.
    _.contains = _.includes = _.include = function (obj, item, fromIndex, guard) {
        if (!isArrayLike(obj))
            obj = _.values(obj);
        if (typeof fromIndex != 'number' || guard)
            fromIndex = 0;
        return _.indexOf(obj, item, fromIndex) >= 0;
    };
    // Invoke a method (with arguments) on every item in a collection.
    _.invoke = function (obj, method) {
        var args = slice.call(arguments, 2);
        var isFunc = _.isFunction(method);
        return _.map(obj, function (value) {
            var func = isFunc ? method : value[method];
            return func == null ? func : func.apply(value, args);
        });
    };
    // Convenience version of a common use case of `map`: fetching a property.
    _.pluck = function (obj, key) {
        return _.map(obj, _.property(key));
    };
    // Convenience version of a common use case of `filter`: selecting only objects
    // containing specific `key:value` pairs.
    _.where = function (obj, attrs) {
        return _.filter(obj, _.matcher(attrs));
    };
    // Convenience version of a common use case of `find`: getting the first object
    // containing specific `key:value` pairs.
    _.findWhere = function (obj, attrs) {
        return _.find(obj, _.matcher(attrs));
    };
    // Return the maximum element (or element-based computation).
    _.max = function (obj, iteratee, context) {
        var result = -Infinity, lastComputed = -Infinity, value, computed;
        if (iteratee == null && obj != null) {
            obj = isArrayLike(obj) ? obj : _.values(obj);
            for (var i = 0, length = obj.length; i < length; i++) {
                value = obj[i];
                if (value > result) {
                    result = value;
                }
            }
        }
        else {
            iteratee = cb(iteratee, context);
            _.each(obj, function (value, index, list) {
                computed = iteratee(value, index, list);
                if (computed > lastComputed || computed === -Infinity && result === -Infinity) {
                    result = value;
                    lastComputed = computed;
                }
            });
        }
        return result;
    };
    // Return the minimum element (or element-based computation).
    _.min = function (obj, iteratee, context) {
        var result = Infinity, lastComputed = Infinity, value, computed;
        if (iteratee == null && obj != null) {
            obj = isArrayLike(obj) ? obj : _.values(obj);
            for (var i = 0, length = obj.length; i < length; i++) {
                value = obj[i];
                if (value < result) {
                    result = value;
                }
            }
        }
        else {
            iteratee = cb(iteratee, context);
            _.each(obj, function (value, index, list) {
                computed = iteratee(value, index, list);
                if (computed < lastComputed || computed === Infinity && result === Infinity) {
                    result = value;
                    lastComputed = computed;
                }
            });
        }
        return result;
    };
    // Shuffle a collection, using the modern version of the
    // [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle).
    _.shuffle = function (obj) {
        var set = isArrayLike(obj) ? obj : _.values(obj);
        var length = set.length;
        var shuffled = Array(length);
        for (var index = 0, rand; index < length; index++) {
            rand = _.random(0, index);
            if (rand !== index)
                shuffled[index] = shuffled[rand];
            shuffled[rand] = set[index];
        }
        return shuffled;
    };
    // Sample **n** random values from a collection.
    // If **n** is not specified, returns a single random element.
    // The internal `guard` argument allows it to work with `map`.
    _.sample = function (obj, n, guard) {
        if (n == null || guard) {
            if (!isArrayLike(obj))
                obj = _.values(obj);
            return obj[_.random(obj.length - 1)];
        }
        return _.shuffle(obj).slice(0, Math.max(0, n));
    };
    // Sort the object's values by a criterion produced by an iteratee.
    _.sortBy = function (obj, iteratee, context) {
        iteratee = cb(iteratee, context);
        return _.pluck(_.map(obj, function (value, index, list) {
            return {
                value: value,
                index: index,
                criteria: iteratee(value, index, list)
            };
        }).sort(function (left, right) {
            var a = left.criteria;
            var b = right.criteria;
            if (a !== b) {
                if (a > b || a === void 0)
                    return 1;
                if (a < b || b === void 0)
                    return -1;
            }
            return left.index - right.index;
        }), 'value');
    };
    // An internal function used for aggregate "group by" operations.
    var group = function (behavior) {
        return function (obj, iteratee, context) {
            var result = {};
            iteratee = cb(iteratee, context);
            _.each(obj, function (value, index) {
                var key = iteratee(value, index, obj);
                behavior(result, value, key);
            });
            return result;
        };
    };
    // Groups the object's values by a criterion. Pass either a string attribute
    // to group by, or a function that returns the criterion.
    _.groupBy = group(function (result, value, key) {
        if (_.has(result, key))
            result[key].push(value);
        else
            result[key] = [value];
    });
    // Indexes the object's values by a criterion, similar to `groupBy`, but for
    // when you know that your index values will be unique.
    _.indexBy = group(function (result, value, key) {
        result[key] = value;
    });
    // Counts instances of an object that group by a certain criterion. Pass
    // either a string attribute to count by, or a function that returns the
    // criterion.
    _.countBy = group(function (result, value, key) {
        if (_.has(result, key))
            result[key]++;
        else
            result[key] = 1;
    });
    // Safely create a real, live array from anything iterable.
    _.toArray = function (obj) {
        if (!obj)
            return [];
        if (_.isArray(obj))
            return slice.call(obj);
        if (isArrayLike(obj))
            return _.map(obj, _.identity);
        return _.values(obj);
    };
    // Return the number of elements in an object.
    _.size = function (obj) {
        if (obj == null)
            return 0;
        return isArrayLike(obj) ? obj.length : _.keys(obj).length;
    };
    // Split a collection into two arrays: one whose elements all satisfy the given
    // predicate, and one whose elements all do not satisfy the predicate.
    _.partition = function (obj, predicate, context) {
        predicate = cb(predicate, context);
        var pass = [], fail = [];
        _.each(obj, function (value, key, obj) {
            (predicate(value, key, obj) ? pass : fail).push(value);
        });
        return [pass, fail];
    };
    // Array Functions
    // ---------------
    // Get the first element of an array. Passing **n** will return the first N
    // values in the array. Aliased as `head` and `take`. The **guard** check
    // allows it to work with `_.map`.
    _.first = _.head = _.take = function (array, n, guard) {
        if (array == null)
            return void 0;
        if (n == null || guard)
            return array[0];
        return _.initial(array, array.length - n);
    };
    // Returns everything but the last entry of the array. Especially useful on
    // the arguments object. Passing **n** will return all the values in
    // the array, excluding the last N.
    _.initial = function (array, n, guard) {
        return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n)));
    };
    // Get the last element of an array. Passing **n** will return the last N
    // values in the array.
    _.last = function (array, n, guard) {
        if (array == null)
            return void 0;
        if (n == null || guard)
            return array[array.length - 1];
        return _.rest(array, Math.max(0, array.length - n));
    };
    // Returns everything but the first entry of the array. Aliased as `tail` and `drop`.
    // Especially useful on the arguments object. Passing an **n** will return
    // the rest N values in the array.
    _.rest = _.tail = _.drop = function (array, n, guard) {
        return slice.call(array, n == null || guard ? 1 : n);
    };
    // Trim out all falsy values from an array.
    _.compact = function (array) {
        return _.filter(array, _.identity);
    };
    // Internal implementation of a recursive `flatten` function.
    var flatten = function (input, shallow, strict, startIndex) {
        var output = [], idx = 0;
        for (var i = startIndex || 0, length = getLength(input); i < length; i++) {
            var value = input[i];
            if (isArrayLike(value) && (_.isArray(value) || _.isArguments(value))) {
                //flatten current level of array or arguments object
                if (!shallow)
                    value = flatten(value, shallow, strict);
                var j = 0, len = value.length;
                output.length += len;
                while (j < len) {
                    output[idx++] = value[j++];
                }
            }
            else if (!strict) {
                output[idx++] = value;
            }
        }
        return output;
    };
    // Flatten out an array, either recursively (by default), or just one level.
    _.flatten = function (array, shallow) {
        return flatten(array, shallow, false);
    };
    // Return a version of the array that does not contain the specified value(s).
    _.without = function (array) {
        return _.difference(array, slice.call(arguments, 1));
    };
    // Produce a duplicate-free version of the array. If the array has already
    // been sorted, you have the option of using a faster algorithm.
    // Aliased as `unique`.
    _.uniq = _.unique = function (array, isSorted, iteratee, context) {
        if (!_.isBoolean(isSorted)) {
            context = iteratee;
            iteratee = isSorted;
            isSorted = false;
        }
        if (iteratee != null)
            iteratee = cb(iteratee, context);
        var result = [];
        var seen = [];
        for (var i = 0, length = getLength(array); i < length; i++) {
            var value = array[i], computed = iteratee ? iteratee(value, i, array) : value;
            if (isSorted) {
                if (!i || seen !== computed)
                    result.push(value);
                seen = computed;
            }
            else if (iteratee) {
                if (!_.contains(seen, computed)) {
                    seen.push(computed);
                    result.push(value);
                }
            }
            else if (!_.contains(result, value)) {
                result.push(value);
            }
        }
        return result;
    };
    // Produce an array that contains the union: each distinct element from all of
    // the passed-in arrays.
    _.union = function () {
        return _.uniq(flatten(arguments, true, true));
    };
    // Produce an array that contains every item shared between all the
    // passed-in arrays.
    _.intersection = function (array) {
        var result = [];
        var argsLength = arguments.length;
        for (var i = 0, length = getLength(array); i < length; i++) {
            var item = array[i];
            if (_.contains(result, item))
                continue;
            for (var j = 1; j < argsLength; j++) {
                if (!_.contains(arguments[j], item))
                    break;
            }
            if (j === argsLength)
                result.push(item);
        }
        return result;
    };
    // Take the difference between one array and a number of other arrays.
    // Only the elements present in just the first array will remain.
    _.difference = function (array) {
        var rest = flatten(arguments, true, true, 1);
        return _.filter(array, function (value) {
            return !_.contains(rest, value);
        });
    };
    // Zip together multiple lists into a single array -- elements that share
    // an index go together.
    _.zip = function () {
        return _.unzip(arguments);
    };
    // Complement of _.zip. Unzip accepts an array of arrays and groups
    // each array's elements on shared indices
    _.unzip = function (array) {
        var length = array && _.max(array, getLength).length || 0;
        var result = Array(length);
        for (var index = 0; index < length; index++) {
            result[index] = _.pluck(array, index);
        }
        return result;
    };
    // Converts lists into objects. Pass either a single array of `[key, value]`
    // pairs, or two parallel arrays of the same length -- one of keys, and one of
    // the corresponding values.
    _.object = function (list, values) {
        var result = {};
        for (var i = 0, length = getLength(list); i < length; i++) {
            if (values) {
                result[list[i]] = values[i];
            }
            else {
                result[list[i][0]] = list[i][1];
            }
        }
        return result;
    };
    // Generator function to create the findIndex and findLastIndex functions
    function createPredicateIndexFinder(dir) {
        return function (array, predicate, context) {
            predicate = cb(predicate, context);
            var length = getLength(array);
            var index = dir > 0 ? 0 : length - 1;
            for (; index >= 0 && index < length; index += dir) {
                if (predicate(array[index], index, array))
                    return index;
            }
            return -1;
        };
    }
    // Returns the first index on an array-like that passes a predicate test
    _.findIndex = createPredicateIndexFinder(1);
    _.findLastIndex = createPredicateIndexFinder(-1);
    // Use a comparator function to figure out the smallest index at which
    // an object should be inserted so as to maintain order. Uses binary search.
    _.sortedIndex = function (array, obj, iteratee, context) {
        iteratee = cb(iteratee, context, 1);
        var value = iteratee(obj);
        var low = 0, high = getLength(array);
        while (low < high) {
            var mid = Math.floor((low + high) / 2);
            if (iteratee(array[mid]) < value)
                low = mid + 1;
            else
                high = mid;
        }
        return low;
    };
    // Generator function to create the indexOf and lastIndexOf functions
    function createIndexFinder(dir, predicateFind, sortedIndex) {
        return function (array, item, idx) {
            var i = 0, length = getLength(array);
            if (typeof idx == 'number') {
                if (dir > 0) {
                    i = idx >= 0 ? idx : Math.max(idx + length, i);
                }
                else {
                    length = idx >= 0 ? Math.min(idx + 1, length) : idx + length + 1;
                }
            }
            else if (sortedIndex && idx && length) {
                idx = sortedIndex(array, item);
                return array[idx] === item ? idx : -1;
            }
            if (item !== item) {
                idx = predicateFind(slice.call(array, i, length), _.isNaN);
                return idx >= 0 ? idx + i : -1;
            }
            for (idx = dir > 0 ? i : length - 1; idx >= 0 && idx < length; idx += dir) {
                if (array[idx] === item)
                    return idx;
            }
            return -1;
        };
    }
    // Return the position of the first occurrence of an item in an array,
    // or -1 if the item is not included in the array.
    // If the array is large and already in sort order, pass `true`
    // for **isSorted** to use binary search.
    _.indexOf = createIndexFinder(1, _.findIndex, _.sortedIndex);
    _.lastIndexOf = createIndexFinder(-1, _.findLastIndex);
    // Generate an integer Array containing an arithmetic progression. A port of
    // the native Python `range()` function. See
    // [the Python documentation](http://docs.python.org/library/functions.html#range).
    _.range = function (start, stop, step) {
        if (stop == null) {
            stop = start || 0;
            start = 0;
        }
        step = step || 1;
        var length = Math.max(Math.ceil((stop - start) / step), 0);
        var range = Array(length);
        for (var idx = 0; idx < length; idx++, start += step) {
            range[idx] = start;
        }
        return range;
    };
    // Function (ahem) Functions
    // ------------------
    // Determines whether to execute a function as a constructor
    // or a normal function with the provided arguments
    var executeBound = function (sourceFunc, boundFunc, context, callingContext, args) {
        if (!(callingContext instanceof boundFunc))
            return sourceFunc.apply(context, args);
        var self = baseCreate(sourceFunc.prototype);
        var result = sourceFunc.apply(self, args);
        if (_.isObject(result))
            return result;
        return self;
    };
    // Create a function bound to a given object (assigning `this`, and arguments,
    // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if
    // available.
    _.bind = function (func, context) {
        if (nativeBind && func.bind === nativeBind)
            return nativeBind.apply(func, slice.call(arguments, 1));
        if (!_.isFunction(func))
            throw new TypeError('Bind must be called on a function');
        var args = slice.call(arguments, 2);
        var bound = function () {
            return executeBound(func, bound, context, this, args.concat(slice.call(arguments)));
        };
        return bound;
    };
    // Partially apply a function by creating a version that has had some of its
    // arguments pre-filled, without changing its dynamic `this` context. _ acts
    // as a placeholder, allowing any combination of arguments to be pre-filled.
    _.partial = function (func) {
        var boundArgs = slice.call(arguments, 1);
        var bound = function () {
            var position = 0, length = boundArgs.length;
            var args = Array(length);
            for (var i = 0; i < length; i++) {
                args[i] = boundArgs[i] === _ ? arguments[position++] : boundArgs[i];
            }
            while (position < arguments.length)
                args.push(arguments[position++]);
            return executeBound(func, bound, this, this, args);
        };
        return bound;
    };
    // Bind a number of an object's methods to that object. Remaining arguments
    // are the method names to be bound. Useful for ensuring that all callbacks
    // defined on an object belong to it.
    _.bindAll = function (obj) {
        var i, length = arguments.length, key;
        if (length <= 1)
            throw new Error('bindAll must be passed function names');
        for (i = 1; i < length; i++) {
            key = arguments[i];
            obj[key] = _.bind(obj[key], obj);
        }
        return obj;
    };
    // Memoize an expensive function by storing its results.
    _.memoize = function (func, hasher) {
        var memoize = function (key) {
            var cache = memoize.cache;
            var address = '' + (hasher ? hasher.apply(this, arguments) : key);
            if (!_.has(cache, address))
                cache[address] = func.apply(this, arguments);
            return cache[address];
        };
        memoize.cache = {};
        return memoize;
    };
    // Delays a function for the given number of milliseconds, and then calls
    // it with the arguments supplied.
    _.delay = function (func, wait) {
        var args = slice.call(arguments, 2);
        return setTimeout(function () {
            return func.apply(null, args);
        }, wait);
    };
    // Defers a function, scheduling it to run after the current call stack has
    // cleared.
    _.defer = _.partial(_.delay, _, 1);
    // Returns a function, that, when invoked, will only be triggered at most once
    // during a given window of time. Normally, the throttled function will run
    // as much as it can, without ever going more than once per `wait` duration;
    // but if you'd like to disable the execution on the leading edge, pass
    // `{leading: false}`. To disable execution on the trailing edge, ditto.
    _.throttle = function (func, wait, options) {
        var context, args, result;
        var timeout = null;
        var previous = 0;
        if (!options)
            options = {};
        var later = function () {
            previous = options.leading === false ? 0 : _.now();
            timeout = null;
            result = func.apply(context, args);
            if (!timeout)
                context = args = null;
        };
        return function () {
            var now = _.now();
            if (!previous && options.leading === false)
                previous = now;
            var remaining = wait - (now - previous);
            context = this;
            args = arguments;
            if (remaining <= 0 || remaining > wait) {
                if (timeout) {
                    clearTimeout(timeout);
                    timeout = null;
                }
                previous = now;
                result = func.apply(context, args);
                if (!timeout)
                    context = args = null;
            }
            else if (!timeout && options.trailing !== false) {
                timeout = setTimeout(later, remaining);
            }
            return result;
        };
    };
    // Returns a function, that, as long as it continues to be invoked, will not
    // be triggered. The function will be called after it stops being called for
    // N milliseconds. If `immediate` is passed, trigger the function on the
    // leading edge, instead of the trailing.
    _.debounce = function (func, wait, immediate) {
        var timeout, args, context, timestamp, result;
        var later = function () {
            var last = _.now() - timestamp;
            if (last < wait && last >= 0) {
                timeout = setTimeout(later, wait - last);
            }
            else {
                timeout = null;
                if (!immediate) {
                    result = func.apply(context, args);
                    if (!timeout)
                        context = args = null;
                }
            }
        };
        return function () {
            context = this;
            args = arguments;
            timestamp = _.now();
            var callNow = immediate && !timeout;
            if (!timeout)
                timeout = setTimeout(later, wait);
            if (callNow) {
                result = func.apply(context, args);
                context = args = null;
            }
            return result;
        };
    };
    // Returns the first function passed as an argument to the second,
    // allowing you to adjust arguments, run code before and after, and
    // conditionally execute the original function.
    _.wrap = function (func, wrapper) {
        return _.partial(wrapper, func);
    };
    // Returns a negated version of the passed-in predicate.
    _.negate = function (predicate) {
        return function () {
            return !predicate.apply(this, arguments);
        };
    };
    // Returns a function that is the composition of a list of functions, each
    // consuming the return value of the function that follows.
    _.compose = function () {
        var args = arguments;
        var start = args.length - 1;
        return function () {
            var i = start;
            var result = args[start].apply(this, arguments);
            while (i--)
                result = args[i].call(this, result);
            return result;
        };
    };
    // Returns a function that will only be executed on and after the Nth call.
    _.after = function (times, func) {
        return function () {
            if (--times < 1) {
                return func.apply(this, arguments);
            }
        };
    };
    // Returns a function that will only be executed up to (but not including) the Nth call.
    _.before = function (times, func) {
        var memo;
        return function () {
            if (--times > 0) {
                memo = func.apply(this, arguments);
            }
            if (times <= 1)
                func = null;
            return memo;
        };
    };
    // Returns a function that will be executed at most one time, no matter how
    // often you call it. Useful for lazy initialization.
    _.once = _.partial(_.before, 2);
    // Object Functions
    // ----------------
    // Keys in IE < 9 that won't be iterated by `for key in ...` and thus missed.
    var hasEnumBug = !{ toString: null }.propertyIsEnumerable('toString');
    var nonEnumerableProps = ['valueOf', 'isPrototypeOf', 'toString',
        'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString'];
    function collectNonEnumProps(obj, keys) {
        var nonEnumIdx = nonEnumerableProps.length;
        var constructor = obj.constructor;
        var proto = (_.isFunction(constructor) && constructor.prototype) || ObjProto;
        // Constructor is a special case.
        var prop = 'constructor';
        if (_.has(obj, prop) && !_.contains(keys, prop))
            keys.push(prop);
        while (nonEnumIdx--) {
            prop = nonEnumerableProps[nonEnumIdx];
            if (prop in obj && obj[prop] !== proto[prop] && !_.contains(keys, prop)) {
                keys.push(prop);
            }
        }
    }
    // Retrieve the names of an object's own properties.
    // Delegates to **ECMAScript 5**'s native `Object.keys`
    _.keys = function (obj) {
        if (!_.isObject(obj))
            return [];
        if (nativeKeys)
            return nativeKeys(obj);
        var keys = [];
        for (var key in obj)
            if (_.has(obj, key))
                keys.push(key);
        // Ahem, IE < 9.
        if (hasEnumBug)
            collectNonEnumProps(obj, keys);
        return keys;
    };
    // Retrieve all the property names of an object.
    _.allKeys = function (obj) {
        if (!_.isObject(obj))
            return [];
        var keys = [];
        for (var key in obj)
            keys.push(key);
        // Ahem, IE < 9.
        if (hasEnumBug)
            collectNonEnumProps(obj, keys);
        return keys;
    };
    // Retrieve the values of an object's properties.
    _.values = function (obj) {
        var keys = _.keys(obj);
        var length = keys.length;
        var values = Array(length);
        for (var i = 0; i < length; i++) {
            values[i] = obj[keys[i]];
        }
        return values;
    };
    // Returns the results of applying the iteratee to each element of the object
    // In contrast to _.map it returns an object
    _.mapObject = function (obj, iteratee, context) {
        iteratee = cb(iteratee, context);
        var keys = _.keys(obj), length = keys.length, results = {}, currentKey;
        for (var index = 0; index < length; index++) {
            currentKey = keys[index];
            results[currentKey] = iteratee(obj[currentKey], currentKey, obj);
        }
        return results;
    };
    // Convert an object into a list of `[key, value]` pairs.
    _.pairs = function (obj) {
        var keys = _.keys(obj);
        var length = keys.length;
        var pairs = Array(length);
        for (var i = 0; i < length; i++) {
            pairs[i] = [keys[i], obj[keys[i]]];
        }
        return pairs;
    };
    // Invert the keys and values of an object. The values must be serializable.
    _.invert = function (obj) {
        var result = {};
        var keys = _.keys(obj);
        for (var i = 0, length = keys.length; i < length; i++) {
            result[obj[keys[i]]] = keys[i];
        }
        return result;
    };
    // Return a sorted list of the function names available on the object.
    // Aliased as `methods`
    _.functions = _.methods = function (obj) {
        var names = [];
        for (var key in obj) {
            if (_.isFunction(obj[key]))
                names.push(key);
        }
        return names.sort();
    };
    // Extend a given object with all the properties in passed-in object(s).
    _.extend = createAssigner(_.allKeys);
    // Assigns a given object with all the own properties in the passed-in object(s)
    // (https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/assign)
    _.extendOwn = _.assign = createAssigner(_.keys);
    // Returns the first key on an object that passes a predicate test
    _.findKey = function (obj, predicate, context) {
        predicate = cb(predicate, context);
        var keys = _.keys(obj), key;
        for (var i = 0, length = keys.length; i < length; i++) {
            key = keys[i];
            if (predicate(obj[key], key, obj))
                return key;
        }
    };
    // Return a copy of the object only containing the whitelisted properties.
    _.pick = function (object, oiteratee, context) {
        var result = {}, obj = object, iteratee, keys;
        if (obj == null)
            return result;
        if (_.isFunction(oiteratee)) {
            keys = _.allKeys(obj);
            iteratee = optimizeCb(oiteratee, context);
        }
        else {
            keys = flatten(arguments, false, false, 1);
            iteratee = function (value, key, obj) { return key in obj; };
            obj = Object(obj);
        }
        for (var i = 0, length = keys.length; i < length; i++) {
            var key = keys[i];
            var value = obj[key];
            if (iteratee(value, key, obj))
                result[key] = value;
        }
        return result;
    };
    // Return a copy of the object without the blacklisted properties.
    _.omit = function (obj, iteratee, context) {
        if (_.isFunction(iteratee)) {
            iteratee = _.negate(iteratee);
        }
        else {
            var keys = _.map(flatten(arguments, false, false, 1), String);
            iteratee = function (value, key) {
                return !_.contains(keys, key);
            };
        }
        return _.pick(obj, iteratee, context);
    };
    // Fill in a given object with default properties.
    _.defaults = createAssigner(_.allKeys, true);
    // Creates an object that inherits from the given prototype object.
    // If additional properties are provided then they will be added to the
    // created object.
    _.create = function (prototype, props) {
        var result = baseCreate(prototype);
        if (props)
            _.extendOwn(result, props);
        return result;
    };
    // Create a (shallow-cloned) duplicate of an object.
    _.clone = function (obj) {
        if (!_.isObject(obj))
            return obj;
        return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
    };
    // Invokes interceptor with the obj, and then returns obj.
    // The primary purpose of this method is to "tap into" a method chain, in
    // order to perform operations on intermediate results within the chain.
    _.tap = function (obj, interceptor) {
        interceptor(obj);
        return obj;
    };
    // Returns whether an object has a given set of `key:value` pairs.
    _.isMatch = function (object, attrs) {
        var keys = _.keys(attrs), length = keys.length;
        if (object == null)
            return !length;
        var obj = Object(object);
        for (var i = 0; i < length; i++) {
            var key = keys[i];
            if (attrs[key] !== obj[key] || !(key in obj))
                return false;
        }
        return true;
    };
    // Internal recursive comparison function for `isEqual`.
    var eq = function (a, b, aStack, bStack) {
        // Identical objects are equal. `0 === -0`, but they aren't identical.
        // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
        if (a === b)
            return a !== 0 || 1 / a === 1 / b;
        // A strict comparison is necessary because `null == undefined`.
        if (a == null || b == null)
            return a === b;
        // Unwrap any wrapped objects.
        if (a instanceof _)
            a = a._wrapped;
        if (b instanceof _)
            b = b._wrapped;
        // Compare `[[Class]]` names.
        var className = toString.call(a);
        if (className !== toString.call(b))
            return false;
        switch (className) {
            // Strings, numbers, regular expressions, dates, and booleans are compared by value.
            case '[object RegExp]':
            // RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i')
            case '[object String]':
                // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
                // equivalent to `new String("5")`.
                return '' + a === '' + b;
            case '[object Number]':
                // `NaN`s are equivalent, but non-reflexive.
                // Object(NaN) is equivalent to NaN
                if (+a !== +a)
                    return +b !== +b;
                // An `egal` comparison is performed for other numeric values.
                return +a === 0 ? 1 / +a === 1 / b : +a === +b;
            case '[object Date]':
            case '[object Boolean]':
                // Coerce dates and booleans to numeric primitive values. Dates are compared by their
                // millisecond representations. Note that invalid dates with millisecond representations
                // of `NaN` are not equivalent.
                return +a === +b;
        }
        var areArrays = className === '[object Array]';
        if (!areArrays) {
            if (typeof a != 'object' || typeof b != 'object')
                return false;
            // Objects with different constructors are not equivalent, but `Object`s or `Array`s
            // from different frames are.
            var aCtor = a.constructor, bCtor = b.constructor;
            if (aCtor !== bCtor && !(_.isFunction(aCtor) && aCtor instanceof aCtor &&
                _.isFunction(bCtor) && bCtor instanceof bCtor)
                && ('constructor' in a && 'constructor' in b)) {
                return false;
            }
        }
        // Assume equality for cyclic structures. The algorithm for detecting cyclic
        // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
        // Initializing stack of traversed objects.
        // It's done here since we only need them for objects and arrays comparison.
        aStack = aStack || [];
        bStack = bStack || [];
        var length = aStack.length;
        while (length--) {
            // Linear search. Performance is inversely proportional to the number of
            // unique nested structures.
            if (aStack[length] === a)
                return bStack[length] === b;
        }
        // Add the first object to the stack of traversed objects.
        aStack.push(a);
        bStack.push(b);
        // Recursively compare objects and arrays.
        if (areArrays) {
            // Compare array lengths to determine if a deep comparison is necessary.
            length = a.length;
            if (length !== b.length)
                return false;
            // Deep compare the contents, ignoring non-numeric properties.
            while (length--) {
                if (!eq(a[length], b[length], aStack, bStack))
                    return false;
            }
        }
        else {
            // Deep compare objects.
            var keys = _.keys(a), key;
            length = keys.length;
            // Ensure that both objects contain the same number of properties before comparing deep equality.
            if (_.keys(b).length !== length)
                return false;
            while (length--) {
                // Deep compare each member
                key = keys[length];
                if (!(_.has(b, key) && eq(a[key], b[key], aStack, bStack)))
                    return false;
            }
        }
        // Remove the first object from the stack of traversed objects.
        aStack.pop();
        bStack.pop();
        return true;
    };
    // Perform a deep comparison to check if two objects are equal.
    _.isEqual = function (a, b) {
        return eq(a, b);
    };
    // Is a given array, string, or object empty?
    // An "empty" object has no enumerable own-properties.
    _.isEmpty = function (obj) {
        if (obj == null)
            return true;
        if (isArrayLike(obj) && (_.isArray(obj) || _.isString(obj) || _.isArguments(obj)))
            return obj.length === 0;
        return _.keys(obj).length === 0;
    };
    // Is a given value a DOM element?
    _.isElement = function (obj) {
        return !!(obj && obj.nodeType === 1);
    };
    // Is a given value an array?
    // Delegates to ECMA5's native Array.isArray
    _.isArray = nativeIsArray || function (obj) {
        return toString.call(obj) === '[object Array]';
    };
    // Is a given variable an object?
    _.isObject = function (obj) {
        var type = typeof obj;
        return type === 'function' || type === 'object' && !!obj;
    };
    // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp, isError.
    _.each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp', 'Error'], function (name) {
        _['is' + name] = function (obj) {
            return toString.call(obj) === '[object ' + name + ']';
        };
    });
    // Define a fallback version of the method in browsers (ahem, IE < 9), where
    // there isn't any inspectable "Arguments" type.
    if (!_.isArguments(arguments)) {
        _.isArguments = function (obj) {
            return _.has(obj, 'callee');
        };
    }
    // Optimize `isFunction` if appropriate. Work around some typeof bugs in old v8,
    // IE 11 (#1621), and in Safari 8 (#1929).
    if (typeof /./ != 'function' && typeof Int8Array != 'object') {
        _.isFunction = function (obj) {
            return typeof obj == 'function' || false;
        };
    }
    // Is a given object a finite number?
    _.isFinite = function (obj) {
        return isFinite(obj) && !isNaN(parseFloat(obj));
    };
    // Is the given value `NaN`? (NaN is the only number which does not equal itself).
    _.isNaN = function (obj) {
        return _.isNumber(obj) && obj !== +obj;
    };
    // Is a given value a boolean?
    _.isBoolean = function (obj) {
        return obj === true || obj === false || toString.call(obj) === '[object Boolean]';
    };
    // Is a given value equal to null?
    _.isNull = function (obj) {
        return obj === null;
    };
    // Is a given variable undefined?
    _.isUndefined = function (obj) {
        return obj === void 0;
    };
    // Shortcut function for checking if an object has a given property directly
    // on itself (in other words, not on a prototype).
    _.has = function (obj, key) {
        return obj != null && hasOwnProperty.call(obj, key);
    };
    // Utility Functions
    // -----------------
    // Run Underscore.js in *noConflict* mode, returning the `_` variable to its
    // previous owner. Returns a reference to the Underscore object.
    _.noConflict = function () {
        root._ = previousUnderscore;
        return this;
    };
    // Keep the identity function around for default iteratees.
    _.identity = function (value) {
        return value;
    };
    // Predicate-generating functions. Often useful outside of Underscore.
    _.constant = function (value) {
        return function () {
            return value;
        };
    };
    _.noop = function () { };
    _.property = property;
    // Generates a function for a given object that returns a given property.
    _.propertyOf = function (obj) {
        return obj == null ? function () { } : function (key) {
            return obj[key];
        };
    };
    // Returns a predicate for checking whether an object has a given set of
    // `key:value` pairs.
    _.matcher = _.matches = function (attrs) {
        attrs = _.extendOwn({}, attrs);
        return function (obj) {
            return _.isMatch(obj, attrs);
        };
    };
    // Run a function **n** times.
    _.times = function (n, iteratee, context) {
        var accum = Array(Math.max(0, n));
        iteratee = optimizeCb(iteratee, context, 1);
        for (var i = 0; i < n; i++)
            accum[i] = iteratee(i);
        return accum;
    };
    // Return a random integer between min and max (inclusive).
    _.random = function (min, max) {
        if (max == null) {
            max = min;
            min = 0;
        }
        return min + Math.floor(Math.random() * (max - min + 1));
    };
    // A (possibly faster) way to get the current timestamp as an integer.
    _.now = Date.now || function () {
        return new Date().getTime();
    };
    // List of HTML entities for escaping.
    var escapeMap = {
        '&': '&amp;',
        '<': '&lt;',
        '>': '&gt;',
        '"': '&quot;',
        "'": '&#x27;',
        '`': '&#x60;'
    };
    var unescapeMap = _.invert(escapeMap);
    // Functions for escaping and unescaping strings to/from HTML interpolation.
    var createEscaper = function (map) {
        var escaper = function (match) {
            return map[match];
        };
        // Regexes for identifying a key that needs to be escaped
        var source = '(?:' + _.keys(map).join('|') + ')';
        var testRegexp = RegExp(source);
        var replaceRegexp = RegExp(source, 'g');
        return function (string) {
            string = string == null ? '' : '' + string;
            return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string;
        };
    };
    _.escape = createEscaper(escapeMap);
    _.unescape = createEscaper(unescapeMap);
    // If the value of the named `property` is a function then invoke it with the
    // `object` as context; otherwise, return it.
    _.result = function (object, property, fallback) {
        var value = object == null ? void 0 : object[property];
        if (value === void 0) {
            value = fallback;
        }
        return _.isFunction(value) ? value.call(object) : value;
    };
    // Generate a unique integer id (unique within the entire client session).
    // Useful for temporary DOM ids.
    var idCounter = 0;
    _.uniqueId = function (prefix) {
        var id = ++idCounter + '';
        return prefix ? prefix + id : id;
    };
    // By default, Underscore uses ERB-style template delimiters, change the
    // following template settings to use alternative delimiters.
    _.templateSettings = {
        evaluate: /<%([\s\S]+?)%>/g,
        interpolate: /<%=([\s\S]+?)%>/g,
        escape: /<%-([\s\S]+?)%>/g
    };
    // When customizing `templateSettings`, if you don't want to define an
    // interpolation, evaluation or escaping regex, we need one that is
    // guaranteed not to match.
    var noMatch = /(.)^/;
    // Certain characters need to be escaped so that they can be put into a
    // string literal.
    var escapes = {
        "'": "'",
        '\\': '\\',
        '\r': 'r',
        '\n': 'n',
        '\u2028': 'u2028',
        '\u2029': 'u2029'
    };
    var escaper = /\\|'|\r|\n|\u2028|\u2029/g;
    var escapeChar = function (match) {
        return '\\' + escapes[match];
    };
    // JavaScript micro-templating, similar to John Resig's implementation.
    // Underscore templating handles arbitrary delimiters, preserves whitespace,
    // and correctly escapes quotes within interpolated code.
    // NB: `oldSettings` only exists for backwards compatibility.
    _.template = function (text, settings, oldSettings) {
        if (!settings && oldSettings)
            settings = oldSettings;
        settings = _.defaults({}, settings, _.templateSettings);
        // Combine delimiters into one regular expression via alternation.
        var matcher = RegExp([
            (settings.escape || noMatch).source,
            (settings.interpolate || noMatch).source,
            (settings.evaluate || noMatch).source
        ].join('|') + '|$', 'g');
        // Compile the template source, escaping string literals appropriately.
        var index = 0;
        var source = "__p+='";
        text.replace(matcher, function (match, escape, interpolate, evaluate, offset) {
            source += text.slice(index, offset).replace(escaper, escapeChar);
            index = offset + match.length;
            if (escape) {
                source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
            }
            else if (interpolate) {
                source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
            }
            else if (evaluate) {
                source += "';\n" + evaluate + "\n__p+='";
            }
            // Adobe VMs need the match returned to produce the correct offest.
            return match;
        });
        source += "';\n";
        // If a variable is not specified, place data values in local scope.
        if (!settings.variable)
            source = 'with(obj||{}){\n' + source + '}\n';
        source = "var __t,__p='',__j=Array.prototype.join," +
            "print=function(){__p+=__j.call(arguments,'');};\n" +
            source + 'return __p;\n';
        try {
            var render = new Function(settings.variable || 'obj', '_', source);
        }
        catch (e) {
            e.source = source;
            throw e;
        }
        var template = function (data) {
            return render.call(this, data, _);
        };
        // Provide the compiled source as a convenience for precompilation.
        var argument = settings.variable || 'obj';
        template.source = 'function(' + argument + '){\n' + source + '}';
        return template;
    };
    // Add a "chain" function. Start chaining a wrapped Underscore object.
    _.chain = function (obj) {
        var instance = _(obj);
        instance._chain = true;
        return instance;
    };
    // OOP
    // ---------------
    // If Underscore is called as a function, it returns a wrapped object that
    // can be used OO-style. This wrapper holds altered versions of all the
    // underscore functions. Wrapped objects may be chained.
    // Helper function to continue chaining intermediate results.
    var result = function (instance, obj) {
        return instance._chain ? _(obj).chain() : obj;
    };
    // Add your own custom functions to the Underscore object.
    _.mixin = function (obj) {
        _.each(_.functions(obj), function (name) {
            var func = _[name] = obj[name];
            _.prototype[name] = function () {
                var args = [this._wrapped];
                push.apply(args, arguments);
                return result(this, func.apply(_, args));
            };
        });
    };
    // Add all of the Underscore functions to the wrapper object.
    _.mixin(_);
    // Add all mutator Array functions to the wrapper.
    _.each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function (name) {
        var method = ArrayProto[name];
        _.prototype[name] = function () {
            var obj = this._wrapped;
            method.apply(obj, arguments);
            if ((name === 'shift' || name === 'splice') && obj.length === 0)
                delete obj[0];
            return result(this, obj);
        };
    });
    // Add all accessor Array functions to the wrapper.
    _.each(['concat', 'join', 'slice'], function (name) {
        var method = ArrayProto[name];
        _.prototype[name] = function () {
            return result(this, method.apply(this._wrapped, arguments));
        };
    });
    // Extracts the result from a wrapped and chained object.
    _.prototype.value = function () {
        return this._wrapped;
    };
    // Provide unwrapping proxy for some methods used in engine operations
    // such as arithmetic and JSON stringification.
    _.prototype.valueOf = _.prototype.toJSON = _.prototype.value;
    _.prototype.toString = function () {
        return '' + this._wrapped;
    };
    // AMD registration happens at the end for compatibility with AMD loaders
    // that may not enforce next-turn semantics on modules. Even though general
    // practice for AMD registration is to be anonymous, underscore registers
    // as a named module because, like jQuery, it is a base library that is
    // popular enough to be bundled in a third party lib, but not be part of
    // an AMD load request. Those cases could generate an error when an
    // anonymous define() is called outside of a loader request.
    if (typeof define === 'function' && define.amd) {
        define('underscore', [], function () {
            return _;
        });
    }
}.call(this));
//# sourceMappingURL=underscore.js.map 
//# sourceMappingURL=underscore.js.map 
//# sourceMappingURL=underscore.js.map 
//# sourceMappingURL=underscore.js.map 
//# sourceMappingURL=underscore.js.map 
//# sourceMappingURL=underscore.js.map;
/*!
 * jQuery Validation Plugin v1.16.0
 *
 * http://jqueryvalidation.org/
 *
 * Copyright (c) 2016 Jörn Zaefferer
 * Released under the MIT license
 */
(function (factory) {
    if (typeof define === "function" && define.amd) {
        define(["jquery"], factory);
    }
    else if (typeof module === "object" && module.exports) {
        module.exports = factory(require("jquery"));
    }
    else {
        factory(jQuery);
    }
}(function ($) {
    $.extend($.fn, {
        // http://jqueryvalidation.org/validate/
        validate: function (options) {
            // If nothing is selected, return nothing; can't chain anyway
            if (!this.length) {
                if (options && options.debug && window.console) {
                    console.warn("Nothing selected, can't validate, returning nothing.");
                }
                return;
            }
            // Check if a validator for this form was already created
            var validator = $.data(this[0], "validator");
            if (validator) {
                return validator;
            }
            // Add novalidate tag if HTML5.
            this.attr("novalidate", "novalidate");
            validator = new $.validator(options, this[0]);
            $.data(this[0], "validator", validator);
            if (validator.settings.onsubmit) {
                this.on("click.validate", ":submit", function (event) {
                    if (validator.settings.submitHandler) {
                        validator.submitButton = event.target;
                    }
                    // Allow suppressing validation by adding a cancel class to the submit button
                    if ($(this).hasClass("cancel")) {
                        validator.cancelSubmit = true;
                    }
                    // Allow suppressing validation by adding the html5 formnovalidate attribute to the submit button
                    if ($(this).attr("formnovalidate") !== undefined) {
                        validator.cancelSubmit = true;
                    }
                });
                // Validate the form on submit
                this.on("submit.validate", function (event) {
                    if (validator.settings.debug) {
                        // Prevent form submit to be able to see console output
                        event.preventDefault();
                    }
                    function handle() {
                        var hidden, result;
                        if (validator.settings.submitHandler) {
                            if (validator.submitButton) {
                                // Insert a hidden input as a replacement for the missing submit button
                                hidden = $("<input type='hidden'/>")
                                    .attr("name", validator.submitButton.name)
                                    .val($(validator.submitButton).val())
                                    .appendTo(validator.currentForm);
                            }
                            result = validator.settings.submitHandler.call(validator, validator.currentForm, event);
                            if (validator.submitButton) {
                                // And clean up afterwards; thanks to no-block-scope, hidden can be referenced
                                hidden.remove();
                            }
                            if (result !== undefined) {
                                return result;
                            }
                            return false;
                        }
                        return true;
                    }
                    // Prevent submit for invalid forms or custom submit handlers
                    if (validator.cancelSubmit) {
                        validator.cancelSubmit = false;
                        return handle();
                    }
                    if (validator.form()) {
                        if (validator.pendingRequest) {
                            validator.formSubmitted = true;
                            return false;
                        }
                        return handle();
                    }
                    else {
                        validator.focusInvalid();
                        return false;
                    }
                });
            }
            return validator;
        },
        // http://jqueryvalidation.org/valid/
        valid: function () {
            var valid, validator, errorList;
            if ($(this[0]).is("form")) {
                valid = this.validate().form();
            }
            else {
                errorList = [];
                valid = true;
                validator = $(this[0].form).validate();
                this.each(function () {
                    valid = validator.element(this) && valid;
                    if (!valid) {
                        errorList = errorList.concat(validator.errorList);
                    }
                });
                validator.errorList = errorList;
            }
            return valid;
        },
        // http://jqueryvalidation.org/rules/
        rules: function (command, argument) {
            var element = this[0], settings, staticRules, existingRules, data, param, filtered;
            // If nothing is selected, return empty object; can't chain anyway
            if (element == null || element.form == null) {
                return;
            }
            if (command) {
                settings = $.data(element.form, "validator").settings;
                staticRules = settings.rules;
                existingRules = $.validator.staticRules(element);
                switch (command) {
                    case "add":
                        $.extend(existingRules, $.validator.normalizeRule(argument));
                        // Remove messages from rules, but allow them to be set separately
                        delete existingRules.messages;
                        staticRules[element.name] = existingRules;
                        if (argument.messages) {
                            settings.messages[element.name] = $.extend(settings.messages[element.name], argument.messages);
                        }
                        break;
                    case "remove":
                        if (!argument) {
                            delete staticRules[element.name];
                            return existingRules;
                        }
                        filtered = {};
                        $.each(argument.split(/\s/), function (index, method) {
                            filtered[method] = existingRules[method];
                            delete existingRules[method];
                            if (method === "required") {
                                $(element).removeAttr("aria-required");
                            }
                        });
                        return filtered;
                }
            }
            data = $.validator.normalizeRules($.extend({}, $.validator.classRules(element), $.validator.attributeRules(element), $.validator.dataRules(element), $.validator.staticRules(element)), element);
            // Make sure required is at front
            if (data.required) {
                param = data.required;
                delete data.required;
                data = $.extend({ required: param }, data);
                $(element).attr("aria-required", "true");
            }
            // Make sure remote is at back
            if (data.remote) {
                param = data.remote;
                delete data.remote;
                data = $.extend(data, { remote: param });
            }
            return data;
        }
    });
    // Custom selectors
    $.extend($.expr.pseudos || $.expr[":"], {
        // http://jqueryvalidation.org/blank-selector/
        blank: function (a) {
            return !$.trim("" + $(a).val());
        },
        // http://jqueryvalidation.org/filled-selector/
        filled: function (a) {
            var val = $(a).val();
            return val !== null && !!$.trim("" + val);
        },
        // http://jqueryvalidation.org/unchecked-selector/
        unchecked: function (a) {
            return !$(a).prop("checked");
        }
    });
    // Constructor for validator
    $.validator = function (options, form) {
        this.settings = $.extend(true, {}, $.validator.defaults, options);
        this.currentForm = form;
        this.init();
    };
    // http://jqueryvalidation.org/jQuery.validator.format/
    $.validator.format = function (source, params) {
        if (arguments.length === 1) {
            return function () {
                var args = $.makeArray(arguments);
                args.unshift(source);
                return $.validator.format.apply(this, args);
            };
        }
        if (params === undefined) {
            return source;
        }
        if (arguments.length > 2 && params.constructor !== Array) {
            params = $.makeArray(arguments).slice(1);
        }
        if (params.constructor !== Array) {
            params = [params];
        }
        $.each(params, function (i, n) {
            source = source.replace(new RegExp("\\{" + i + "\\}", "g"), function () {
                return n;
            });
        });
        return source;
    };
    $.extend($.validator, {
        defaults: {
            messages: {},
            groups: {},
            rules: {},
            errorClass: "error",
            pendingClass: "pending",
            validClass: "valid",
            errorElement: "label",
            focusCleanup: false,
            focusInvalid: true,
            errorContainer: $([]),
            errorLabelContainer: $([]),
            onsubmit: true,
            ignore: ":hidden",
            ignoreTitle: false,
            onfocusin: function (element) {
                this.lastActive = element;
                // Hide error label and remove error class on focus if enabled
                if (this.settings.focusCleanup) {
                    if (this.settings.unhighlight) {
                        this.settings.unhighlight.call(this, element, this.settings.errorClass, this.settings.validClass);
                    }
                    this.hideThese(this.errorsFor(element));
                }
            },
            onfocusout: function (element) {
                if (!this.checkable(element) && (element.name in this.submitted || !this.optional(element))) {
                    this.element(element);
                }
            },
            onkeyup: function (element, event) {
                // Avoid revalidate the field when pressing one of the following keys
                // Shift       => 16
                // Ctrl        => 17
                // Alt         => 18
                // Caps lock   => 20
                // End         => 35
                // Home        => 36
                // Left arrow  => 37
                // Up arrow    => 38
                // Right arrow => 39
                // Down arrow  => 40
                // Insert      => 45
                // Num lock    => 144
                // AltGr key   => 225
                var excludedKeys = [
                    16, 17, 18, 20, 35, 36, 37,
                    38, 39, 40, 45, 144, 225
                ];
                if (event.which === 9 && this.elementValue(element) === "" || $.inArray(event.keyCode, excludedKeys) !== -1) {
                    return;
                }
                else if (element.name in this.submitted || element.name in this.invalid) {
                    this.element(element);
                }
            },
            onclick: function (element) {
                // Click on selects, radiobuttons and checkboxes
                if (element.name in this.submitted) {
                    this.element(element);
                }
                else if (element.parentNode.name in this.submitted) {
                    this.element(element.parentNode);
                }
            },
            highlight: function (element, errorClass, validClass) {
                if (element.type === "radio") {
                    this.findByName(element.name).addClass(errorClass).removeClass(validClass);
                }
                else {
                    $(element).addClass(errorClass).removeClass(validClass);
                }
            },
            unhighlight: function (element, errorClass, validClass) {
                if (element.type === "radio") {
                    this.findByName(element.name).removeClass(errorClass).addClass(validClass);
                }
                else {
                    $(element).removeClass(errorClass).addClass(validClass);
                }
            }
        },
        // http://jqueryvalidation.org/jQuery.validator.setDefaults/
        setDefaults: function (settings) {
            $.extend($.validator.defaults, settings);
        },
        messages: {
            required: "This field is required.",
            remote: "Please fix this field.",
            email: "Please enter a valid email address.",
            url: "Please enter a valid URL.",
            date: "Please enter a valid date.",
            dateISO: "Please enter a valid date (ISO).",
            number: "Please enter a valid number.",
            digits: "Please enter only digits.",
            equalTo: "Please enter the same value again.",
            maxlength: $.validator.format("Please enter no more than {0} characters."),
            minlength: $.validator.format("Please enter at least {0} characters."),
            rangelength: $.validator.format("Please enter a value between {0} and {1} characters long."),
            range: $.validator.format("Please enter a value between {0} and {1}."),
            max: $.validator.format("Please enter a value less than or equal to {0}."),
            min: $.validator.format("Please enter a value greater than or equal to {0}."),
            step: $.validator.format("Please enter a multiple of {0}.")
        },
        autoCreateRanges: false,
        prototype: {
            init: function () {
                this.labelContainer = $(this.settings.errorLabelContainer);
                this.errorContext = this.labelContainer.length && this.labelContainer || $(this.currentForm);
                this.containers = $(this.settings.errorContainer).add(this.settings.errorLabelContainer);
                this.submitted = {};
                this.valueCache = {};
                this.pendingRequest = 0;
                this.pending = {};
                this.invalid = {};
                this.reset();
                var groups = (this.groups = {}), rules;
                $.each(this.settings.groups, function (key, value) {
                    if (typeof value === "string") {
                        value = value.split(/\s/);
                    }
                    $.each(value, function (index, name) {
                        groups[name] = key;
                    });
                });
                rules = this.settings.rules;
                $.each(rules, function (key, value) {
                    rules[key] = $.validator.normalizeRule(value);
                });
                function delegate(event) {
                    // Set form expando on contenteditable
                    if (!this.form && this.hasAttribute("contenteditable")) {
                        this.form = $(this).closest("form")[0];
                    }
                    var validator = $.data(this.form, "validator"), eventType = "on" + event.type.replace(/^validate/, ""), settings = validator.settings;
                    if (settings[eventType] && !$(this).is(settings.ignore)) {
                        settings[eventType].call(validator, this, event);
                    }
                }
                $(this.currentForm)
                    .on("focusin.validate focusout.validate keyup.validate", ":text, [type='password'], [type='file'], select, textarea, [type='number'], [type='search'], " +
                    "[type='tel'], [type='url'], [type='email'], [type='datetime'], [type='date'], [type='month'], " +
                    "[type='week'], [type='time'], [type='datetime-local'], [type='range'], [type='color'], " +
                    "[type='radio'], [type='checkbox'], [contenteditable], [type='button']", delegate)
                    .on("click.validate", "select, option, [type='radio'], [type='checkbox']", delegate);
                if (this.settings.invalidHandler) {
                    $(this.currentForm).on("invalid-form.validate", this.settings.invalidHandler);
                }
                // Add aria-required to any Static/Data/Class required fields before first validation
                // Screen readers require this attribute to be present before the initial submission http://www.w3.org/TR/WCAG-TECHS/ARIA2.html
                $(this.currentForm).find("[required], [data-rule-required], .required").attr("aria-required", "true");
            },
            // http://jqueryvalidation.org/Validator.form/
            form: function () {
                this.checkForm();
                $.extend(this.submitted, this.errorMap);
                this.invalid = $.extend({}, this.errorMap);
                if (!this.valid()) {
                    $(this.currentForm).triggerHandler("invalid-form", [this]);
                }
                this.showErrors();
                return this.valid();
            },
            checkForm: function () {
                this.prepareForm();
                for (var i = 0, elements = (this.currentElements = this.elements()); elements[i]; i++) {
                    this.check(elements[i]);
                }
                return this.valid();
            },
            // http://jqueryvalidation.org/Validator.element/
            element: function (element) {
                var cleanElement = this.clean(element), checkElement = this.validationTargetFor(cleanElement), v = this, result = true, rs, group;
                if (checkElement === undefined) {
                    delete this.invalid[cleanElement.name];
                }
                else {
                    this.prepareElement(checkElement);
                    this.currentElements = $(checkElement);
                    // If this element is grouped, then validate all group elements already
                    // containing a value
                    group = this.groups[checkElement.name];
                    if (group) {
                        $.each(this.groups, function (name, testgroup) {
                            if (testgroup === group && name !== checkElement.name) {
                                cleanElement = v.validationTargetFor(v.clean(v.findByName(name)));
                                if (cleanElement && cleanElement.name in v.invalid) {
                                    v.currentElements.push(cleanElement);
                                    result = v.check(cleanElement) && result;
                                }
                            }
                        });
                    }
                    rs = this.check(checkElement) !== false;
                    result = result && rs;
                    if (rs) {
                        this.invalid[checkElement.name] = false;
                    }
                    else {
                        this.invalid[checkElement.name] = true;
                    }
                    if (!this.numberOfInvalids()) {
                        // Hide error containers on last error
                        this.toHide = this.toHide.add(this.containers);
                    }
                    this.showErrors();
                    // Add aria-invalid status for screen readers
                    $(element).attr("aria-invalid", !rs);
                }
                return result;
            },
            // http://jqueryvalidation.org/Validator.showErrors/
            showErrors: function (errors) {
                if (errors) {
                    var validator = this;
                    // Add items to error list and map
                    $.extend(this.errorMap, errors);
                    this.errorList = $.map(this.errorMap, function (message, name) {
                        return {
                            message: message,
                            element: validator.findByName(name)[0]
                        };
                    });
                    // Remove items from success list
                    this.successList = $.grep(this.successList, function (element) {
                        return !(element.name in errors);
                    });
                }
                if (this.settings.showErrors) {
                    this.settings.showErrors.call(this, this.errorMap, this.errorList);
                }
                else {
                    this.defaultShowErrors();
                }
            },
            // http://jqueryvalidation.org/Validator.resetForm/
            resetForm: function () {
                if ($.fn.resetForm) {
                    $(this.currentForm).resetForm();
                }
                this.invalid = {};
                this.submitted = {};
                this.prepareForm();
                this.hideErrors();
                var elements = this.elements()
                    .removeData("previousValue")
                    .removeAttr("aria-invalid");
                this.resetElements(elements);
            },
            resetElements: function (elements) {
                var i;
                if (this.settings.unhighlight) {
                    for (i = 0; elements[i]; i++) {
                        this.settings.unhighlight.call(this, elements[i], this.settings.errorClass, "");
                        this.findByName(elements[i].name).removeClass(this.settings.validClass);
                    }
                }
                else {
                    elements
                        .removeClass(this.settings.errorClass)
                        .removeClass(this.settings.validClass);
                }
            },
            numberOfInvalids: function () {
                return this.objectLength(this.invalid);
            },
            objectLength: function (obj) {
                /* jshint unused: false */
                var count = 0, i;
                for (i in obj) {
                    if (obj[i]) {
                        count++;
                    }
                }
                return count;
            },
            hideErrors: function () {
                this.hideThese(this.toHide);
            },
            hideThese: function (errors) {
                errors.not(this.containers).text("");
                this.addWrapper(errors).hide();
            },
            valid: function () {
                return this.size() === 0;
            },
            size: function () {
                return this.errorList.length;
            },
            focusInvalid: function () {
                if (this.settings.focusInvalid) {
                    try {
                        $(this.findLastActive() || this.errorList.length && this.errorList[0].element || [])
                            .filter(":visible")
                            .focus()
                            .trigger("focusin");
                    }
                    catch (e) {
                    }
                }
            },
            findLastActive: function () {
                var lastActive = this.lastActive;
                return lastActive && $.grep(this.errorList, function (n) {
                    return n.element.name === lastActive.name;
                }).length === 1 && lastActive;
            },
            elements: function () {
                var validator = this, rulesCache = {};
                // Select all valid inputs inside the form (no submit or reset buttons)
                return $(this.currentForm)
                    .find("input, select, textarea, [contenteditable]")
                    .not(":submit, :reset, :image, :disabled")
                    .not(this.settings.ignore)
                    .filter(function () {
                    var name = this.name || $(this).attr("name"); // For contenteditable
                    if (!name && validator.settings.debug && window.console) {
                        console.error("%o has no name assigned", this);
                    }
                    // Set form expando on contenteditable
                    if (this.hasAttribute("contenteditable")) {
                        this.form = $(this).closest("form")[0];
                    }
                    // Select only the first element for each name, and only those with rules specified
                    if (name in rulesCache || !validator.objectLength($(this).rules())) {
                        return false;
                    }
                    rulesCache[name] = true;
                    return true;
                });
            },
            clean: function (selector) {
                return $(selector)[0];
            },
            errors: function () {
                var errorClass = this.settings.errorClass.split(" ").join(".");
                return $(this.settings.errorElement + "." + errorClass, this.errorContext);
            },
            resetInternals: function () {
                this.successList = [];
                this.errorList = [];
                this.errorMap = {};
                this.toShow = $([]);
                this.toHide = $([]);
            },
            reset: function () {
                this.resetInternals();
                this.currentElements = $([]);
            },
            prepareForm: function () {
                this.reset();
                this.toHide = this.errors().add(this.containers);
            },
            prepareElement: function (element) {
                this.reset();
                this.toHide = this.errorsFor(element);
            },
            elementValue: function (element) {
                var $element = $(element), type = element.type, val, idx;
                if (type === "radio" || type === "checkbox") {
                    return this.findByName(element.name).filter(":checked").val();
                }
                else if (type === "number" && typeof element.validity !== "undefined") {
                    return element.validity.badInput ? "NaN" : $element.val();
                }
                if (element.hasAttribute("contenteditable")) {
                    val = $element.text();
                }
                else {
                    val = $element.val();
                }
                if (type === "file") {
                    // Modern browser (chrome & safari)
                    if (val.substr(0, 12) === "C:\\fakepath\\") {
                        return val.substr(12);
                    }
                    // Legacy browsers
                    // Unix-based path
                    idx = val.lastIndexOf("/");
                    if (idx >= 0) {
                        return val.substr(idx + 1);
                    }
                    // Windows-based path
                    idx = val.lastIndexOf("\\");
                    if (idx >= 0) {
                        return val.substr(idx + 1);
                    }
                    // Just the file name
                    return val;
                }
                if (typeof val === "string") {
                    return val.replace(/\r/g, "");
                }
                return val;
            },
            check: function (element) {
                element = this.validationTargetFor(this.clean(element));
                var rules = $(element).rules(), rulesCount = $.map(rules, function (n, i) {
                    return i;
                }).length, dependencyMismatch = false, val = this.elementValue(element), result, method, rule;
                // If a normalizer is defined for this element, then
                // call it to retreive the changed value instead
                // of using the real one.
                // Note that `this` in the normalizer is `element`.
                if (typeof rules.normalizer === "function") {
                    val = rules.normalizer.call(element, val);
                    if (typeof val !== "string") {
                        throw new TypeError("The normalizer should return a string value.");
                    }
                    // Delete the normalizer from rules to avoid treating
                    // it as a pre-defined method.
                    delete rules.normalizer;
                }
                for (method in rules) {
                    rule = { method: method, parameters: rules[method] };
                    try {
                        result = $.validator.methods[method].call(this, val, element, rule.parameters);
                        // If a method indicates that the field is optional and therefore valid,
                        // don't mark it as valid when there are no other rules
                        if (result === "dependency-mismatch" && rulesCount === 1) {
                            dependencyMismatch = true;
                            continue;
                        }
                        dependencyMismatch = false;
                        if (result === "pending") {
                            this.toHide = this.toHide.not(this.errorsFor(element));
                            return;
                        }
                        if (!result) {
                            this.formatAndAdd(element, rule);
                            return false;
                        }
                    }
                    catch (e) {
                        if (this.settings.debug && window.console) {
                            console.log("Exception occurred when checking element " + element.id + ", check the '" + rule.method + "' method.", e);
                        }
                        if (e instanceof TypeError) {
                            e.message += ".  Exception occurred when checking element " + element.id + ", check the '" + rule.method + "' method.";
                        }
                        throw e;
                    }
                }
                if (dependencyMismatch) {
                    return;
                }
                if (this.objectLength(rules)) {
                    this.successList.push(element);
                }
                return true;
            },
            // Return the custom message for the given element and validation method
            // specified in the element's HTML5 data attribute
            // return the generic message if present and no method specific message is present
            customDataMessage: function (element, method) {
                return $(element).data("msg" + method.charAt(0).toUpperCase() +
                    method.substring(1).toLowerCase()) || $(element).data("msg");
            },
            // Return the custom message for the given element name and validation method
            customMessage: function (name, method) {
                var m = this.settings.messages[name];
                return m && (m.constructor === String ? m : m[method]);
            },
            // Return the first defined argument, allowing empty strings
            findDefined: function () {
                for (var i = 0; i < arguments.length; i++) {
                    if (arguments[i] !== undefined) {
                        return arguments[i];
                    }
                }
                return undefined;
            },
            // The second parameter 'rule' used to be a string, and extended to an object literal
            // of the following form:
            // rule = {
            //     method: "method name",
            //     parameters: "the given method parameters"
            // }
            //
            // The old behavior still supported, kept to maintain backward compatibility with
            // old code, and will be removed in the next major release.
            defaultMessage: function (element, rule) {
                if (typeof rule === "string") {
                    rule = { method: rule };
                }
                var message = this.findDefined(this.customMessage(element.name, rule.method), this.customDataMessage(element, rule.method), 
                // 'title' is never undefined, so handle empty string as undefined
                !this.settings.ignoreTitle && element.title || undefined, $.validator.messages[rule.method], "<strong>Warning: No message defined for " + element.name + "</strong>"), theregex = /\$?\{(\d+)\}/g;
                if (typeof message === "function") {
                    message = message.call(this, rule.parameters, element);
                }
                else if (theregex.test(message)) {
                    message = $.validator.format(message.replace(theregex, "{$1}"), rule.parameters);
                }
                return message;
            },
            formatAndAdd: function (element, rule) {
                var message = this.defaultMessage(element, rule);
                this.errorList.push({
                    message: message,
                    element: element,
                    method: rule.method
                });
                this.errorMap[element.name] = message;
                this.submitted[element.name] = message;
            },
            addWrapper: function (toToggle) {
                if (this.settings.wrapper) {
                    toToggle = toToggle.add(toToggle.parent(this.settings.wrapper));
                }
                return toToggle;
            },
            defaultShowErrors: function () {
                var i, elements, error;
                for (i = 0; this.errorList[i]; i++) {
                    error = this.errorList[i];
                    if (this.settings.highlight) {
                        this.settings.highlight.call(this, error.element, this.settings.errorClass, this.settings.validClass);
                    }
                    this.showLabel(error.element, error.message);
                }
                if (this.errorList.length) {
                    this.toShow = this.toShow.add(this.containers);
                }
                if (this.settings.success) {
                    for (i = 0; this.successList[i]; i++) {
                        this.showLabel(this.successList[i]);
                    }
                }
                if (this.settings.unhighlight) {
                    for (i = 0, elements = this.validElements(); elements[i]; i++) {
                        this.settings.unhighlight.call(this, elements[i], this.settings.errorClass, this.settings.validClass);
                    }
                }
                this.toHide = this.toHide.not(this.toShow);
                this.hideErrors();
                this.addWrapper(this.toShow).show();
            },
            validElements: function () {
                return this.currentElements.not(this.invalidElements());
            },
            invalidElements: function () {
                return $(this.errorList).map(function () {
                    return this.element;
                });
            },
            showLabel: function (element, message) {
                var place, group, errorID, v, error = this.errorsFor(element), elementID = this.idOrName(element), describedBy = $(element).attr("aria-describedby");
                if (error.length) {
                    // Refresh error/success class
                    error.removeClass(this.settings.validClass).addClass(this.settings.errorClass);
                    // Replace message on existing label
                    error.html(message);
                }
                else {
                    // Create error element
                    error = $("<" + this.settings.errorElement + ">")
                        .attr("id", elementID + "-error")
                        .addClass(this.settings.errorClass)
                        .html(message || "");
                    // Maintain reference to the element to be placed into the DOM
                    place = error;
                    if (this.settings.wrapper) {
                        // Make sure the element is visible, even in IE
                        // actually showing the wrapped element is handled elsewhere
                        place = error.hide().show().wrap("<" + this.settings.wrapper + "/>").parent();
                    }
                    if (this.labelContainer.length) {
                        this.labelContainer.append(place);
                    }
                    else if (this.settings.errorPlacement) {
                        this.settings.errorPlacement.call(this, place, $(element));
                    }
                    else {
                        place.insertAfter(element);
                    }
                    // Link error back to the element
                    if (error.is("label")) {
                        // If the error is a label, then associate using 'for'
                        error.attr("for", elementID);
                    }
                    else if (error.parents("label[for='" + this.escapeCssMeta(elementID) + "']").length === 0) {
                        errorID = error.attr("id");
                        // Respect existing non-error aria-describedby
                        if (!describedBy) {
                            describedBy = errorID;
                        }
                        else if (!describedBy.match(new RegExp("\\b" + this.escapeCssMeta(errorID) + "\\b"))) {
                            // Add to end of list if not already present
                            describedBy += " " + errorID;
                        }
                        $(element).attr("aria-describedby", describedBy);
                        // If this element is grouped, then assign to all elements in the same group
                        group = this.groups[element.name];
                        if (group) {
                            v = this;
                            $.each(v.groups, function (name, testgroup) {
                                if (testgroup === group) {
                                    $("[name='" + v.escapeCssMeta(name) + "']", v.currentForm)
                                        .attr("aria-describedby", error.attr("id"));
                                }
                            });
                        }
                    }
                }
                if (!message && this.settings.success) {
                    error.text("");
                    if (typeof this.settings.success === "string") {
                        error.addClass(this.settings.success);
                    }
                    else {
                        this.settings.success(error, element);
                    }
                }
                this.toShow = this.toShow.add(error);
            },
            errorsFor: function (element) {
                var name = this.escapeCssMeta(this.idOrName(element)), describer = $(element).attr("aria-describedby"), selector = "label[for='" + name + "'], label[for='" + name + "'] *";
                // 'aria-describedby' should directly reference the error element
                if (describer) {
                    selector = selector + ", #" + this.escapeCssMeta(describer)
                        .replace(/\s+/g, ", #");
                }
                return this
                    .errors()
                    .filter(selector);
            },
            // See https://api.jquery.com/category/selectors/, for CSS
            // meta-characters that should be escaped in order to be used with JQuery
            // as a literal part of a name/id or any selector.
            escapeCssMeta: function (string) {
                return string.replace(/([\\!"#$%&'()*+,./:;<=>?@\[\]^`{|}~])/g, "\\$1");
            },
            idOrName: function (element) {
                return this.groups[element.name] || (this.checkable(element) ? element.name : element.id || element.name);
            },
            validationTargetFor: function (element) {
                // If radio/checkbox, validate first element in group instead
                if (this.checkable(element)) {
                    element = this.findByName(element.name);
                }
                // Always apply ignore filter
                return $(element).not(this.settings.ignore)[0];
            },
            checkable: function (element) {
                return (/radio|checkbox/i).test(element.type);
            },
            findByName: function (name) {
                return $(this.currentForm).find("[name='" + this.escapeCssMeta(name) + "']");
            },
            getLength: function (value, element) {
                switch (element.nodeName.toLowerCase()) {
                    case "select":
                        return $("option:selected", element).length;
                    case "input":
                        if (this.checkable(element)) {
                            return this.findByName(element.name).filter(":checked").length;
                        }
                }
                return value.length;
            },
            depend: function (param, element) {
                return this.dependTypes[typeof param] ? this.dependTypes[typeof param](param, element) : true;
            },
            dependTypes: {
                "boolean": function (param) {
                    return param;
                },
                "string": function (param, element) {
                    return !!$(param, element.form).length;
                },
                "function": function (param, element) {
                    return param(element);
                }
            },
            optional: function (element) {
                var val = this.elementValue(element);
                return !$.validator.methods.required.call(this, val, element) && "dependency-mismatch";
            },
            startRequest: function (element) {
                if (!this.pending[element.name]) {
                    this.pendingRequest++;
                    $(element).addClass(this.settings.pendingClass);
                    this.pending[element.name] = true;
                }
            },
            stopRequest: function (element, valid) {
                this.pendingRequest--;
                // Sometimes synchronization fails, make sure pendingRequest is never < 0
                if (this.pendingRequest < 0) {
                    this.pendingRequest = 0;
                }
                delete this.pending[element.name];
                $(element).removeClass(this.settings.pendingClass);
                if (valid && this.pendingRequest === 0 && this.formSubmitted && this.form()) {
                    $(this.currentForm).submit();
                    this.formSubmitted = false;
                }
                else if (!valid && this.pendingRequest === 0 && this.formSubmitted) {
                    $(this.currentForm).triggerHandler("invalid-form", [this]);
                    this.formSubmitted = false;
                }
            },
            previousValue: function (element, method) {
                method = typeof method === "string" && method || "remote";
                return $.data(element, "previousValue") || $.data(element, "previousValue", {
                    old: null,
                    valid: true,
                    message: this.defaultMessage(element, { method: method })
                });
            },
            // Cleans up all forms and elements, removes validator-specific events
            destroy: function () {
                this.resetForm();
                $(this.currentForm)
                    .off(".validate")
                    .removeData("validator")
                    .find(".validate-equalTo-blur")
                    .off(".validate-equalTo")
                    .removeClass("validate-equalTo-blur");
            }
        },
        classRuleSettings: {
            required: { required: true },
            email: { email: true },
            url: { url: true },
            date: { date: true },
            dateISO: { dateISO: true },
            number: { number: true },
            digits: { digits: true },
            creditcard: { creditcard: true }
        },
        addClassRules: function (className, rules) {
            if (className.constructor === String) {
                this.classRuleSettings[className] = rules;
            }
            else {
                $.extend(this.classRuleSettings, className);
            }
        },
        classRules: function (element) {
            var rules = {}, classes = $(element).attr("class");
            if (classes) {
                $.each(classes.split(" "), function () {
                    if (this in $.validator.classRuleSettings) {
                        $.extend(rules, $.validator.classRuleSettings[this]);
                    }
                });
            }
            return rules;
        },
        normalizeAttributeRule: function (rules, type, method, value) {
            // Convert the value to a number for number inputs, and for text for backwards compability
            // allows type="date" and others to be compared as strings
            if (/min|max|step/.test(method) && (type === null || /number|range|text/.test(type))) {
                value = Number(value);
                // Support Opera Mini, which returns NaN for undefined minlength
                if (isNaN(value)) {
                    value = undefined;
                }
            }
            if (value || value === 0) {
                rules[method] = value;
            }
            else if (type === method && type !== "range") {
                // Exception: the jquery validate 'range' method
                // does not test for the html5 'range' type
                rules[method] = true;
            }
        },
        attributeRules: function (element) {
            var rules = {}, $element = $(element), type = element.getAttribute("type"), method, value;
            for (method in $.validator.methods) {
                // Support for <input required> in both html5 and older browsers
                if (method === "required") {
                    value = element.getAttribute(method);
                    // Some browsers return an empty string for the required attribute
                    // and non-HTML5 browsers might have required="" markup
                    if (value === "") {
                        value = true;
                    }
                    // Force non-HTML5 browsers to return bool
                    value = !!value;
                }
                else {
                    value = $element.attr(method);
                }
                this.normalizeAttributeRule(rules, type, method, value);
            }
            // 'maxlength' may be returned as -1, 2147483647 ( IE ) and 524288 ( safari ) for text inputs
            if (rules.maxlength && /-1|2147483647|524288/.test(rules.maxlength)) {
                delete rules.maxlength;
            }
            return rules;
        },
        dataRules: function (element) {
            var rules = {}, $element = $(element), type = element.getAttribute("type"), method, value;
            for (method in $.validator.methods) {
                value = $element.data("rule" + method.charAt(0).toUpperCase() + method.substring(1).toLowerCase());
                this.normalizeAttributeRule(rules, type, method, value);
            }
            return rules;
        },
        staticRules: function (element) {
            var rules = {}, validator = $.data(element.form, "validator");
            if (validator.settings.rules) {
                rules = $.validator.normalizeRule(validator.settings.rules[element.name]) || {};
            }
            return rules;
        },
        normalizeRules: function (rules, element) {
            // Handle dependency check
            $.each(rules, function (prop, val) {
                // Ignore rule when param is explicitly false, eg. required:false
                if (val === false) {
                    delete rules[prop];
                    return;
                }
                if (val.param || val.depends) {
                    var keepRule = true;
                    switch (typeof val.depends) {
                        case "string":
                            keepRule = !!$(val.depends, element.form).length;
                            break;
                        case "function":
                            keepRule = val.depends.call(element, element);
                            break;
                    }
                    if (keepRule) {
                        rules[prop] = val.param !== undefined ? val.param : true;
                    }
                    else {
                        $.data(element.form, "validator").resetElements($(element));
                        delete rules[prop];
                    }
                }
            });
            // Evaluate parameters
            $.each(rules, function (rule, parameter) {
                rules[rule] = $.isFunction(parameter) && rule !== "normalizer" ? parameter(element) : parameter;
            });
            // Clean number parameters
            $.each(["minlength", "maxlength"], function () {
                if (rules[this]) {
                    rules[this] = Number(rules[this]);
                }
            });
            $.each(["rangelength", "range"], function () {
                var parts;
                if (rules[this]) {
                    if ($.isArray(rules[this])) {
                        rules[this] = [Number(rules[this][0]), Number(rules[this][1])];
                    }
                    else if (typeof rules[this] === "string") {
                        parts = rules[this].replace(/[\[\]]/g, "").split(/[\s,]+/);
                        rules[this] = [Number(parts[0]), Number(parts[1])];
                    }
                }
            });
            if ($.validator.autoCreateRanges) {
                // Auto-create ranges
                if (rules.min != null && rules.max != null) {
                    rules.range = [rules.min, rules.max];
                    delete rules.min;
                    delete rules.max;
                }
                if (rules.minlength != null && rules.maxlength != null) {
                    rules.rangelength = [rules.minlength, rules.maxlength];
                    delete rules.minlength;
                    delete rules.maxlength;
                }
            }
            return rules;
        },
        // Converts a simple string to a {string: true} rule, e.g., "required" to {required:true}
        normalizeRule: function (data) {
            if (typeof data === "string") {
                var transformed = {};
                $.each(data.split(/\s/), function () {
                    transformed[this] = true;
                });
                data = transformed;
            }
            return data;
        },
        // http://jqueryvalidation.org/jQuery.validator.addMethod/
        addMethod: function (name, method, message) {
            $.validator.methods[name] = method;
            $.validator.messages[name] = message !== undefined ? message : $.validator.messages[name];
            if (method.length < 3) {
                $.validator.addClassRules(name, $.validator.normalizeRule(name));
            }
        },
        // http://jqueryvalidation.org/jQuery.validator.methods/
        methods: {
            // http://jqueryvalidation.org/required-method/
            required: function (value, element, param) {
                // Check if dependency is met
                if (!this.depend(param, element)) {
                    return "dependency-mismatch";
                }
                if (element.nodeName.toLowerCase() === "select") {
                    // Could be an array for select-multiple or a string, both are fine this way
                    var val = $(element).val();
                    return val && val.length > 0;
                }
                if (this.checkable(element)) {
                    return this.getLength(value, element) > 0;
                }
                return value.length > 0;
            },
            // http://jqueryvalidation.org/email-method/
            email: function (value, element) {
                // From https://html.spec.whatwg.org/multipage/forms.html#valid-e-mail-address
                // Retrieved 2014-01-14
                // If you have a problem with this implementation, report a bug against the above spec
                // Or use custom methods to implement your own email validation
                return this.optional(element) || /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/.test(value);
            },
            // http://jqueryvalidation.org/url-method/
            url: function (value, element) {
                // Copyright (c) 2010-2013 Diego Perini, MIT licensed
                // https://gist.github.com/dperini/729294
                // see also https://mathiasbynens.be/demo/url-regex
                // modified to allow protocol-relative URLs
                return this.optional(element) || /^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})).?)(?::\d{2,5})?(?:[/?#]\S*)?$/i.test(value);
            },
            // http://jqueryvalidation.org/date-method/
            date: function (value, element) {
                return this.optional(element) || !/Invalid|NaN/.test(new Date(value).toString());
            },
            // http://jqueryvalidation.org/dateISO-method/
            dateISO: function (value, element) {
                return this.optional(element) || /^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$/.test(value);
            },
            // http://jqueryvalidation.org/number-method/
            number: function (value, element) {
                return this.optional(element) || /^(?:-?\d+|-?\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test(value);
            },
            // http://jqueryvalidation.org/digits-method/
            digits: function (value, element) {
                return this.optional(element) || /^\d+$/.test(value);
            },
            // http://jqueryvalidation.org/minlength-method/
            minlength: function (value, element, param) {
                var length = $.isArray(value) ? value.length : this.getLength(value, element);
                return this.optional(element) || length >= param;
            },
            // http://jqueryvalidation.org/maxlength-method/
            maxlength: function (value, element, param) {
                var length = $.isArray(value) ? value.length : this.getLength(value, element);
                return this.optional(element) || length <= param;
            },
            // http://jqueryvalidation.org/rangelength-method/
            rangelength: function (value, element, param) {
                var length = $.isArray(value) ? value.length : this.getLength(value, element);
                return this.optional(element) || (length >= param[0] && length <= param[1]);
            },
            // http://jqueryvalidation.org/min-method/
            min: function (value, element, param) {
                return this.optional(element) || value >= param;
            },
            // http://jqueryvalidation.org/max-method/
            max: function (value, element, param) {
                return this.optional(element) || value <= param;
            },
            // http://jqueryvalidation.org/range-method/
            range: function (value, element, param) {
                return this.optional(element) || (value >= param[0] && value <= param[1]);
            },
            // http://jqueryvalidation.org/step-method/
            step: function (value, element, param) {
                var type = $(element).attr("type"), errorMessage = "Step attribute on input type " + type + " is not supported.", supportedTypes = ["text", "number", "range"], re = new RegExp("\\b" + type + "\\b"), notSupported = type && !re.test(supportedTypes.join()), decimalPlaces = function (num) {
                    var match = ("" + num).match(/(?:\.(\d+))?$/);
                    if (!match) {
                        return 0;
                    }
                    // Number of digits right of decimal point.
                    return match[1] ? match[1].length : 0;
                }, toInt = function (num) {
                    return Math.round(num * Math.pow(10, decimals));
                }, valid = true, decimals;
                // Works only for text, number and range input types
                // TODO find a way to support input types date, datetime, datetime-local, month, time and week
                if (notSupported) {
                    throw new Error(errorMessage);
                }
                decimals = decimalPlaces(param);
                // Value can't have too many decimals
                if (decimalPlaces(value) > decimals || toInt(value) % toInt(param) !== 0) {
                    valid = false;
                }
                return this.optional(element) || valid;
            },
            // http://jqueryvalidation.org/equalTo-method/
            equalTo: function (value, element, param) {
                // Bind to the blur event of the target in order to revalidate whenever the target field is updated
                var target = $(param);
                if (this.settings.onfocusout && target.not(".validate-equalTo-blur").length) {
                    target.addClass("validate-equalTo-blur").on("blur.validate-equalTo", function () {
                        $(element).valid();
                    });
                }
                return value === target.val();
            },
            // http://jqueryvalidation.org/remote-method/
            remote: function (value, element, param, method) {
                if (this.optional(element)) {
                    return "dependency-mismatch";
                }
                method = typeof method === "string" && method || "remote";
                var previous = this.previousValue(element, method), validator, data, optionDataString;
                if (!this.settings.messages[element.name]) {
                    this.settings.messages[element.name] = {};
                }
                previous.originalMessage = previous.originalMessage || this.settings.messages[element.name][method];
                this.settings.messages[element.name][method] = previous.message;
                param = typeof param === "string" && { url: param } || param;
                optionDataString = $.param($.extend({ data: value }, param.data));
                if (previous.old === optionDataString) {
                    return previous.valid;
                }
                previous.old = optionDataString;
                validator = this;
                this.startRequest(element);
                data = {};
                data[element.name] = value;
                $.ajax($.extend(true, {
                    mode: "abort",
                    port: "validate" + element.name,
                    dataType: "json",
                    data: data,
                    context: validator.currentForm,
                    success: function (response) {
                        var valid = response === true || response === "true", errors, message, submitted;
                        validator.settings.messages[element.name][method] = previous.originalMessage;
                        if (valid) {
                            submitted = validator.formSubmitted;
                            validator.resetInternals();
                            validator.toHide = validator.errorsFor(element);
                            validator.formSubmitted = submitted;
                            validator.successList.push(element);
                            validator.invalid[element.name] = false;
                            validator.showErrors();
                        }
                        else {
                            errors = {};
                            message = response || validator.defaultMessage(element, { method: method, parameters: value });
                            errors[element.name] = previous.message = message;
                            validator.invalid[element.name] = true;
                            validator.showErrors(errors);
                        }
                        previous.valid = valid;
                        validator.stopRequest(element, valid);
                    }
                }, param));
                return "pending";
            }
        }
    });
    // Ajax mode: abort
    // usage: $.ajax({ mode: "abort"[, port: "uniqueport"]});
    // if mode:"abort" is used, the previous request on that port (port can be undefined) is aborted via XMLHttpRequest.abort()
    var pendingRequests = {}, ajax;
    // Use a prefilter if available (1.5+)
    if ($.ajaxPrefilter) {
        $.ajaxPrefilter(function (settings, _, xhr) {
            var port = settings.port;
            if (settings.mode === "abort") {
                if (pendingRequests[port]) {
                    pendingRequests[port].abort();
                }
                pendingRequests[port] = xhr;
            }
        });
    }
    else {
        // Proxy ajax
        ajax = $.ajax;
        $.ajax = function (settings) {
            var mode = ("mode" in settings ? settings : $.ajaxSettings).mode, port = ("port" in settings ? settings : $.ajaxSettings).port;
            if (mode === "abort") {
                if (pendingRequests[port]) {
                    pendingRequests[port].abort();
                }
                pendingRequests[port] = ajax.apply(this, arguments);
                return pendingRequests[port];
            }
            return ajax.apply(this, arguments);
        };
    }
    return $;
}));
//# sourceMappingURL=zjquery.validate.js.map 
//# sourceMappingURL=zjquery.validate.js.map 
//# sourceMappingURL=zjquery.validate.js.map 
//# sourceMappingURL=zjquery.validate.js.map 
//# sourceMappingURL=zjquery.validate.js.map 
//# sourceMappingURL=zjquery.validate.js.map 
//# sourceMappingURL=zjquery.validate.js.map;
/*!
** Unobtrusive validation support library for jQuery and jQuery Validate
** Copyright (C) Microsoft Corporation. All rights reserved.
*/
/*jslint white: true, browser: true, onevar: true, undef: true, nomen: true, eqeqeq: true, plusplus: true, bitwise: true, regexp: true, newcap: true, immed: true, strict: false */
/*global document: false, jQuery: false */
(function ($) {
    var $jQval = $.validator, adapters, data_validation = "unobtrusiveValidation";
    function setValidationValues(options, ruleName, value) {
        options.rules[ruleName] = value;
        if (options.message) {
            options.messages[ruleName] = options.message;
        }
    }
    function splitAndTrim(value) {
        return value.replace(/^\s+|\s+$/g, "").split(/\s*,\s*/g);
    }
    function escapeAttributeValue(value) {
        // As mentioned on http://api.jquery.com/category/selectors/
        return value.replace(/([!"#$%&'()*+,./:;<=>?@\[\\\]^`{|}~])/g, "\\$1");
    }
    function getModelPrefix(fieldName) {
        return fieldName.substr(0, fieldName.lastIndexOf(".") + 1);
    }
    function appendModelPrefix(value, prefix) {
        if (value.indexOf("*.") === 0) {
            value = value.replace("*.", prefix);
        }
        return value;
    }
    function onError(error, inputElement) {
        var container = $(this).find("[data-valmsg-for='" + escapeAttributeValue(inputElement[0].name) + "']"), replaceAttrValue = container.attr("data-valmsg-replace"), replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) !== false : null;
        container.removeClass("field-validation-valid").addClass("field-validation-error");
        error.data("unobtrusiveContainer", container);
        if (replace) {
            container.empty();
            error.removeClass("input-validation-error").appendTo(container);
        }
        else {
            error.hide();
        }
    }
    function onErrors(event, validator) {
        var container = $(this).find("[data-valmsg-summary=true]"), list = container.find("ul");
        if (list && list.length && validator.errorList.length) {
            list.empty();
            container.addClass("validation-summary-errors").removeClass("validation-summary-valid");
            $.each(validator.errorList, function () {
                $("<li />").html(this.message).appendTo(list);
            });
        }
    }
    function onSuccess(error) {
        var container = error.data("unobtrusiveContainer");
        if (container) {
            var replaceAttrValue = container.attr("data-valmsg-replace"), replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) : null;
            container.addClass("field-validation-valid").removeClass("field-validation-error");
            error.removeData("unobtrusiveContainer");
            if (replace) {
                container.empty();
            }
        }
    }
    function onReset(event) {
        var $form = $(this), key = '__jquery_unobtrusive_validation_form_reset';
        if ($form.data(key)) {
            return;
        }
        // Set a flag that indicates we're currently resetting the form.
        $form.data(key, true);
        try {
            $form.data("validator").resetForm();
        }
        finally {
            $form.removeData(key);
        }
        $form.find(".validation-summary-errors")
            .addClass("validation-summary-valid")
            .removeClass("validation-summary-errors");
        $form.find(".field-validation-error")
            .addClass("field-validation-valid")
            .removeClass("field-validation-error")
            .removeData("unobtrusiveContainer")
            .find(">*") // If we were using valmsg-replace, get the underlying error
            .removeData("unobtrusiveContainer");
    }
    function validationInfo(form) {
        var $form = $(form), result = $form.data(data_validation), onResetProxy = $.proxy(onReset, form), defaultOptions = $jQval.unobtrusive.options || {}, execInContext = function (name, args) {
            var func = defaultOptions[name];
            func && $.isFunction(func) && func.apply(form, args);
        };
        if (!result) {
            result = {
                options: {
                    errorClass: defaultOptions.errorClass || "input-validation-error",
                    errorElement: defaultOptions.errorElement || "span",
                    errorPlacement: function () {
                        onError.apply(form, arguments);
                        execInContext("errorPlacement", arguments);
                    },
                    invalidHandler: function () {
                        onErrors.apply(form, arguments);
                        execInContext("invalidHandler", arguments);
                    },
                    messages: {},
                    rules: {},
                    success: function () {
                        onSuccess.apply(form, arguments);
                        execInContext("success", arguments);
                    }
                },
                attachValidation: function () {
                    $form
                        .off("reset." + data_validation, onResetProxy)
                        .on("reset." + data_validation, onResetProxy)
                        .validate(this.options);
                },
                validate: function () {
                    $form.validate();
                    return $form.valid();
                }
            };
            $form.data(data_validation, result);
        }
        return result;
    }
    $jQval.unobtrusive = {
        adapters: [],
        parseElement: function (element, skipAttach) {
            /// <summary>
            /// Parses a single HTML element for unobtrusive validation attributes.
            /// </summary>
            /// <param name="element" domElement="true">The HTML element to be parsed.</param>
            /// <param name="skipAttach" type="Boolean">[Optional] true to skip attaching the
            /// validation to the form. If parsing just this single element, you should specify true.
            /// If parsing several elements, you should specify false, and manually attach the validation
            /// to the form when you are finished. The default is false.</param>
            var $element = $(element), form = $element.parents("form")[0], valInfo, rules, messages;
            if (!form) {
                return;
            }
            valInfo = validationInfo(form);
            valInfo.options.rules[element.name] = rules = {};
            valInfo.options.messages[element.name] = messages = {};
            $.each(this.adapters, function () {
                var prefix = "data-val-" + this.name, message = $element.attr(prefix), paramValues = {};
                if (message !== undefined) {
                    prefix += "-";
                    $.each(this.params, function () {
                        paramValues[this] = $element.attr(prefix + this);
                    });
                    this.adapt({
                        element: element,
                        form: form,
                        message: message,
                        params: paramValues,
                        rules: rules,
                        messages: messages
                    });
                }
            });
            $.extend(rules, { "__dummy__": true });
            if (!skipAttach) {
                valInfo.attachValidation();
            }
        },
        parse: function (selector) {
            /// <summary>
            /// Parses all the HTML elements in the specified selector. It looks for input elements decorated
            /// with the [data-val=true] attribute value and enables validation according to the data-val-*
            /// attribute values.
            /// </summary>
            /// <param name="selector" type="String">Any valid jQuery selector.</param>
            // $forms includes all forms in selector's DOM hierarchy (parent, children and self) that have at least one
            // element with data-val=true
            var $selector = $(selector), $forms = $selector.parents()
                .addBack()
                .filter("form")
                .add($selector.find("form"))
                .has("[data-val=true]");
            $selector.find("[data-val=true]").each(function () {
                $jQval.unobtrusive.parseElement(this, true);
            });
            $forms.each(function () {
                var info = validationInfo(this);
                if (info) {
                    info.attachValidation();
                }
            });
        }
    };
    adapters = $jQval.unobtrusive.adapters;
    adapters.add = function (adapterName, params, fn) {
        /// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation.</summary>
        /// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
        /// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>
        /// <param name="params" type="Array" optional="true">[Optional] An array of parameter names (strings) that will
        /// be extracted from the data-val-nnnn-mmmm HTML attributes (where nnnn is the adapter name, and
        /// mmmm is the parameter name).</param>
        /// <param name="fn" type="Function">The function to call, which adapts the values from the HTML
        /// attributes into jQuery Validate rules and/or messages.</param>
        /// <returns type="jQuery.validator.unobtrusive.adapters" />
        if (!fn) {
            fn = params;
            params = [];
        }
        this.push({ name: adapterName, params: params, adapt: fn });
        return this;
    };
    adapters.addBool = function (adapterName, ruleName) {
        /// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
        /// the jQuery Validate validation rule has no parameter values.</summary>
        /// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
        /// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>
        /// <param name="ruleName" type="String" optional="true">[Optional] The name of the jQuery Validate rule. If not provided, the value
        /// of adapterName will be used instead.</param>
        /// <returns type="jQuery.validator.unobtrusive.adapters" />
        return this.add(adapterName, function (options) {
            setValidationValues(options, ruleName || adapterName, true);
        });
    };
    adapters.addMinMax = function (adapterName, minRuleName, maxRuleName, minMaxRuleName, minAttribute, maxAttribute) {
        /// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
        /// the jQuery Validate validation has three potential rules (one for min-only, one for max-only, and
        /// one for min-and-max). The HTML parameters are expected to be named -min and -max.</summary>
        /// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
        /// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>
        /// <param name="minRuleName" type="String">The name of the jQuery Validate rule to be used when you only
        /// have a minimum value.</param>
        /// <param name="maxRuleName" type="String">The name of the jQuery Validate rule to be used when you only
        /// have a maximum value.</param>
        /// <param name="minMaxRuleName" type="String">The name of the jQuery Validate rule to be used when you
        /// have both a minimum and maximum value.</param>
        /// <param name="minAttribute" type="String" optional="true">[Optional] The name of the HTML attribute that
        /// contains the minimum value. The default is "min".</param>
        /// <param name="maxAttribute" type="String" optional="true">[Optional] The name of the HTML attribute that
        /// contains the maximum value. The default is "max".</param>
        /// <returns type="jQuery.validator.unobtrusive.adapters" />
        return this.add(adapterName, [minAttribute || "min", maxAttribute || "max"], function (options) {
            var min = options.params.min, max = options.params.max;
            if (min && max) {
                setValidationValues(options, minMaxRuleName, [min, max]);
            }
            else if (min) {
                setValidationValues(options, minRuleName, min);
            }
            else if (max) {
                setValidationValues(options, maxRuleName, max);
            }
        });
    };
    adapters.addSingleVal = function (adapterName, attribute, ruleName) {
        /// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
        /// the jQuery Validate validation rule has a single value.</summary>
        /// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
        /// in the data-val-nnnn HTML attribute(where nnnn is the adapter name).</param>
        /// <param name="attribute" type="String">[Optional] The name of the HTML attribute that contains the value.
        /// The default is "val".</param>
        /// <param name="ruleName" type="String" optional="true">[Optional] The name of the jQuery Validate rule. If not provided, the value
        /// of adapterName will be used instead.</param>
        /// <returns type="jQuery.validator.unobtrusive.adapters" />
        return this.add(adapterName, [attribute || "val"], function (options) {
            setValidationValues(options, ruleName || adapterName, options.params[attribute]);
        });
    };
    $jQval.addMethod("__dummy__", function (value, element, params) {
        return true;
    });
    $jQval.addMethod("regex", function (value, element, params) {
        var match;
        if (this.optional(element)) {
            return true;
        }
        match = new RegExp(params).exec(value);
        return (match && (match.index === 0) && (match[0].length === value.length));
    });
    $jQval.addMethod("nonalphamin", function (value, element, nonalphamin) {
        var match;
        if (nonalphamin) {
            match = value.match(/\W/g);
            match = match && match.length >= nonalphamin;
        }
        return match;
    });
    if ($jQval.methods.extension) {
        adapters.addSingleVal("accept", "mimtype");
        adapters.addSingleVal("extension", "extension");
    }
    else {
        // for backward compatibility, when the 'extension' validation method does not exist, such as with versions
        // of JQuery Validation plugin prior to 1.10, we should use the 'accept' method for
        // validating the extension, and ignore mime-type validations as they are not supported.
        adapters.addSingleVal("extension", "extension", "accept");
    }
    adapters.addSingleVal("regex", "pattern");
    adapters.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url");
    adapters.addMinMax("length", "minlength", "maxlength", "rangelength").addMinMax("range", "min", "max", "range");
    adapters.addMinMax("minlength", "minlength").addMinMax("maxlength", "minlength", "maxlength");
    adapters.add("equalto", ["other"], function (options) {
        var prefix = getModelPrefix(options.element.name), other = options.params.other, fullOtherName = appendModelPrefix(other, prefix), element = $(options.form).find(":input").filter("[name='" + escapeAttributeValue(fullOtherName) + "']")[0];
        setValidationValues(options, "equalTo", element);
    });
    adapters.add("required", function (options) {
        // jQuery Validate equates "required" with "mandatory" for checkbox elements
        if (options.element.tagName.toUpperCase() !== "INPUT" || options.element.type.toUpperCase() !== "CHECKBOX") {
            setValidationValues(options, "required", true);
        }
    });
    adapters.add("remote", ["url", "type", "additionalfields"], function (options) {
        var value = {
            url: options.params.url,
            type: options.params.type || "GET",
            data: {}
        }, prefix = getModelPrefix(options.element.name);
        $.each(splitAndTrim(options.params.additionalfields || options.element.name), function (i, fieldName) {
            var paramName = appendModelPrefix(fieldName, prefix);
            value.data[paramName] = function () {
                var field = $(options.form).find(":input").filter("[name='" + escapeAttributeValue(paramName) + "']");
                // For checkboxes and radio buttons, only pick up values from checked fields.
                if (field.is(":checkbox")) {
                    return field.filter(":checked").val() || field.filter(":hidden").val() || '';
                }
                else if (field.is(":radio")) {
                    return field.filter(":checked").val() || '';
                }
                return field.val();
            };
        });
        setValidationValues(options, "remote", value);
    });
    adapters.add("password", ["min", "nonalphamin", "regex"], function (options) {
        if (options.params.min) {
            setValidationValues(options, "minlength", options.params.min);
        }
        if (options.params.nonalphamin) {
            setValidationValues(options, "nonalphamin", options.params.nonalphamin);
        }
        if (options.params.regex) {
            setValidationValues(options, "regex", options.params.regex);
        }
    });
    $(function () {
        $jQval.unobtrusive.parse(document);
    });
}(jQuery));
//# sourceMappingURL=zjquery.validate.unobtrusive.js.map 
//# sourceMappingURL=zjquery.validate.unobtrusive.js.map 
//# sourceMappingURL=zjquery.validate.unobtrusive.js.map 
//# sourceMappingURL=zjquery.validate.unobtrusive.js.map 
//# sourceMappingURL=zjquery.validate.unobtrusive.js.map 
//# sourceMappingURL=zjquery.validate.unobtrusive.js.map 
//# sourceMappingURL=zjquery.validate.unobtrusive.js.map;
/** @license React v16.2.0
 * react.production.min.js
 *
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */
'use strict';(function(q,k){"object"===typeof exports&&"undefined"!==typeof module?module.exports=k():"function"===typeof define&&define.amd?define(k):q.React=k()})(this,function(){function q(a){for(var b=arguments.length-1,c="Minified React error #"+a+"; visit http://facebook.github.io/react/docs/error-decoder.html?invariant\x3d"+a,d=0;d<b;d++)c+="\x26args[]\x3d"+encodeURIComponent(arguments[d+1]);b=Error(c+" for the full message or use the non-minified dev environment for full errors and additional helpful warnings.");
b.name="Invariant Violation";b.framesToPop=1;throw b;}function k(a){return function(){return a}}function p(a,b,c){this.props=a;this.context=b;this.refs=w;this.updater=c||x}function y(a,b,c){this.props=a;this.context=b;this.refs=w;this.updater=c||x}function z(){}function A(a,b,c){this.props=a;this.context=b;this.refs=w;this.updater=c||x}function G(a,b,c){var d,f={},l=null,e=null;if(null!=b)for(d in void 0!==b.ref&&(e=b.ref),void 0!==b.key&&(l=""+b.key),b)H.call(b,d)&&!I.hasOwnProperty(d)&&(f[d]=b[d]);
var g=arguments.length-2;if(1===g)f.children=c;else if(1<g){for(var h=Array(g),n=0;n<g;n++)h[n]=arguments[n+2];f.children=h}if(a&&a.defaultProps)for(d in g=a.defaultProps,g)void 0===f[d]&&(f[d]=g[d]);return{$$typeof:r,type:a,key:l,ref:e,props:f,_owner:B.current}}function C(a){return"object"===typeof a&&null!==a&&a.$$typeof===r}function O(a){var b={"\x3d":"\x3d0",":":"\x3d2"};return"$"+(""+a).replace(/[=:]/g,function(a){return b[a]})}function J(a,b,c,d){if(u.length){var f=u.pop();f.result=a;f.keyPrefix=
b;f.func=c;f.context=d;f.count=0;return f}return{result:a,keyPrefix:b,func:c,context:d,count:0}}function K(a){a.result=null;a.keyPrefix=null;a.func=null;a.context=null;a.count=0;10>u.length&&u.push(a)}function t(a,b,c,d){var f=typeof a;if("undefined"===f||"boolean"===f)a=null;var l=!1;if(null===a)l=!0;else switch(f){case "string":case "number":l=!0;break;case "object":switch(a.$$typeof){case r:case P:case Q:case R:l=!0}}if(l)return c(d,a,""===b?"."+D(a,0):b),1;l=0;b=""===b?".":b+":";if(Array.isArray(a))for(var e=
0;e<a.length;e++){f=a[e];var g=b+D(f,e);l+=t(f,g,c,d)}else if(null===a||"undefined"===typeof a?g=null:(g=L&&a[L]||a["@@iterator"],g="function"===typeof g?g:null),"function"===typeof g)for(a=g.call(a),e=0;!(f=a.next()).done;)f=f.value,g=b+D(f,e++),l+=t(f,g,c,d);else"object"===f&&(c=""+a,q("31","[object Object]"===c?"object with keys {"+Object.keys(a).join(", ")+"}":c,""));return l}function D(a,b){return"object"===typeof a&&null!==a&&null!=a.key?O(a.key):b.toString(36)}function S(a,b,c){a.func.call(a.context,
b,a.count++)}function T(a,b,c){var d=a.result,f=a.keyPrefix;a=a.func.call(a.context,b,a.count++);Array.isArray(a)?E(a,d,c,F.thatReturnsArgument):null!=a&&(C(a)&&(b=f+(!a.key||b&&b.key===a.key?"":(""+a.key).replace(M,"$\x26/")+"/")+c,a={$$typeof:r,type:a.type,key:b,ref:a.ref,props:a.props,_owner:a._owner}),d.push(a))}function E(a,b,c,d,f){var e="";null!=c&&(e=(""+c).replace(M,"$\x26/")+"/");b=J(b,e,d,f);null==a||t(a,"",T,b);K(b)}var N=Object.getOwnPropertySymbols,U=Object.prototype.hasOwnProperty,
V=Object.prototype.propertyIsEnumerable,v=function(){try{if(!Object.assign)return!1;var a=new String("abc");a[5]="de";if("5"===Object.getOwnPropertyNames(a)[0])return!1;var b={};for(a=0;10>a;a++)b["_"+String.fromCharCode(a)]=a;if("0123456789"!==Object.getOwnPropertyNames(b).map(function(a){return b[a]}).join(""))return!1;var c={};"abcdefghijklmnopqrst".split("").forEach(function(a){c[a]=a});return"abcdefghijklmnopqrst"!==Object.keys(Object.assign({},c)).join("")?!1:!0}catch(d){return!1}}()?Object.assign:
function(a,b){if(null===a||void 0===a)throw new TypeError("Object.assign cannot be called with null or undefined");var c=Object(a);for(var d,f=1;f<arguments.length;f++){var e=Object(arguments[f]);for(var h in e)U.call(e,h)&&(c[h]=e[h]);if(N){d=N(e);for(var g=0;g<d.length;g++)V.call(e,d[g])&&(c[d[g]]=e[d[g]])}}return c},h="function"===typeof Symbol&&Symbol["for"],r=h?Symbol["for"]("react.element"):60103,P=h?Symbol["for"]("react.call"):60104,Q=h?Symbol["for"]("react.return"):60105,R=h?Symbol["for"]("react.portal"):
60106;h=h?Symbol["for"]("react.fragment"):60107;var L="function"===typeof Symbol&&Symbol.iterator,w={},e=function(){};e.thatReturns=k;e.thatReturnsFalse=k(!1);e.thatReturnsTrue=k(!0);e.thatReturnsNull=k(null);e.thatReturnsThis=function(){return this};e.thatReturnsArgument=function(a){return a};var F=e,x={isMounted:function(a){return!1},enqueueForceUpdate:function(a,b,c){},enqueueReplaceState:function(a,b,c,d){},enqueueSetState:function(a,b,c,d){}};p.prototype.isReactComponent={};p.prototype.setState=
function(a,b){"object"!==typeof a&&"function"!==typeof a&&null!=a?q("85"):void 0;this.updater.enqueueSetState(this,a,b,"setState")};p.prototype.forceUpdate=function(a){this.updater.enqueueForceUpdate(this,a,"forceUpdate")};z.prototype=p.prototype;e=y.prototype=new z;e.constructor=y;v(e,p.prototype);e.isPureReactComponent=!0;e=A.prototype=new z;e.constructor=A;v(e,p.prototype);e.unstable_isAsyncReactComponent=!0;e.render=function(){return this.props.children};var B={current:null},H=Object.prototype.hasOwnProperty,
I={key:!0,ref:!0,__self:!0,__source:!0},M=/\/+/g,u=[];h={Children:{map:function(a,b,c){if(null==a)return a;var d=[];E(a,d,null,b,c);return d},forEach:function(a,b,c){if(null==a)return a;b=J(null,null,b,c);null==a||t(a,"",S,b);K(b)},count:function(a,b){return null==a?0:t(a,"",F.thatReturnsNull,null)},toArray:function(a){var b=[];E(a,b,null,F.thatReturnsArgument);return b},only:function(a){C(a)?void 0:q("143");return a}},Component:p,PureComponent:y,unstable_AsyncComponent:A,Fragment:h,createElement:G,
cloneElement:function(a,b,c){var d=v({},a.props),e=a.key,h=a.ref,k=a._owner;if(null!=b){void 0!==b.ref&&(h=b.ref,k=B.current);void 0!==b.key&&(e=""+b.key);if(a.type&&a.type.defaultProps)var g=a.type.defaultProps;for(m in b)H.call(b,m)&&!I.hasOwnProperty(m)&&(d[m]=void 0===b[m]&&void 0!==g?g[m]:b[m])}var m=arguments.length-2;if(1===m)d.children=c;else if(1<m){g=Array(m);for(var n=0;n<m;n++)g[n]=arguments[n+2];d.children=g}return{$$typeof:r,type:a.type,key:e,ref:h,props:d,_owner:k}},createFactory:function(a){var b=
G.bind(null,a);b.type=a;return b},isValidElement:C,version:"16.2.0",__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED:{ReactCurrentOwner:B,assign:v}};h=(e=Object.freeze({default:h}))&&h||e;return h["default"]?h["default"]:h});
;
/** @license React v16.2.0
 * react-dom.production.min.js
 *
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */
/*
 Modernizr 3.0.0pre (Custom Build) | MIT
*/
'use strict'; (function (na, l) { "object" === typeof exports && "undefined" !== typeof module ? module.exports = l(require("react")) : "function" === typeof define && define.amd ? define(["react"], l) : na.ReactDOM = l(na.React) })(this, function (na) {
    function l(a) {
        for (var b = arguments.length - 1, c = "Minified React error #" + a + "; visit http://facebook.github.io/react/docs/error-decoder.html?invariant\x3d" + a, d = 0; d < b; d++)c += "\x26args[]\x3d" + encodeURIComponent(arguments[d + 1]); b = Error(c + " for the full message or use the non-minified dev environment for full errors and additional helpful warnings.");
        b.name = "Invariant Violation"; b.framesToPop = 1; throw b;
    } function va(a, b) { return (a & b) === b } function Xc(a, b) { if (Yc.hasOwnProperty(a) || 2 < a.length && ("o" === a[0] || "O" === a[0]) && ("n" === a[1] || "N" === a[1])) return !1; if (null === b) return !0; switch (typeof b) { case "boolean": return Yc.hasOwnProperty(a) ? a = !0 : (b = Ub(a)) ? a = b.hasBooleanValue || b.hasStringBooleanValue || b.hasOverloadedBooleanValue : (a = a.toLowerCase().slice(0, 5), a = "data-" === a || "aria-" === a), a; case "undefined": case "number": case "string": case "object": return !0; default: return !1 } }
    function Ub(a) { return ib.hasOwnProperty(a) ? ib[a] : null } function Zc() { if (jb) for (var a in ba) { var b = ba[a], c = jb.indexOf(a); -1 < c ? void 0 : l("96", a); if (!oa[c]) { b.extractEvents ? void 0 : l("97", a); oa[c] = b; c = b.eventTypes; for (var d in c) { var e = void 0; var f = c[d], g = b, h = d; Vb.hasOwnProperty(h) ? l("99", h) : void 0; Vb[h] = f; var k = f.phasedRegistrationNames; if (k) { for (e in k) k.hasOwnProperty(e) && $c(k[e], g, h); e = !0 } else f.registrationName ? ($c(f.registrationName, g, h), e = !0) : e = !1; e ? void 0 : l("98", d, a) } } } } function $c(a, b, c) {
        ca[a] ?
        l("100", a) : void 0; ca[a] = b; kb[a] = b.eventTypes[c].dependencies
    } function ad(a) { jb ? l("101") : void 0; jb = Array.prototype.slice.call(a); Zc() } function bd(a) { var b = !1, c; for (c in a) if (a.hasOwnProperty(c)) { var d = a[c]; ba.hasOwnProperty(c) && ba[c] === d || (ba[c] ? l("102", c) : void 0, ba[c] = d, b = !0) } b && Zc() } function lb(a) { return function () { return a } } function cd(a, b, c, d) { b = a.type || "unknown-event"; a.currentTarget = dd(d); y.invokeGuardedCallbackAndCatchFirstError(b, c, void 0, a); a.currentTarget = null } function wa(a, b) {
        null == b ? l("30") :
        void 0; if (null == a) return b; if (Array.isArray(a)) { if (Array.isArray(b)) return a.push.apply(a, b), a; a.push(b); return a } return Array.isArray(b) ? [a].concat(b) : [a, b]
    } function da(a, b, c) { Array.isArray(a) ? a.forEach(b, c) : a && b.call(c, a) } function Wb(a, b) {
        var c = a.stateNode; if (!c) return null; var d = Xb(c); if (!d) return null; c = d[b]; a: switch (b) {
            case "onClick": case "onClickCapture": case "onDoubleClick": case "onDoubleClickCapture": case "onMouseDown": case "onMouseDownCapture": case "onMouseMove": case "onMouseMoveCapture": case "onMouseUp": case "onMouseUpCapture": (d =
                !d.disabled) || (a = a.type, d = !("button" === a || "input" === a || "select" === a || "textarea" === a)); a = !d; break a; default: a = !1
        }if (a) return null; c && "function" !== typeof c ? l("231", b, typeof c) : void 0; return c
    } function ed(a, b, c, d) { for (var e, f = 0; f < oa.length; f++) { var g = oa[f]; g && (g = g.extractEvents(a, b, c, d)) && (e = wa(e, g)) } return e } function Yb(a) { a && (pa = wa(pa, a)) } function Zb(a) { var b = pa; pa = null; b && (a ? da(b, $e) : da(b, af), pa ? l("95") : void 0, y.rethrowCaughtError()) } function W(a) {
        if (a[O]) return a[O]; for (var b = []; !a[O];)if (b.push(a),
            a.parentNode) a = a.parentNode; else return null; var c = void 0, d = a[O]; if (5 === d.tag || 6 === d.tag) return d; for (; a && (d = a[O]); a = b.pop())c = d; return c
    } function xa(a) { if (5 === a.tag || 6 === a.tag) return a.stateNode; l("33") } function fd(a) { return a[ea] || null } function T(a) { do a = a["return"]; while (a && 5 !== a.tag); return a ? a : null } function gd(a, b, c) { for (var d = []; a;)d.push(a), a = T(a); for (a = d.length; 0 < a--;)b(d[a], "captured", c); for (a = 0; a < d.length; a++)b(d[a], "bubbled", c) } function hd(a, b, c) {
        if (b = Wb(a, c.dispatchConfig.phasedRegistrationNames[b])) c._dispatchListeners =
            wa(c._dispatchListeners, b), c._dispatchInstances = wa(c._dispatchInstances, a)
    } function bf(a) { a && a.dispatchConfig.phasedRegistrationNames && gd(a._targetInst, hd, a) } function cf(a) { if (a && a.dispatchConfig.phasedRegistrationNames) { var b = a._targetInst; b = b ? T(b) : null; gd(b, hd, a) } } function $b(a, b, c) { a && c && c.dispatchConfig.registrationName && (b = Wb(a, c.dispatchConfig.registrationName)) && (c._dispatchListeners = wa(c._dispatchListeners, b), c._dispatchInstances = wa(c._dispatchInstances, a)) } function df(a) {
    a && a.dispatchConfig.registrationName &&
        $b(a._targetInst, null, a)
    } function ya(a) { da(a, bf) } function id(a, b, c, d) {
        if (c && d) a: { var e = c; for (var f = d, g = 0, h = e; h; h = T(h))g++; h = 0; for (var k = f; k; k = T(k))h++; for (; 0 < g - h;)e = T(e), g--; for (; 0 < h - g;)f = T(f), h--; for (; g--;) { if (e === f || e === f.alternate) break a; e = T(e); f = T(f) } e = null } else e = null; f = e; for (e = []; c && c !== f;) { g = c.alternate; if (null !== g && g === f) break; e.push(c); c = T(c) } for (c = []; d && d !== f;) { g = d.alternate; if (null !== g && g === f) break; c.push(d); d = T(d) } for (d = 0; d < e.length; d++)$b(e[d], "bubbled", a); for (a = c.length; 0 < a--;)$b(c[a],
            "captured", b)
    } function jd() { !ac && P.canUseDOM && (ac = "textContent" in document.documentElement ? "textContent" : "innerText"); return ac } function kd() { if (H._fallbackText) return H._fallbackText; var a, b = H._startText, c = b.length, d, e = ld(), f = e.length; for (a = 0; a < c && b[a] === e[a]; a++); var g = c - a; for (d = 1; d <= g && b[c - d] === e[f - d]; d++); H._fallbackText = e.slice(a, 1 < d ? 1 - d : void 0); return H._fallbackText } function ld() { return "value" in H._root ? H._root.value : H._root[jd()] } function n(a, b, c, d) {
    this.dispatchConfig = a; this._targetInst =
        b; this.nativeEvent = c; a = this.constructor.Interface; for (var e in a) a.hasOwnProperty(e) && ((b = a[e]) ? this[e] = b(c) : "target" === e ? this.target = d : this[e] = c[e]); this.isDefaultPrevented = (null != c.defaultPrevented ? c.defaultPrevented : !1 === c.returnValue) ? G.thatReturnsTrue : G.thatReturnsFalse; this.isPropagationStopped = G.thatReturnsFalse; return this
    } function ef(a, b, c, d) { if (this.eventPool.length) { var e = this.eventPool.pop(); this.call(e, a, b, c, d); return e } return new this(a, b, c, d) } function ff(a) {
        a instanceof this ? void 0 :
        l("223"); a.destructor(); 10 > this.eventPool.length && this.eventPool.push(a)
    } function md(a) { a.eventPool = []; a.getPooled = ef; a.release = ff } function nd(a, b, c, d) { return n.call(this, a, b, c, d) } function od(a, b, c, d) { return n.call(this, a, b, c, d) } function gf() { var a = window.opera; return "object" === typeof a && "function" === typeof a.version && 12 >= parseInt(a.version(), 10) } function pd(a, b) {
        switch (a) {
            case "topKeyUp": return -1 !== hf.indexOf(b.keyCode); case "topKeyDown": return 229 !== b.keyCode; case "topKeyPress": case "topMouseDown": case "topBlur": return !0;
            default: return !1
        }
    } function qd(a) { a = a.detail; return "object" === typeof a && "data" in a ? a.data : null } function jf(a, b) { switch (a) { case "topCompositionEnd": return qd(b); case "topKeyPress": if (32 !== b.which) return null; rd = !0; return sd; case "topTextInput": return a = b.data, a === sd && rd ? null : a; default: return null } } function kf(a, b) {
        if (za) return "topCompositionEnd" === a || !bc && pd(a, b) ? (a = kd(), H._root = null, H._startText = null, H._fallbackText = null, za = !1, a) : null; switch (a) {
            case "topPaste": return null; case "topKeyPress": if (!(b.ctrlKey ||
                b.altKey || b.metaKey) || b.ctrlKey && b.altKey) { if (b.char && 1 < b.char.length) return b.char; if (b.which) return String.fromCharCode(b.which) } return null; case "topCompositionEnd": return td ? null : b.data; default: return null
        }
    } function ud(a) { if (a = vd(a)) { mb && "function" === typeof mb.restoreControlledState ? void 0 : l("194"); var b = Xb(a.stateNode); mb.restoreControlledState(a.stateNode, a.type, b) } } function wd(a) { Ga ? fa ? fa.push(a) : fa = [a] : Ga = a } function xd() { if (Ga) { var a = Ga, b = fa; fa = Ga = null; ud(a); if (b) for (a = 0; a < b.length; a++)ud(b[a]) } }
    function cc(a, b) { if (dc) return ec(a, b); dc = !0; try { return ec(a, b) } finally { dc = !1, xd() } } function yd(a) { var b = a && a.nodeName && a.nodeName.toLowerCase(); return "input" === b ? !!lf[a.type] : "textarea" === b ? !0 : !1 } function fc(a) { a = a.target || a.srcElement || window; a.correspondingUseElement && (a = a.correspondingUseElement); return 3 === a.nodeType ? a.parentNode : a } function gc(a, b) {
        if (!P.canUseDOM || b && !("addEventListener" in document)) return !1; b = "on" + a; var c = b in document; c || (c = document.createElement("div"), c.setAttribute(b, "return;"),
            c = "function" === typeof c[b]); !c && zd && "wheel" === a && (c = document.implementation.hasFeature("Events.wheel", "3.0")); return c
    } function Ad(a) { var b = a.type; return (a = a.nodeName) && "input" === a.toLowerCase() && ("checkbox" === b || "radio" === b) } function mf(a) {
        var b = Ad(a) ? "checked" : "value", c = Object.getOwnPropertyDescriptor(a.constructor.prototype, b), d = "" + a[b]; if (!a.hasOwnProperty(b) && "function" === typeof c.get && "function" === typeof c.set) return Object.defineProperty(a, b, {
            enumerable: c.enumerable, configurable: !0, get: function () { return c.get.call(this) },
            set: function (a) { d = "" + a; c.set.call(this, a) }
        }), { getValue: function () { return d }, setValue: function (a) { d = "" + a }, stopTracking: function () { a._valueTracker = null; delete a[b] } }
    } function nb(a) { a._valueTracker || (a._valueTracker = mf(a)) } function Bd(a) { if (!a) return !1; var b = a._valueTracker; if (!b) return !0; var c = b.getValue(); var d = ""; a && (d = Ad(a) ? a.checked ? "true" : "false" : a.value); a = d; return a !== c ? (b.setValue(a), !0) : !1 } function Cd(a, b, c) { a = n.getPooled(Dd.change, a, b, c); a.type = "change"; wd(c); ya(a); return a } function nf(a) {
        Yb(a);
        Zb(!1)
    } function ob(a) { var b = xa(a); if (Bd(b)) return a } function of(a, b) { if ("topChange" === a) return b } function Ed() { Ha && (Ha.detachEvent("onpropertychange", Fd), Oa = Ha = null) } function Fd(a) { "value" === a.propertyName && ob(Oa) && (a = Cd(Oa, a, fc(a)), cc(nf, a)) } function pf(a, b, c) { "topFocus" === a ? (Ed(), Ha = b, Oa = c, Ha.attachEvent("onpropertychange", Fd)) : "topBlur" === a && Ed() } function qf(a, b) { if ("topSelectionChange" === a || "topKeyUp" === a || "topKeyDown" === a) return ob(Oa) } function rf(a, b) { if ("topClick" === a) return ob(b) } function sf(a,
        b) { if ("topInput" === a || "topChange" === a) return ob(b) } function Aa(a, b, c, d) { return n.call(this, a, b, c, d) } function tf(a) { var b = this.nativeEvent; return b.getModifierState ? b.getModifierState(a) : (a = uf[a]) ? !!b[a] : !1 } function hc(a) { return tf } function qa(a, b, c, d) { return n.call(this, a, b, c, d) } function Pa(a) { a = a.type; return "string" === typeof a ? a : "function" === typeof a ? a.displayName || a.name : null } function Qa(a) {
            var b = a; if (a.alternate) for (; b["return"];)b = b["return"]; else {
                if (0 !== (b.effectTag & 2)) return 1; for (; b["return"];)if (b =
                    b["return"], 0 !== (b.effectTag & 2)) return 1
            } return 3 === b.tag ? 2 : 3
        } function vf(a) { return (a = a._reactInternalFiber) ? 2 === Qa(a) : !1 } function Gd(a) { 2 !== Qa(a) ? l("188") : void 0 } function Hd(a) {
            var b = a.alternate; if (!b) return b = Qa(a), 3 === b ? l("188") : void 0, 1 === b ? null : a; for (var c = a, d = b; ;) {
                var e = c["return"], f = e ? e.alternate : null; if (!e || !f) break; if (e.child === f.child) { for (var g = e.child; g;) { if (g === c) return Gd(e), a; if (g === d) return Gd(e), b; g = g.sibling } l("188") } if (c["return"] !== d["return"]) c = e, d = f; else {
                    g = !1; for (var h = e.child; h;) {
                        if (h ===
                            c) { g = !0; c = e; d = f; break } if (h === d) { g = !0; d = e; c = f; break } h = h.sibling
                    } if (!g) { for (h = f.child; h;) { if (h === c) { g = !0; c = f; d = e; break } if (h === d) { g = !0; d = f; c = e; break } h = h.sibling } g ? void 0 : l("189") }
                } c.alternate !== d ? l("190") : void 0
            } 3 !== c.tag ? l("188") : void 0; return c.stateNode.current === c ? a : b
        } function wf(a) {
            a = Hd(a); if (!a) return null; for (var b = a; ;) {
                if (5 === b.tag || 6 === b.tag) return b; if (b.child) b.child["return"] = b, b = b.child; else {
                    if (b === a) break; for (; !b.sibling;) { if (!b["return"] || b["return"] === a) return null; b = b["return"] } b.sibling["return"] =
                        b["return"]; b = b.sibling
                }
            } return null
        } function xf(a) { a = Hd(a); if (!a) return null; for (var b = a; ;) { if (5 === b.tag || 6 === b.tag) return b; if (b.child && 4 !== b.tag) b.child["return"] = b, b = b.child; else { if (b === a) break; for (; !b.sibling;) { if (!b["return"] || b["return"] === a) return null; b = b["return"] } b.sibling["return"] = b["return"]; b = b.sibling } } return null } function yf(a) {
            var b = a.targetInst; do {
                if (!b) { a.ancestors.push(b); break } var c; for (c = b; c["return"];)c = c["return"]; c = 3 !== c.tag ? null : c.stateNode.containerInfo; if (!c) break; a.ancestors.push(b);
                b = W(c)
            } while (b); for (c = 0; c < a.ancestors.length; c++)b = a.ancestors[c], pb(a.topLevelType, b, a.nativeEvent, fc(a.nativeEvent))
        } function ic(a) { Ra = !!a } function r(a, b, c) { return c ? Id.listen(c, b, jc.bind(null, a)) : null } function ha(a, b, c) { return c ? Id.capture(c, b, jc.bind(null, a)) : null } function jc(a, b) {
            if (Ra) {
                var c = fc(b); c = W(c); null === c || "number" !== typeof c.tag || 2 === Qa(c) || (c = null); if (qb.length) { var d = qb.pop(); d.topLevelType = a; d.nativeEvent = b; d.targetInst = c; a = d } else a = { topLevelType: a, nativeEvent: b, targetInst: c, ancestors: [] };
                try { cc(yf, a) } finally { a.topLevelType = null, a.nativeEvent = null, a.targetInst = null, a.ancestors.length = 0, 10 > qb.length && qb.push(a) }
            }
        } function rb(a, b) { var c = {}; c[a.toLowerCase()] = b.toLowerCase(); c["Webkit" + a] = "webkit" + b; c["Moz" + a] = "moz" + b; c["ms" + a] = "MS" + b; c["O" + a] = "o" + b.toLowerCase(); return c } function sb(a) { if (kc[a]) return kc[a]; if (!U[a]) return a; var b = U[a], c; for (c in b) if (b.hasOwnProperty(c) && c in Jd) return kc[a] = b[c]; return "" } function Kd(a) {
            Object.prototype.hasOwnProperty.call(a, tb) || (a[tb] = zf++ , Ld[a[tb]] =
                {}); return Ld[a[tb]]
        } function Md(a, b) { return a === b ? 0 !== a || 0 !== b || 1 / a === 1 / b : a !== a && b !== b } function Nd(a, b) { return a && b ? a === b ? !0 : Od(a) ? !1 : Od(b) ? Nd(a, b.parentNode) : "contains" in a ? a.contains(b) : a.compareDocumentPosition ? !!(a.compareDocumentPosition(b) & 16) : !1 : !1 } function Pd(a) { for (; a && a.firstChild;)a = a.firstChild; return a } function Qd(a, b) {
            var c = Pd(a); a = 0; for (var d; c;) {
                if (3 === c.nodeType) { d = a + c.textContent.length; if (a <= b && d >= b) return { node: c, offset: b - a }; a = d } a: {
                    for (; c;) {
                        if (c.nextSibling) { c = c.nextSibling; break a } c =
                            c.parentNode
                    } c = void 0
                } c = Pd(c)
            }
        } function lc(a) { var b = a && a.nodeName && a.nodeName.toLowerCase(); return b && ("input" === b && "text" === a.type || "textarea" === b || "true" === a.contentEditable) } function Rd(a, b) {
            if (mc || null == X || X !== nc()) return null; var c = X; "selectionStart" in c && lc(c) ? c = { start: c.selectionStart, end: c.selectionEnd } : window.getSelection ? (c = window.getSelection(), c = { anchorNode: c.anchorNode, anchorOffset: c.anchorOffset, focusNode: c.focusNode, focusOffset: c.focusOffset }) : c = void 0; return Sa && oc(Sa, c) ? null : (Sa =
                c, a = n.getPooled(Sd.select, pc, a, b), a.type = "select", a.target = X, ya(a), a)
        } function Td(a, b, c, d) { return n.call(this, a, b, c, d) } function Ud(a, b, c, d) { return n.call(this, a, b, c, d) } function Vd(a, b, c, d) { return n.call(this, a, b, c, d) } function ub(a) { var b = a.keyCode; "charCode" in a ? (a = a.charCode, 0 === a && 13 === b && (a = 13)) : a = b; return 32 <= a || 13 === a ? a : 0 } function Wd(a, b, c, d) { return n.call(this, a, b, c, d) } function Xd(a, b, c, d) { return n.call(this, a, b, c, d) } function Yd(a, b, c, d) { return n.call(this, a, b, c, d) } function Zd(a, b, c, d) {
            return n.call(this,
                a, b, c, d)
        } function $d(a, b, c, d) { return n.call(this, a, b, c, d) } function I(a, b) { 0 > ra || (a.current = vb[ra], vb[ra] = null, ra--) } function M(a, b, c) { ra++; vb[ra] = a.current; a.current = b } function Ta(a) { return Ua(a) ? wb : ia.current } function Va(a, b) {
            var c = a.type.contextTypes; if (!c) return ja; var d = a.stateNode; if (d && d.__reactInternalMemoizedUnmaskedChildContext === b) return d.__reactInternalMemoizedMaskedChildContext; var e = {}, f; for (f in c) e[f] = b[f]; d && (a = a.stateNode, a.__reactInternalMemoizedUnmaskedChildContext = b, a.__reactInternalMemoizedMaskedChildContext =
                e); return e
        } function Ua(a) { return 2 === a.tag && null != a.type.childContextTypes } function ae(a) { Ua(a) && (I(J, a), I(ia, a)) } function be(a, b, c) { null != ia.cursor ? l("168") : void 0; M(ia, b, a); M(J, c, a) } function ce(a, b) { var c = a.stateNode, d = a.type.childContextTypes; if ("function" !== typeof c.getChildContext) return b; c = c.getChildContext(); for (var e in c) e in d ? void 0 : l("108", Pa(a) || "Unknown", e); return C({}, b, c) } function xb(a) {
            if (!Ua(a)) return !1; var b = a.stateNode; b = b && b.__reactInternalMemoizedMergedChildContext || ja; wb =
                ia.current; M(ia, b, a); M(J, J.current, a); return !0
        } function de(a, b) { var c = a.stateNode; c ? void 0 : l("169"); if (b) { var d = ce(a, wb); c.__reactInternalMemoizedMergedChildContext = d; I(J, a); I(ia, a); M(ia, d, a) } else I(J, a); M(J, b, a) } function Q(a, b, c) {
        this.tag = a; this.key = b; this.stateNode = this.type = null; this.sibling = this.child = this["return"] = null; this.index = 0; this.memoizedState = this.updateQueue = this.memoizedProps = this.pendingProps = this.ref = null; this.internalContextTag = c; this.effectTag = 0; this.lastEffect = this.firstEffect =
            this.nextEffect = null; this.expirationTime = 0; this.alternate = null
        } function yb(a, b, c) { var d = a.alternate; null === d ? (d = new Q(a.tag, a.key, a.internalContextTag), d.type = a.type, d.stateNode = a.stateNode, d.alternate = a, a.alternate = d) : (d.effectTag = 0, d.nextEffect = null, d.firstEffect = null, d.lastEffect = null); d.expirationTime = c; d.pendingProps = b; d.child = a.child; d.memoizedProps = a.memoizedProps; d.memoizedState = a.memoizedState; d.updateQueue = a.updateQueue; d.sibling = a.sibling; d.index = a.index; d.ref = a.ref; return d } function qc(a,
            b, c) { var d = void 0, e = a.type, f = a.key; "function" === typeof e ? (d = e.prototype && e.prototype.isReactComponent ? new Q(2, f, b) : new Q(0, f, b), d.type = e, d.pendingProps = a.props) : "string" === typeof e ? (d = new Q(5, f, b), d.type = e, d.pendingProps = a.props) : "object" === typeof e && null !== e && "number" === typeof e.tag ? (d = e, d.pendingProps = a.props) : l("130", null == e ? e : typeof e, ""); d.expirationTime = c; return d } function zb(a, b, c, d) { b = new Q(10, d, b); b.pendingProps = a; b.expirationTime = c; return b } function rc(a, b, c) {
                b = new Q(6, null, b); b.pendingProps =
                    a; b.expirationTime = c; return b
            } function sc(a, b, c) { b = new Q(7, a.key, b); b.type = a.handler; b.pendingProps = a; b.expirationTime = c; return b } function tc(a, b, c) { a = new Q(9, null, b); a.expirationTime = c; return a } function uc(a, b, c) { b = new Q(4, a.key, b); b.pendingProps = a.children || []; b.expirationTime = c; b.stateNode = { containerInfo: a.containerInfo, pendingChildren: null, implementation: a.implementation }; return b } function ee(a) { return function (b) { try { return a(b) } catch (c) { } } } function Af(a) {
                if ("undefined" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) return !1;
                var b = __REACT_DEVTOOLS_GLOBAL_HOOK__; if (b.isDisabled || !b.supportsFiber) return !0; try { var c = b.inject(a); vc = ee(function (a) { return b.onCommitFiberRoot(c, a) }); wc = ee(function (a) { return b.onCommitFiberUnmount(c, a) }) } catch (d) { } return !0
            } function fe(a) { "function" === typeof vc && vc(a) } function ge(a) { "function" === typeof wc && wc(a) } function he(a) { return { baseState: a, expirationTime: 0, first: null, last: null, callbackList: null, hasForceUpdate: !1, isInitialized: !1 } } function Ab(a, b) {
                null === a.last ? a.first = a.last = b : (a.last.next =
                    b, a.last = b); if (0 === a.expirationTime || a.expirationTime > b.expirationTime) a.expirationTime = b.expirationTime
            } function Bb(a, b) { var c = a.alternate, d = a.updateQueue; null === d && (d = a.updateQueue = he(null)); null !== c ? (a = c.updateQueue, null === a && (a = c.updateQueue = he(null))) : a = null; a = a !== d ? a : null; null === a ? Ab(d, b) : null === d.last || null === a.last ? (Ab(d, b), Ab(a, b)) : (Ab(d, b), a.last = b) } function ie(a, b, c, d) { a = a.partialState; return "function" === typeof a ? a.call(b, c, d) : a } function xc(a, b, c, d, e, f) {
            null !== a && a.updateQueue === c && (c =
                b.updateQueue = { baseState: c.baseState, expirationTime: c.expirationTime, first: c.first, last: c.last, isInitialized: c.isInitialized, callbackList: null, hasForceUpdate: !1 }); c.expirationTime = 0; c.isInitialized ? a = c.baseState : (a = c.baseState = b.memoizedState, c.isInitialized = !0); for (var g = !0, h = c.first, k = !1; null !== h;) {
                    var l = h.expirationTime; if (l > f) { var D = c.expirationTime; if (0 === D || D > l) c.expirationTime = l; k || (k = !0, c.baseState = a) } else {
                        k || (c.first = h.next, null === c.first && (c.last = null)); if (h.isReplace) a = ie(h, d, a, e), g = !0;
                        else if (l = ie(h, d, a, e)) a = g ? C({}, a, l) : C(a, l), g = !1; h.isForced && (c.hasForceUpdate = !0); null !== h.callback && (l = c.callbackList, null === l && (l = c.callbackList = []), l.push(h))
                    } h = h.next
                } null !== c.callbackList ? b.effectTag |= 32 : null !== c.first || c.hasForceUpdate || (b.updateQueue = null); k || (c.baseState = a); return a
            } function je(a, b) { var c = a.callbackList; if (null !== c) for (a.callbackList = null, a = 0; a < c.length; a++) { var d = c[a], e = d.callback; d.callback = null; "function" !== typeof e ? l("191", e) : void 0; e.call(b) } } function Wa(a) {
                if (null ===
                    a || "undefined" === typeof a) return null; a = ke && a[ke] || a["@@iterator"]; return "function" === typeof a ? a : null
            } function Xa(a, b) {
                var c = b.ref; if (null !== c && "function" !== typeof c) {
                    if (b._owner) { b = b._owner; var d = void 0; b && (2 !== b.tag ? l("110") : void 0, d = b.stateNode); d ? void 0 : l("147", c); var e = "" + c; if (null !== a && null !== a.ref && a.ref._stringRef === e) return a.ref; a = function (a) { var b = d.refs === ja ? d.refs = {} : d.refs; null === a ? delete b[e] : b[e] = a }; a._stringRef = e; return a } "string" !== typeof c ? l("148") : void 0; b._owner ? void 0 : l("149",
                        c)
                } return c
            } function Cb(a, b) { "textarea" !== a.type && l("31", "[object Object]" === Object.prototype.toString.call(b) ? "object with keys {" + Object.keys(b).join(", ") + "}" : b, "") } function le(a) {
                function b(b, c) { if (a) { var d = b.lastEffect; null !== d ? (d.nextEffect = c, b.lastEffect = c) : b.firstEffect = b.lastEffect = c; c.nextEffect = null; c.effectTag = 8 } } function c(c, d) { if (!a) return null; for (; null !== d;)b(c, d), d = d.sibling; return null } function d(a, b) {
                    for (a = new Map; null !== b;)null !== b.key ? a.set(b.key, b) : a.set(b.index, b), b = b.sibling;
                    return a
                } function e(a, b, c) { a = yb(a, b, c); a.index = 0; a.sibling = null; return a } function f(b, c, d) { b.index = d; if (!a) return c; d = b.alternate; if (null !== d) return d = d.index, d < c ? (b.effectTag = 2, c) : d; b.effectTag = 2; return c } function g(b) { a && null === b.alternate && (b.effectTag = 2); return b } function h(a, b, c, d) { if (null === b || 6 !== b.tag) return b = rc(c, a.internalContextTag, d), b["return"] = a, b; b = e(b, c, d); b["return"] = a; return b } function k(a, b, c, d) {
                    if (null !== b && b.type === c.type) return d = e(b, c.props, d), d.ref = Xa(b, c), d["return"] = a, d;
                    d = qc(c, a.internalContextTag, d); d.ref = Xa(b, c); d["return"] = a; return d
                } function m(a, b, c, d) { if (null === b || 7 !== b.tag) return b = sc(c, a.internalContextTag, d), b["return"] = a, b; b = e(b, c, d); b["return"] = a; return b } function D(a, b, c, d) { if (null === b || 9 !== b.tag) return b = tc(c, a.internalContextTag, d), b.type = c.value, b["return"] = a, b; b = e(b, null, d); b.type = c.value; b["return"] = a; return b } function A(a, b, c, d) {
                    if (null === b || 4 !== b.tag || b.stateNode.containerInfo !== c.containerInfo || b.stateNode.implementation !== c.implementation) return b =
                        uc(c, a.internalContextTag, d), b["return"] = a, b; b = e(b, c.children || [], d); b["return"] = a; return b
                } function v(a, b, c, d, g) { if (null === b || 10 !== b.tag) return b = zb(c, a.internalContextTag, d, g), b["return"] = a, b; b = e(b, c, d); b["return"] = a; return b } function K(a, b, c) {
                    if ("string" === typeof b || "number" === typeof b) return b = rc("" + b, a.internalContextTag, c), b["return"] = a, b; if ("object" === typeof b && null !== b) {
                        switch (b.$$typeof) {
                            case Db: if (b.type === sa) return b = zb(b.props.children, a.internalContextTag, c, b.key), b["return"] = a, b; c = qc(b,
                                a.internalContextTag, c); c.ref = Xa(null, b); c["return"] = a; return c; case Eb: return b = sc(b, a.internalContextTag, c), b["return"] = a, b; case Fb: return c = tc(b, a.internalContextTag, c), c.type = b.value, c["return"] = a, c; case Ya: return b = uc(b, a.internalContextTag, c), b["return"] = a, b
                        }if (Gb(b) || Wa(b)) return b = zb(b, a.internalContextTag, c, null), b["return"] = a, b; Cb(a, b)
                    } return null
                } function L(a, b, c, d) {
                    var e = null !== b ? b.key : null; if ("string" === typeof c || "number" === typeof c) return null !== e ? null : h(a, b, "" + c, d); if ("object" === typeof c &&
                        null !== c) { switch (c.$$typeof) { case Db: return c.key === e ? c.type === sa ? v(a, b, c.props.children, d, e) : k(a, b, c, d) : null; case Eb: return c.key === e ? m(a, b, c, d) : null; case Fb: return null === e ? D(a, b, c, d) : null; case Ya: return c.key === e ? A(a, b, c, d) : null }if (Gb(c) || Wa(c)) return null !== e ? null : v(a, b, c, d, null); Cb(a, c) } return null
                } function R(a, b, c, d, e) {
                    if ("string" === typeof d || "number" === typeof d) return a = a.get(c) || null, h(b, a, "" + d, e); if ("object" === typeof d && null !== d) {
                        switch (d.$$typeof) {
                            case Db: return a = a.get(null === d.key ? c : d.key) ||
                                null, d.type === sa ? v(b, a, d.props.children, e, d.key) : k(b, a, d, e); case Eb: return a = a.get(null === d.key ? c : d.key) || null, m(b, a, d, e); case Fb: return a = a.get(c) || null, D(b, a, d, e); case Ya: return a = a.get(null === d.key ? c : d.key) || null, A(b, a, d, e)
                        }if (Gb(d) || Wa(d)) return a = a.get(c) || null, v(b, a, d, e, null); Cb(b, d)
                    } return null
                } function n(e, g, h, z) {
                    for (var t = null, q = null, p = g, x = g = 0, k = null; null !== p && x < h.length; x++) {
                    p.index > x ? (k = p, p = null) : k = p.sibling; var l = L(e, p, h[x], z); if (null === l) { null === p && (p = k); break } a && p && null === l.alternate &&
                        b(e, p); g = f(l, g, x); null === q ? t = l : q.sibling = l; q = l; p = k
                    } if (x === h.length) return c(e, p), t; if (null === p) { for (; x < h.length; x++)if (p = K(e, h[x], z)) g = f(p, g, x), null === q ? t = p : q.sibling = p, q = p; return t } for (p = d(e, p); x < h.length; x++)if (k = R(p, e, x, h[x], z)) { if (a && null !== k.alternate) p["delete"](null === k.key ? x : k.key); g = f(k, g, x); null === q ? t = k : q.sibling = k; q = k } a && p.forEach(function (a) { return b(e, a) }); return t
                } function r(e, g, h, z) {
                    var t = Wa(h); "function" !== typeof t ? l("150") : void 0; h = t.call(h); null == h ? l("151") : void 0; for (var q = t = null,
                        p = g, x = g = 0, k = null, m = h.next(); null !== p && !m.done; x++ , m = h.next()) { p.index > x ? (k = p, p = null) : k = p.sibling; var La = L(e, p, m.value, z); if (null === La) { p || (p = k); break } a && p && null === La.alternate && b(e, p); g = f(La, g, x); null === q ? t = La : q.sibling = La; q = La; p = k } if (m.done) return c(e, p), t; if (null === p) { for (; !m.done; x++ , m = h.next())m = K(e, m.value, z), null !== m && (g = f(m, g, x), null === q ? t = m : q.sibling = m, q = m); return t } for (p = d(e, p); !m.done; x++ , m = h.next())if (m = R(p, e, x, m.value, z), null !== m) {
                            if (a && null !== m.alternate) p["delete"](null === m.key ? x : m.key);
                            g = f(m, g, x); null === q ? t = m : q.sibling = m; q = m
                        } a && p.forEach(function (a) { return b(e, a) }); return t
                } return function (a, d, f, h) {
                "object" === typeof f && null !== f && f.type === sa && null === f.key && (f = f.props.children); var k = "object" === typeof f && null !== f; if (k) switch (f.$$typeof) {
                    case Db: a: {
                        var q = f.key; for (k = d; null !== k;) { if (k.key === q) if (10 === k.tag ? f.type === sa : k.type === f.type) { c(a, k.sibling); d = e(k, f.type === sa ? f.props.children : f.props, h); d.ref = Xa(k, f); d["return"] = a; a = d; break a } else { c(a, k); break } else b(a, k); k = k.sibling } f.type ===
                            sa ? (d = zb(f.props.children, a.internalContextTag, h, f.key), d["return"] = a, a = d) : (h = qc(f, a.internalContextTag, h), h.ref = Xa(d, f), h["return"] = a, a = h)
                    } return g(a); case Eb: a: { for (k = f.key; null !== d;) { if (d.key === k) if (7 === d.tag) { c(a, d.sibling); d = e(d, f, h); d["return"] = a; a = d; break a } else { c(a, d); break } else b(a, d); d = d.sibling } d = sc(f, a.internalContextTag, h); d["return"] = a; a = d } return g(a); case Fb: a: {
                        if (null !== d) if (9 === d.tag) { c(a, d.sibling); d = e(d, null, h); d.type = f.value; d["return"] = a; a = d; break a } else c(a, d); d = tc(f, a.internalContextTag,
                            h); d.type = f.value; d["return"] = a; a = d
                    } return g(a); case Ya: a: { for (k = f.key; null !== d;) { if (d.key === k) if (4 === d.tag && d.stateNode.containerInfo === f.containerInfo && d.stateNode.implementation === f.implementation) { c(a, d.sibling); d = e(d, f.children || [], h); d["return"] = a; a = d; break a } else { c(a, d); break } else b(a, d); d = d.sibling } d = uc(f, a.internalContextTag, h); d["return"] = a; a = d } return g(a)
                }if ("string" === typeof f || "number" === typeof f) return f = "" + f, null !== d && 6 === d.tag ? (c(a, d.sibling), d = e(d, f, h)) : (c(a, d), d = rc(f, a.internalContextTag,
                    h)), d["return"] = a, a = d, g(a); if (Gb(f)) return n(a, d, f, h); if (Wa(f)) return r(a, d, f, h); k && Cb(a, f); if ("undefined" === typeof f) switch (a.tag) { case 2: case 1: h = a.type, l("152", h.displayName || h.name || "Component") }return c(a, d)
                }
            } function Bf(a, b, c) { var d = 3 < arguments.length && void 0 !== arguments[3] ? arguments[3] : null; return { $$typeof: Ya, key: null == d ? null : "" + d, children: a, containerInfo: b, implementation: c } } function Cf(a) {
                if (me.hasOwnProperty(a)) return !0; if (ne.hasOwnProperty(a)) return !1; if (Df.test(a)) return me[a] = !0; ne[a] =
                    !0; return !1
            } function zc(a, b, c) { var d = Ub(b); if (d && Xc(b, c)) { var e = d.mutationMethod; e ? e(a, c) : null == c || d.hasBooleanValue && !c || d.hasNumericValue && isNaN(c) || d.hasPositiveNumericValue && 1 > c || d.hasOverloadedBooleanValue && !1 === c ? oe(a, b) : d.mustUseProperty ? a[d.propertyName] = c : (b = d.attributeName, (e = d.attributeNamespace) ? a.setAttributeNS(e, b, "" + c) : d.hasBooleanValue || d.hasOverloadedBooleanValue && !0 === c ? a.setAttribute(b, "") : a.setAttribute(b, "" + c)) } else Ac(a, b, Xc(b, c) ? c : null) } function Ac(a, b, c) {
            Cf(b) && (null == c ? a.removeAttribute(b) :
                a.setAttribute(b, "" + c))
            } function oe(a, b) { var c = Ub(b); c ? (b = c.mutationMethod) ? b(a, void 0) : c.mustUseProperty ? a[c.propertyName] = c.hasBooleanValue ? !1 : "" : a.removeAttribute(c.attributeName) : a.removeAttribute(b) } function Bc(a, b) { var c = b.value, d = b.checked; return C({ type: void 0, step: void 0, min: void 0, max: void 0 }, b, { defaultChecked: void 0, defaultValue: void 0, value: null != c ? c : a._wrapperState.initialValue, checked: null != d ? d : a._wrapperState.initialChecked }) } function pe(a, b) {
                var c = b.defaultValue; a._wrapperState = {
                    initialChecked: null !=
                        b.checked ? b.checked : b.defaultChecked, initialValue: null != b.value ? b.value : c, controlled: "checkbox" === b.type || "radio" === b.type ? null != b.checked : null != b.value
                }
            } function qe(a, b) { b = b.checked; null != b && zc(a, "checked", b) } function Cc(a, b) {
                qe(a, b); var c = b.value; if (null != c) if (0 === c && "" === a.value) a.value = "0"; else if ("number" === b.type) { if (b = parseFloat(a.value) || 0, c != b || c == b && a.value != c) a.value = "" + c } else a.value !== "" + c && (a.value = "" + c); else null == b.value && null != b.defaultValue && a.defaultValue !== "" + b.defaultValue && (a.defaultValue =
                    "" + b.defaultValue), null == b.checked && null != b.defaultChecked && (a.defaultChecked = !!b.defaultChecked)
            } function re(a, b) { switch (b.type) { case "submit": case "reset": break; case "color": case "date": case "datetime": case "datetime-local": case "month": case "time": case "week": a.value = ""; a.value = a.defaultValue; break; default: a.value = a.value }b = a.name; "" !== b && (a.name = ""); a.defaultChecked = !a.defaultChecked; a.defaultChecked = !a.defaultChecked; "" !== b && (a.name = b) } function Ef(a) {
                var b = ""; na.Children.forEach(a, function (a) {
                null ==
                    a || "string" !== typeof a && "number" !== typeof a || (b += a)
                }); return b
            } function Dc(a, b) { a = C({ children: void 0 }, b); if (b = Ef(b.children)) a.children = b; return a } function ka(a, b, c, d) {
                a = a.options; if (b) { b = {}; for (var e = 0; e < c.length; e++)b["$" + c[e]] = !0; for (c = 0; c < a.length; c++)e = b.hasOwnProperty("$" + a[c].value), a[c].selected !== e && (a[c].selected = e), e && d && (a[c].defaultSelected = !0) } else {
                    c = "" + c; b = null; for (e = 0; e < a.length; e++) {
                        if (a[e].value === c) { a[e].selected = !0; d && (a[e].defaultSelected = !0); return } null !== b || a[e].disabled || (b =
                            a[e])
                    } null !== b && (b.selected = !0)
                }
            } function se(a, b) { var c = b.value; a._wrapperState = { initialValue: null != c ? c : b.defaultValue, wasMultiple: !!b.multiple } } function Ec(a, b) { null != b.dangerouslySetInnerHTML ? l("91") : void 0; return C({}, b, { value: void 0, defaultValue: void 0, children: "" + a._wrapperState.initialValue }) } function te(a, b) {
                var c = b.value; null == c && (c = b.defaultValue, b = b.children, null != b && (null != c ? l("92") : void 0, Array.isArray(b) && (1 >= b.length ? void 0 : l("93"), b = b[0]), c = "" + b), null == c && (c = "")); a._wrapperState = {
                    initialValue: "" +
                    c
                }
            } function ue(a, b) { var c = b.value; null != c && (c = "" + c, c !== a.value && (a.value = c), null == b.defaultValue && (a.defaultValue = c)); null != b.defaultValue && (a.defaultValue = b.defaultValue) } function ve(a) { switch (a) { case "svg": return "http://www.w3.org/2000/svg"; case "math": return "http://www.w3.org/1998/Math/MathML"; default: return "http://www.w3.org/1999/xhtml" } } function Fc(a, b) {
                return null == a || "http://www.w3.org/1999/xhtml" === a ? ve(b) : "http://www.w3.org/2000/svg" === a && "foreignObject" === b ? "http://www.w3.org/1999/xhtml" :
                    a
            } function we(a, b, c) { a = a.style; for (var d in b) if (b.hasOwnProperty(d)) { c = 0 === d.indexOf("--"); var e = d; var f = b[d]; e = null == f || "boolean" === typeof f || "" === f ? "" : c || "number" !== typeof f || 0 === f || Za.hasOwnProperty(e) && Za[e] ? ("" + f).trim() : f + "px"; "float" === d && (d = "cssFloat"); c ? a.setProperty(d, e) : a[d] = e } } function Gc(a, b, c) {
                b && (Ff[a] && (null != b.children || null != b.dangerouslySetInnerHTML ? l("137", a, c()) : void 0), null != b.dangerouslySetInnerHTML && (null != b.children ? l("60") : void 0, "object" === typeof b.dangerouslySetInnerHTML &&
                    "__html" in b.dangerouslySetInnerHTML ? void 0 : l("61")), null != b.style && "object" !== typeof b.style ? l("62", c()) : void 0)
            } function Hc(a, b) { if (-1 === a.indexOf("-")) return "string" === typeof b.is; switch (a) { case "annotation-xml": case "color-profile": case "font-face": case "font-face-src": case "font-face-uri": case "font-face-format": case "font-face-name": case "missing-glyph": return !1; default: return !0 } } function Y(a, b) {
                a = 9 === a.nodeType || 11 === a.nodeType ? a : a.ownerDocument; var c = Kd(a); b = kb[b]; for (var d = 0; d < b.length; d++) {
                    var e =
                        b[d]; c.hasOwnProperty(e) && c[e] || ("topScroll" === e ? ha("topScroll", "scroll", a) : "topFocus" === e || "topBlur" === e ? (ha("topFocus", "focus", a), ha("topBlur", "blur", a), c.topBlur = !0, c.topFocus = !0) : "topCancel" === e ? (gc("cancel", !0) && ha("topCancel", "cancel", a), c.topCancel = !0) : "topClose" === e ? (gc("close", !0) && ha("topClose", "close", a), c.topClose = !0) : xe.hasOwnProperty(e) && r(e, xe[e], a), c[e] = !0)
                }
            } function ye(a, b, c, d) {
                c = 9 === c.nodeType ? c : c.ownerDocument; "http://www.w3.org/1999/xhtml" === d && (d = ve(a)); "http://www.w3.org/1999/xhtml" ===
                    d ? "script" === a ? (a = c.createElement("div"), a.innerHTML = "\x3cscript\x3e\x3c/script\x3e", a = a.removeChild(a.firstChild)) : a = "string" === typeof b.is ? c.createElement(a, { is: b.is }) : c.createElement(a) : a = c.createElementNS(d, a); return a
            } function ze(a, b) { return (9 === b.nodeType ? b : b.ownerDocument).createTextNode(a) } function Ae(a, b, c, d) {
                var e = Hc(b, c); switch (b) {
                    case "iframe": case "object": r("topLoad", "load", a); var f = c; break; case "video": case "audio": for (f in Z) Z.hasOwnProperty(f) && r(f, Z[f], a); f = c; break; case "source": r("topError",
                        "error", a); f = c; break; case "img": case "image": r("topError", "error", a); r("topLoad", "load", a); f = c; break; case "form": r("topReset", "reset", a); r("topSubmit", "submit", a); f = c; break; case "details": r("topToggle", "toggle", a); f = c; break; case "input": pe(a, c); f = Bc(a, c); r("topInvalid", "invalid", a); Y(d, "onChange"); break; case "option": f = Dc(a, c); break; case "select": se(a, c); f = C({}, c, { value: void 0 }); r("topInvalid", "invalid", a); Y(d, "onChange"); break; case "textarea": te(a, c); f = Ec(a, c); r("topInvalid", "invalid", a); Y(d, "onChange");
                        break; default: f = c
                }Gc(b, f, $a); var g = f, h; for (h in g) if (g.hasOwnProperty(h)) { var k = g[h]; "style" === h ? we(a, k, $a) : "dangerouslySetInnerHTML" === h ? (k = k ? k.__html : void 0, null != k && Be(a, k)) : "children" === h ? "string" === typeof k ? ("textarea" !== b || "" !== k) && Ic(a, k) : "number" === typeof k && Ic(a, "" + k) : "suppressContentEditableWarning" !== h && "suppressHydrationWarning" !== h && "autoFocus" !== h && (ca.hasOwnProperty(h) ? null != k && Y(d, h) : e ? Ac(a, h, k) : null != k && zc(a, h, k)) } switch (b) {
                    case "input": nb(a); re(a, c); break; case "textarea": nb(a); c =
                        a.textContent; c === a._wrapperState.initialValue && (a.value = c); break; case "option": null != c.value && a.setAttribute("value", c.value); break; case "select": a.multiple = !!c.multiple; b = c.value; null != b ? ka(a, !!c.multiple, b, !1) : null != c.defaultValue && ka(a, !!c.multiple, c.defaultValue, !0); break; default: "function" === typeof f.onClick && (a.onclick = G)
                }
            } function Ce(a, b, c, d, e) {
                var f = null; switch (b) {
                    case "input": c = Bc(a, c); d = Bc(a, d); f = []; break; case "option": c = Dc(a, c); d = Dc(a, d); f = []; break; case "select": c = C({}, c, { value: void 0 });
                        d = C({}, d, { value: void 0 }); f = []; break; case "textarea": c = Ec(a, c); d = Ec(a, d); f = []; break; default: "function" !== typeof c.onClick && "function" === typeof d.onClick && (a.onclick = G)
                }Gc(b, d, $a); var g, h; a = null; for (g in c) if (!d.hasOwnProperty(g) && c.hasOwnProperty(g) && null != c[g]) if ("style" === g) for (h in b = c[g], b) b.hasOwnProperty(h) && (a || (a = {}), a[h] = ""); else "dangerouslySetInnerHTML" !== g && "children" !== g && "suppressContentEditableWarning" !== g && "suppressHydrationWarning" !== g && "autoFocus" !== g && (ca.hasOwnProperty(g) ? f || (f =
                    []) : (f = f || []).push(g, null)); for (g in d) {
                        var k = d[g]; b = null != c ? c[g] : void 0; if (d.hasOwnProperty(g) && k !== b && (null != k || null != b)) if ("style" === g) if (b) { for (h in b) !b.hasOwnProperty(h) || k && k.hasOwnProperty(h) || (a || (a = {}), a[h] = ""); for (h in k) k.hasOwnProperty(h) && b[h] !== k[h] && (a || (a = {}), a[h] = k[h]) } else a || (f || (f = []), f.push(g, a)), a = k; else "dangerouslySetInnerHTML" === g ? (k = k ? k.__html : void 0, b = b ? b.__html : void 0, null != k && b !== k && (f = f || []).push(g, "" + k)) : "children" === g ? b === k || "string" !== typeof k && "number" !== typeof k ||
                            (f = f || []).push(g, "" + k) : "suppressContentEditableWarning" !== g && "suppressHydrationWarning" !== g && (ca.hasOwnProperty(g) ? (null != k && Y(e, g), f || b === k || (f = [])) : (f = f || []).push(g, k))
                    } a && (f = f || []).push("style", a); return f
            } function De(a, b, c, d, e) {
            "input" === c && "radio" === e.type && null != e.name && qe(a, e); Hc(c, d); d = Hc(c, e); for (var f = 0; f < b.length; f += 2) { var g = b[f], h = b[f + 1]; "style" === g ? we(a, h, $a) : "dangerouslySetInnerHTML" === g ? Be(a, h) : "children" === g ? Ic(a, h) : d ? null != h ? Ac(a, g, h) : a.removeAttribute(g) : null != h ? zc(a, g, h) : oe(a, g) } switch (c) {
                case "input": Cc(a,
                    e); break; case "textarea": ue(a, e); break; case "select": a._wrapperState.initialValue = void 0, b = a._wrapperState.wasMultiple, a._wrapperState.wasMultiple = !!e.multiple, c = e.value, null != c ? ka(a, !!e.multiple, c, !1) : b !== !!e.multiple && (null != e.defaultValue ? ka(a, !!e.multiple, e.defaultValue, !0) : ka(a, !!e.multiple, e.multiple ? [] : "", !1))
            }
            } function Ee(a, b, c, d, e) {
                switch (b) {
                    case "iframe": case "object": r("topLoad", "load", a); break; case "video": case "audio": for (var f in Z) Z.hasOwnProperty(f) && r(f, Z[f], a); break; case "source": r("topError",
                        "error", a); break; case "img": case "image": r("topError", "error", a); r("topLoad", "load", a); break; case "form": r("topReset", "reset", a); r("topSubmit", "submit", a); break; case "details": r("topToggle", "toggle", a); break; case "input": pe(a, c); r("topInvalid", "invalid", a); Y(e, "onChange"); break; case "select": se(a, c); r("topInvalid", "invalid", a); Y(e, "onChange"); break; case "textarea": te(a, c), r("topInvalid", "invalid", a), Y(e, "onChange")
                }Gc(b, c, $a); d = null; for (var g in c) c.hasOwnProperty(g) && (f = c[g], "children" === g ? "string" ===
                    typeof f ? a.textContent !== f && (d = ["children", f]) : "number" === typeof f && a.textContent !== "" + f && (d = ["children", "" + f]) : ca.hasOwnProperty(g) && null != f && Y(e, g)); switch (b) { case "input": nb(a); re(a, c); break; case "textarea": nb(a); b = a.textContent; b === a._wrapperState.initialValue && (a.value = b); break; case "select": case "option": break; default: "function" === typeof c.onClick && (a.onclick = G) }return d
            } function Fe(a, b) { return a.nodeValue !== b } function Jc(a) {
                return !(!a || 1 !== a.nodeType && 9 !== a.nodeType && 11 !== a.nodeType && (8 !==
                    a.nodeType || " react-mount-point-unstable " !== a.nodeValue))
            } function Gf(a) { a = a ? 9 === a.nodeType ? a.documentElement : a.firstChild : null; return !(!a || 1 !== a.nodeType || !a.hasAttribute("data-reactroot")) } function Hb(a, b, c, d, e) { Jc(c) ? void 0 : l("200"); var f = c._reactRootContainer; if (f) E.updateContainer(b, f, a, e); else { d = d || Gf(c); if (!d) for (f = void 0; f = c.lastChild;)c.removeChild(f); var g = E.createContainer(c, d); f = c._reactRootContainer = g; E.unbatchedUpdates(function () { E.updateContainer(b, g, a, e) }) } return E.getPublicRootInstance(f) }
    function Ge(a, b) { var c = 2 < arguments.length && void 0 !== arguments[2] ? arguments[2] : null; Jc(b) ? void 0 : l("200"); return Bf(a, b, null, c) } function He(a, b) { this._reactRootContainer = E.createContainer(a, b) } na ? void 0 : l("227"); var Yc = { children: !0, dangerouslySetInnerHTML: !0, defaultValue: !0, defaultChecked: !0, innerHTML: !0, suppressContentEditableWarning: !0, suppressHydrationWarning: !0, style: !0 }, Ie = {
        MUST_USE_PROPERTY: 1, HAS_BOOLEAN_VALUE: 4, HAS_NUMERIC_VALUE: 8, HAS_POSITIVE_NUMERIC_VALUE: 24, HAS_OVERLOADED_BOOLEAN_VALUE: 32,
        HAS_STRING_BOOLEAN_VALUE: 64, injectDOMPropertyConfig: function (a) {
            var b = Ie, c = a.Properties || {}, d = a.DOMAttributeNamespaces || {}, e = a.DOMAttributeNames || {}; a = a.DOMMutationMethods || {}; for (var f in c) {
                ib.hasOwnProperty(f) ? l("48", f) : void 0; var g = f.toLowerCase(), h = c[f]; g = {
                    attributeName: g, attributeNamespace: null, propertyName: f, mutationMethod: null, mustUseProperty: va(h, b.MUST_USE_PROPERTY), hasBooleanValue: va(h, b.HAS_BOOLEAN_VALUE), hasNumericValue: va(h, b.HAS_NUMERIC_VALUE), hasPositiveNumericValue: va(h, b.HAS_POSITIVE_NUMERIC_VALUE),
                    hasOverloadedBooleanValue: va(h, b.HAS_OVERLOADED_BOOLEAN_VALUE), hasStringBooleanValue: va(h, b.HAS_STRING_BOOLEAN_VALUE)
                }; 1 >= g.hasBooleanValue + g.hasNumericValue + g.hasOverloadedBooleanValue ? void 0 : l("50", f); e.hasOwnProperty(f) && (g.attributeName = e[f]); d.hasOwnProperty(f) && (g.attributeNamespace = d[f]); a.hasOwnProperty(f) && (g.mutationMethod = a[f]); ib[f] = g
            }
        }
    }, ib = {}, aa = Ie, Ib = aa.MUST_USE_PROPERTY, w = aa.HAS_BOOLEAN_VALUE, Je = aa.HAS_NUMERIC_VALUE, Jb = aa.HAS_POSITIVE_NUMERIC_VALUE, Ke = aa.HAS_OVERLOADED_BOOLEAN_VALUE,
        Kb = aa.HAS_STRING_BOOLEAN_VALUE, Hf = {
            Properties: {
                allowFullScreen: w, async: w, autoFocus: w, autoPlay: w, capture: Ke, checked: Ib | w, cols: Jb, contentEditable: Kb, controls: w, "default": w, defer: w, disabled: w, download: Ke, draggable: Kb, formNoValidate: w, hidden: w, loop: w, multiple: Ib | w, muted: Ib | w, noValidate: w, open: w, playsInline: w, readOnly: w, required: w, reversed: w, rows: Jb, rowSpan: Je, scoped: w, seamless: w, selected: Ib | w, size: Jb, start: Je, span: Jb, spellCheck: Kb, style: 0, tabIndex: 0, itemScope: w, acceptCharset: 0, className: 0, htmlFor: 0, httpEquiv: 0,
                value: Kb
            }, DOMAttributeNames: { acceptCharset: "accept-charset", className: "class", htmlFor: "for", httpEquiv: "http-equiv" }, DOMMutationMethods: { value: function (a, b) { if (null == b) return a.removeAttribute("value"); "number" !== a.type || !1 === a.hasAttribute("value") ? a.setAttribute("value", "" + b) : a.validity && !a.validity.badInput && a.ownerDocument.activeElement !== a && a.setAttribute("value", "" + b) } }
        }, Kc = aa.HAS_STRING_BOOLEAN_VALUE, Lc = {
            Properties: { autoReverse: Kc, externalResourcesRequired: Kc, preserveAlpha: Kc }, DOMAttributeNames: {
                autoReverse: "autoReverse",
                externalResourcesRequired: "externalResourcesRequired", preserveAlpha: "preserveAlpha"
            }, DOMAttributeNamespaces: { xlinkActuate: "http://www.w3.org/1999/xlink", xlinkArcrole: "http://www.w3.org/1999/xlink", xlinkHref: "http://www.w3.org/1999/xlink", xlinkRole: "http://www.w3.org/1999/xlink", xlinkShow: "http://www.w3.org/1999/xlink", xlinkTitle: "http://www.w3.org/1999/xlink", xlinkType: "http://www.w3.org/1999/xlink", xmlBase: "http://www.w3.org/XML/1998/namespace", xmlLang: "http://www.w3.org/XML/1998/namespace", xmlSpace: "http://www.w3.org/XML/1998/namespace" }
        },
        If = /[\-\:]([a-z])/g, Jf = function (a) { return a[1].toUpperCase() }; "accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode x-height xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type xml:base xmlns:xlink xml:lang xml:space".split(" ").forEach(function (a) {
            var b =
                a.replace(If, Jf); Lc.Properties[b] = 0; Lc.DOMAttributeNames[b] = a
        }); aa.injectDOMPropertyConfig(Hf); aa.injectDOMPropertyConfig(Lc); var y = {
            _caughtError: null, _hasCaughtError: !1, _rethrowError: null, _hasRethrowError: !1, injection: { injectErrorUtils: function (a) { "function" !== typeof a.invokeGuardedCallback ? l("197") : void 0; Le = a.invokeGuardedCallback } }, invokeGuardedCallback: function (a, b, c, d, e, f, g, h, k) { Le.apply(y, arguments) }, invokeGuardedCallbackAndCatchFirstError: function (a, b, c, d, e, f, g, h, k) {
                y.invokeGuardedCallback.apply(this,
                    arguments); if (y.hasCaughtError()) { var l = y.clearCaughtError(); y._hasRethrowError || (y._hasRethrowError = !0, y._rethrowError = l) }
            }, rethrowCaughtError: function () { return Kf.apply(y, arguments) }, hasCaughtError: function () { return y._hasCaughtError }, clearCaughtError: function () { if (y._hasCaughtError) { var a = y._caughtError; y._caughtError = null; y._hasCaughtError = !1; return a } l("198") }
        }, Le = function (a, b, c, d, e, f, g, h, k) {
        y._hasCaughtError = !1; y._caughtError = null; var l = Array.prototype.slice.call(arguments, 3); try {
            b.apply(c,
                l)
        } catch (D) { y._caughtError = D, y._hasCaughtError = !0 }
        }, Kf = function () { if (y._hasRethrowError) { var a = y._rethrowError; y._rethrowError = null; y._hasRethrowError = !1; throw a; } }, jb = null, ba = {}, oa = [], Vb = {}, ca = {}, kb = {}, Lf = Object.freeze({ plugins: oa, eventNameDispatchConfigs: Vb, registrationNameModules: ca, registrationNameDependencies: kb, possibleRegistrationNames: null, injectEventPluginOrder: ad, injectEventPluginsByName: bd }), ta = function () { }; ta.thatReturns = lb; ta.thatReturnsFalse = lb(!1); ta.thatReturnsTrue = lb(!0); ta.thatReturnsNull =
            lb(null); ta.thatReturnsThis = function () { return this }; ta.thatReturnsArgument = function (a) { return a }; var G = ta, Xb = null, vd = null, dd = null, pa = null, Me = function (a, b) { if (a) { var c = a._dispatchListeners, d = a._dispatchInstances; if (Array.isArray(c)) for (var e = 0; e < c.length && !a.isPropagationStopped(); e++)cd(a, b, c[e], d[e]); else c && cd(a, b, c, d); a._dispatchListeners = null; a._dispatchInstances = null; a.isPersistent() || a.constructor.release(a) } }, $e = function (a) { return Me(a, !0) }, af = function (a) { return Me(a, !1) }, Mc = {
                injectEventPluginOrder: ad,
                injectEventPluginsByName: bd
            }, Mf = Object.freeze({ injection: Mc, getListener: Wb, extractEvents: ed, enqueueEvents: Yb, processEventQueue: Zb }), Ne = Math.random().toString(36).slice(2), O = "__reactInternalInstance$" + Ne, ea = "__reactEventHandlers$" + Ne, Oe = Object.freeze({ precacheFiberNode: function (a, b) { b[O] = a }, getClosestInstanceFromNode: W, getInstanceFromNode: function (a) { a = a[O]; return !a || 5 !== a.tag && 6 !== a.tag ? null : a }, getNodeFromInstance: xa, getFiberCurrentPropsFromNode: fd, updateFiberProps: function (a, b) { a[ea] = b } }), Nf = Object.freeze({
                accumulateTwoPhaseDispatches: ya,
                accumulateTwoPhaseDispatchesSkipTarget: function (a) { da(a, cf) }, accumulateEnterLeaveDispatches: id, accumulateDirectDispatches: function (a) { da(a, df) }
            }), Lb = !("undefined" === typeof window || !window.document || !window.document.createElement), P = { canUseDOM: Lb, canUseWorkers: "undefined" !== typeof Worker, canUseEventListeners: Lb && !(!window.addEventListener && !window.attachEvent), canUseViewport: Lb && !!window.screen, isInWorker: !Lb }, ac = null, H = { _root: null, _startText: null, _fallbackText: null }, C = na.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.assign,
                Pe = "dispatchConfig _targetInst nativeEvent isDefaultPrevented isPropagationStopped _dispatchListeners _dispatchInstances".split(" "), Of = { type: null, target: null, currentTarget: G.thatReturnsNull, eventPhase: null, bubbles: null, cancelable: null, timeStamp: function (a) { return a.timeStamp || Date.now() }, defaultPrevented: null, isTrusted: null }; C(n.prototype, {
                    preventDefault: function () {
                    this.defaultPrevented = !0; var a = this.nativeEvent; a && (a.preventDefault ? a.preventDefault() : "unknown" !== typeof a.returnValue && (a.returnValue =
                        !1), this.isDefaultPrevented = G.thatReturnsTrue)
                    }, stopPropagation: function () { var a = this.nativeEvent; a && (a.stopPropagation ? a.stopPropagation() : "unknown" !== typeof a.cancelBubble && (a.cancelBubble = !0), this.isPropagationStopped = G.thatReturnsTrue) }, persist: function () { this.isPersistent = G.thatReturnsTrue }, isPersistent: G.thatReturnsFalse, destructor: function () { var a = this.constructor.Interface, b; for (b in a) this[b] = null; for (a = 0; a < Pe.length; a++)this[Pe[a]] = null }
                }); n.Interface = Of; n.augmentClass = function (a, b) {
                    var c =
                        function () { }; c.prototype = this.prototype; c = new c; C(c, a.prototype); a.prototype = c; a.prototype.constructor = a; a.Interface = C({}, this.Interface, b); a.augmentClass = this.augmentClass; md(a)
                }; md(n); n.augmentClass(nd, { data: null }); n.augmentClass(od, { data: null }); var hf = [9, 13, 27, 32], bc = P.canUseDOM && "CompositionEvent" in window, ab = null; P.canUseDOM && "documentMode" in document && (ab = document.documentMode); var Pf = P.canUseDOM && "TextEvent" in window && !ab && !gf(), td = P.canUseDOM && (!bc || ab && 8 < ab && 11 >= ab), sd = String.fromCharCode(32),
                    V = {
                        beforeInput: { phasedRegistrationNames: { bubbled: "onBeforeInput", captured: "onBeforeInputCapture" }, dependencies: ["topCompositionEnd", "topKeyPress", "topTextInput", "topPaste"] }, compositionEnd: { phasedRegistrationNames: { bubbled: "onCompositionEnd", captured: "onCompositionEndCapture" }, dependencies: "topBlur topCompositionEnd topKeyDown topKeyPress topKeyUp topMouseDown".split(" ") }, compositionStart: { phasedRegistrationNames: { bubbled: "onCompositionStart", captured: "onCompositionStartCapture" }, dependencies: "topBlur topCompositionStart topKeyDown topKeyPress topKeyUp topMouseDown".split(" ") },
                        compositionUpdate: { phasedRegistrationNames: { bubbled: "onCompositionUpdate", captured: "onCompositionUpdateCapture" }, dependencies: "topBlur topCompositionUpdate topKeyDown topKeyPress topKeyUp topMouseDown".split(" ") }
                    }, rd = !1, za = !1, Qf = {
                        eventTypes: V, extractEvents: function (a, b, c, d) {
                            var e; if (bc) b: { switch (a) { case "topCompositionStart": var f = V.compositionStart; break b; case "topCompositionEnd": f = V.compositionEnd; break b; case "topCompositionUpdate": f = V.compositionUpdate; break b }f = void 0 } else za ? pd(a, c) && (f = V.compositionEnd) :
                                "topKeyDown" === a && 229 === c.keyCode && (f = V.compositionStart); f ? (td && (za || f !== V.compositionStart ? f === V.compositionEnd && za && (e = kd()) : (H._root = d, H._startText = ld(), za = !0)), f = nd.getPooled(f, b, c, d), e ? f.data = e : (e = qd(c), null !== e && (f.data = e)), ya(f), e = f) : e = null; (a = Pf ? jf(a, c) : kf(a, c)) ? (b = od.getPooled(V.beforeInput, b, c, d), b.data = a, ya(b)) : b = null; return [e, b]
                        }
                    }, mb = null, Ga = null, fa = null, Qe = { injectFiberControlledHostComponent: function (a) { mb = a } }, Rf = Object.freeze({ injection: Qe, enqueueStateRestore: wd, restoreStateIfNeeded: xd }),
                    ec = function (a, b) { return a(b) }, dc = !1, lf = { color: !0, date: !0, datetime: !0, "datetime-local": !0, email: !0, month: !0, number: !0, password: !0, range: !0, search: !0, tel: !0, text: !0, time: !0, url: !0, week: !0 }, zd; P.canUseDOM && (zd = document.implementation && document.implementation.hasFeature && !0 !== document.implementation.hasFeature("", "")); var Dd = { change: { phasedRegistrationNames: { bubbled: "onChange", captured: "onChangeCapture" }, dependencies: "topBlur topChange topClick topFocus topInput topKeyDown topKeyUp topSelectionChange".split(" ") } },
                        Ha = null, Oa = null, Nc = !1; P.canUseDOM && (Nc = gc("input") && (!document.documentMode || 9 < document.documentMode)); var Sf = {
                            eventTypes: Dd, _isInputEventSupported: Nc, extractEvents: function (a, b, c, d) {
                                var e = b ? xa(b) : window, f = e.nodeName && e.nodeName.toLowerCase(); if ("select" === f || "input" === f && "file" === e.type) var g = of; else if (yd(e)) if (Nc) g = sf; else { g = qf; var h = pf } else f = e.nodeName, !f || "input" !== f.toLowerCase() || "checkbox" !== e.type && "radio" !== e.type || (g = rf); if (g && (g = g(a, b))) return Cd(g, c, d); h && h(a, e, b); "topBlur" === a && null !=
                                    b && (a = b._wrapperState || e._wrapperState) && a.controlled && "number" === e.type && (a = "" + e.value, e.getAttribute("value") !== a && e.setAttribute("value", a))
                            }
                        }; n.augmentClass(Aa, { view: null, detail: null }); var uf = { Alt: "altKey", Control: "ctrlKey", Meta: "metaKey", Shift: "shiftKey" }; Aa.augmentClass(qa, {
                            screenX: null, screenY: null, clientX: null, clientY: null, pageX: null, pageY: null, ctrlKey: null, shiftKey: null, altKey: null, metaKey: null, getModifierState: hc, button: null, buttons: null, relatedTarget: function (a) {
                                return a.relatedTarget ||
                                    (a.fromElement === a.srcElement ? a.toElement : a.fromElement)
                            }
                        }); var Oc = { mouseEnter: { registrationName: "onMouseEnter", dependencies: ["topMouseOut", "topMouseOver"] }, mouseLeave: { registrationName: "onMouseLeave", dependencies: ["topMouseOut", "topMouseOver"] } }, Tf = {
                            eventTypes: Oc, extractEvents: function (a, b, c, d) {
                                if ("topMouseOver" === a && (c.relatedTarget || c.fromElement) || "topMouseOut" !== a && "topMouseOver" !== a) return null; var e = d.window === d ? d : (e = d.ownerDocument) ? e.defaultView || e.parentWindow : window; "topMouseOut" === a ? (a =
                                    b, b = (b = c.relatedTarget || c.toElement) ? W(b) : null) : a = null; if (a === b) return null; var f = null == a ? e : xa(a); e = null == b ? e : xa(b); var g = qa.getPooled(Oc.mouseLeave, a, c, d); g.type = "mouseleave"; g.target = f; g.relatedTarget = e; c = qa.getPooled(Oc.mouseEnter, b, c, d); c.type = "mouseenter"; c.target = e; c.relatedTarget = f; id(g, c, a, b); return [g, c]
                            }
                        }, bb = na.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner, Id = {
                            listen: function (a, b, c) {
                                if (a.addEventListener) return a.addEventListener(b, c, !1), {
                                    remove: function () {
                                        a.removeEventListener(b,
                                            c, !1)
                                    }
                                }; if (a.attachEvent) return a.attachEvent("on" + b, c), { remove: function () { a.detachEvent("on" + b, c) } }
                            }, capture: function (a, b, c) { return a.addEventListener ? (a.addEventListener(b, c, !0), { remove: function () { a.removeEventListener(b, c, !0) } }) : { remove: G } }, registerDefault: function () { }
                        }, qb = [], Ra = !0, pb = void 0, Uf = Object.freeze({ get _enabled() { return Ra }, get _handleTopLevel() { return pb }, setHandleTopLevel: function (a) { pb = a }, setEnabled: ic, isEnabled: function () { return Ra }, trapBubbledEvent: r, trapCapturedEvent: ha, dispatchEvent: jc }),
                            U = { animationend: rb("Animation", "AnimationEnd"), animationiteration: rb("Animation", "AnimationIteration"), animationstart: rb("Animation", "AnimationStart"), transitionend: rb("Transition", "TransitionEnd") }, kc = {}, Jd = {}; P.canUseDOM && (Jd = document.createElement("div").style, "AnimationEvent" in window || (delete U.animationend.animation, delete U.animationiteration.animation, delete U.animationstart.animation), "TransitionEvent" in window || delete U.transitionend.transition); var xe = {
                                topAbort: "abort", topAnimationEnd: sb("animationend") ||
                                    "animationend", topAnimationIteration: sb("animationiteration") || "animationiteration", topAnimationStart: sb("animationstart") || "animationstart", topBlur: "blur", topCancel: "cancel", topCanPlay: "canplay", topCanPlayThrough: "canplaythrough", topChange: "change", topClick: "click", topClose: "close", topCompositionEnd: "compositionend", topCompositionStart: "compositionstart", topCompositionUpdate: "compositionupdate", topContextMenu: "contextmenu", topCopy: "copy", topCut: "cut", topDoubleClick: "dblclick", topDrag: "drag", topDragEnd: "dragend",
                                topDragEnter: "dragenter", topDragExit: "dragexit", topDragLeave: "dragleave", topDragOver: "dragover", topDragStart: "dragstart", topDrop: "drop", topDurationChange: "durationchange", topEmptied: "emptied", topEncrypted: "encrypted", topEnded: "ended", topError: "error", topFocus: "focus", topInput: "input", topKeyDown: "keydown", topKeyPress: "keypress", topKeyUp: "keyup", topLoadedData: "loadeddata", topLoad: "load", topLoadedMetadata: "loadedmetadata", topLoadStart: "loadstart", topMouseDown: "mousedown", topMouseMove: "mousemove", topMouseOut: "mouseout",
                                topMouseOver: "mouseover", topMouseUp: "mouseup", topPaste: "paste", topPause: "pause", topPlay: "play", topPlaying: "playing", topProgress: "progress", topRateChange: "ratechange", topScroll: "scroll", topSeeked: "seeked", topSeeking: "seeking", topSelectionChange: "selectionchange", topStalled: "stalled", topSuspend: "suspend", topTextInput: "textInput", topTimeUpdate: "timeupdate", topToggle: "toggle", topTouchCancel: "touchcancel", topTouchEnd: "touchend", topTouchMove: "touchmove", topTouchStart: "touchstart", topTransitionEnd: sb("transitionend") ||
                                "transitionend", topVolumeChange: "volumechange", topWaiting: "waiting", topWheel: "wheel"
                            }, Ld = {}, zf = 0, tb = "_reactListenersID" + ("" + Math.random()).slice(2), nc = function (a) { a = a || ("undefined" !== typeof document ? document : void 0); if ("undefined" === typeof a) return null; try { return a.activeElement || a.body } catch (b) { return a.body } }, Vf = Object.prototype.hasOwnProperty, oc = function (a, b) {
                                if (Md(a, b)) return !0; if ("object" !== typeof a || null === a || "object" !== typeof b || null === b) return !1; var c = Object.keys(a), d = Object.keys(b); if (c.length !==
                                    d.length) return !1; for (d = 0; d < c.length; d++)if (!Vf.call(b, c[d]) || !Md(a[c[d]], b[c[d]])) return !1; return !0
                            }, Od = function (a) { var b = (a ? a.ownerDocument || a : document).defaultView || window; return !!(a && ("function" === typeof b.Node ? a instanceof b.Node : "object" === typeof a && "number" === typeof a.nodeType && "string" === typeof a.nodeName)) && 3 == a.nodeType }, Wf = P.canUseDOM && "documentMode" in document && 11 >= document.documentMode, Sd = { select: { phasedRegistrationNames: { bubbled: "onSelect", captured: "onSelectCapture" }, dependencies: "topBlur topContextMenu topFocus topKeyDown topKeyUp topMouseDown topMouseUp topSelectionChange".split(" ") } },
                                X = null, pc = null, Sa = null, mc = !1, Xf = {
                                    eventTypes: Sd, extractEvents: function (a, b, c, d) {
                                        var e = d.window === d ? d.document : 9 === d.nodeType ? d : d.ownerDocument, f; if (!(f = !e)) { a: { e = Kd(e); f = kb.onSelect; for (var g = 0; g < f.length; g++) { var h = f[g]; if (!e.hasOwnProperty(h) || !e[h]) { e = !1; break a } } e = !0 } f = !e } if (f) return null; e = b ? xa(b) : window; switch (a) {
                                            case "topFocus": if (yd(e) || "true" === e.contentEditable) X = e, pc = b, Sa = null; break; case "topBlur": Sa = pc = X = null; break; case "topMouseDown": mc = !0; break; case "topContextMenu": case "topMouseUp": return mc =
                                                !1, Rd(c, d); case "topSelectionChange": if (Wf) break; case "topKeyDown": case "topKeyUp": return Rd(c, d)
                                        }return null
                                    }
                                }; n.augmentClass(Td, { animationName: null, elapsedTime: null, pseudoElement: null }); n.augmentClass(Ud, { clipboardData: function (a) { return "clipboardData" in a ? a.clipboardData : window.clipboardData } }); Aa.augmentClass(Vd, { relatedTarget: null }); var Yf = {
                                    Esc: "Escape", Spacebar: " ", Left: "ArrowLeft", Up: "ArrowUp", Right: "ArrowRight", Down: "ArrowDown", Del: "Delete", Win: "OS", Menu: "ContextMenu", Apps: "ContextMenu", Scroll: "ScrollLock",
                                    MozPrintableKey: "Unidentified"
                                }, Zf = { 8: "Backspace", 9: "Tab", 12: "Clear", 13: "Enter", 16: "Shift", 17: "Control", 18: "Alt", 19: "Pause", 20: "CapsLock", 27: "Escape", 32: " ", 33: "PageUp", 34: "PageDown", 35: "End", 36: "Home", 37: "ArrowLeft", 38: "ArrowUp", 39: "ArrowRight", 40: "ArrowDown", 45: "Insert", 46: "Delete", 112: "F1", 113: "F2", 114: "F3", 115: "F4", 116: "F5", 117: "F6", 118: "F7", 119: "F8", 120: "F9", 121: "F10", 122: "F11", 123: "F12", 144: "NumLock", 145: "ScrollLock", 224: "Meta" }; Aa.augmentClass(Wd, {
                                    key: function (a) {
                                        if (a.key) {
                                            var b = Yf[a.key] ||
                                                a.key; if ("Unidentified" !== b) return b
                                        } return "keypress" === a.type ? (a = ub(a), 13 === a ? "Enter" : String.fromCharCode(a)) : "keydown" === a.type || "keyup" === a.type ? Zf[a.keyCode] || "Unidentified" : ""
                                    }, location: null, ctrlKey: null, shiftKey: null, altKey: null, metaKey: null, repeat: null, locale: null, getModifierState: hc, charCode: function (a) { return "keypress" === a.type ? ub(a) : 0 }, keyCode: function (a) { return "keydown" === a.type || "keyup" === a.type ? a.keyCode : 0 }, which: function (a) {
                                        return "keypress" === a.type ? ub(a) : "keydown" === a.type || "keyup" ===
                                            a.type ? a.keyCode : 0
                                    }
                                }); qa.augmentClass(Xd, { dataTransfer: null }); Aa.augmentClass(Yd, { touches: null, targetTouches: null, changedTouches: null, altKey: null, metaKey: null, ctrlKey: null, shiftKey: null, getModifierState: hc }); n.augmentClass(Zd, { propertyName: null, elapsedTime: null, pseudoElement: null }); qa.augmentClass($d, {
                                    deltaX: function (a) { return "deltaX" in a ? a.deltaX : "wheelDeltaX" in a ? -a.wheelDeltaX : 0 }, deltaY: function (a) { return "deltaY" in a ? a.deltaY : "wheelDeltaY" in a ? -a.wheelDeltaY : "wheelDelta" in a ? -a.wheelDelta : 0 }, deltaZ: null,
                                    deltaMode: null
                                }); var Re = {}, Se = {}; "abort animationEnd animationIteration animationStart blur cancel canPlay canPlayThrough click close contextMenu copy cut doubleClick drag dragEnd dragEnter dragExit dragLeave dragOver dragStart drop durationChange emptied encrypted ended error focus input invalid keyDown keyPress keyUp load loadedData loadedMetadata loadStart mouseDown mouseMove mouseOut mouseOver mouseUp paste pause play playing progress rateChange reset scroll seeked seeking stalled submit suspend timeUpdate toggle touchCancel touchEnd touchMove touchStart transitionEnd volumeChange waiting wheel".split(" ").forEach(function (a) {
                                    var b =
                                        a[0].toUpperCase() + a.slice(1), c = "on" + b; b = "top" + b; c = { phasedRegistrationNames: { bubbled: c, captured: c + "Capture" }, dependencies: [b] }; Re[a] = c; Se[b] = c
                                }); var $f = {
                                    eventTypes: Re, extractEvents: function (a, b, c, d) {
                                        var e = Se[a]; if (!e) return null; switch (a) {
                                            case "topKeyPress": if (0 === ub(c)) return null; case "topKeyDown": case "topKeyUp": a = Wd; break; case "topBlur": case "topFocus": a = Vd; break; case "topClick": if (2 === c.button) return null; case "topDoubleClick": case "topMouseDown": case "topMouseMove": case "topMouseUp": case "topMouseOut": case "topMouseOver": case "topContextMenu": a =
                                                qa; break; case "topDrag": case "topDragEnd": case "topDragEnter": case "topDragExit": case "topDragLeave": case "topDragOver": case "topDragStart": case "topDrop": a = Xd; break; case "topTouchCancel": case "topTouchEnd": case "topTouchMove": case "topTouchStart": a = Yd; break; case "topAnimationEnd": case "topAnimationIteration": case "topAnimationStart": a = Td; break; case "topTransitionEnd": a = Zd; break; case "topScroll": a = Aa; break; case "topWheel": a = $d; break; case "topCopy": case "topCut": case "topPaste": a = Ud; break; default: a =
                                                    n
                                        }b = a.getPooled(e, b, c, d); ya(b); return b
                                    }
                                }; pb = function (a, b, c, d) { a = ed(a, b, c, d); Yb(a); Zb(!1) }; Mc.injectEventPluginOrder("ResponderEventPlugin SimpleEventPlugin TapEventPlugin EnterLeaveEventPlugin ChangeEventPlugin SelectEventPlugin BeforeInputEventPlugin".split(" ")); (function (a) { Xb = a.getFiberCurrentPropsFromNode; vd = a.getInstanceFromNode; dd = a.getNodeFromInstance })(Oe); Mc.injectEventPluginsByName({ SimpleEventPlugin: $f, EnterLeaveEventPlugin: Tf, ChangeEventPlugin: Sf, SelectEventPlugin: Xf, BeforeInputEventPlugin: Qf });
    var ja = {}, vb = [], ra = -1; new Set; var ia = { current: ja }, J = { current: !1 }, wb = ja, vc = null, wc = null, ag = function (a, b, c, d) {
        function e(a, b) { b.updater = f; a.stateNode = b; b._reactInternalFiber = a } var f = {
            isMounted: vf, enqueueSetState: function (c, d, e) { c = c._reactInternalFiber; e = void 0 === e ? null : e; var f = b(c); Bb(c, { expirationTime: f, partialState: d, callback: e, isReplace: !1, isForced: !1, nextCallback: null, next: null }); a(c, f) }, enqueueReplaceState: function (c, d, e) {
                c = c._reactInternalFiber; e = void 0 === e ? null : e; var f = b(c); Bb(c, {
                    expirationTime: f,
                    partialState: d, callback: e, isReplace: !0, isForced: !1, nextCallback: null, next: null
                }); a(c, f)
            }, enqueueForceUpdate: function (c, d) { c = c._reactInternalFiber; d = void 0 === d ? null : d; var e = b(c); Bb(c, { expirationTime: e, partialState: null, callback: d, isReplace: !1, isForced: !0, nextCallback: null, next: null }); a(c, e) }
        }; return {
            adoptClassInstance: e, constructClassInstance: function (a, b) {
                var c = a.type, d = Ta(a), f = 2 === a.tag && null != a.type.contextTypes, g = f ? Va(a, d) : ja; b = new c(b, g); e(a, b); f && (a = a.stateNode, a.__reactInternalMemoizedUnmaskedChildContext =
                    d, a.__reactInternalMemoizedMaskedChildContext = g); return b
            }, mountClassInstance: function (a, b) {
                var c = a.alternate, d = a.stateNode, e = d.state || null, h = a.pendingProps; h ? void 0 : l("158"); var g = Ta(a); d.props = h; d.state = a.memoizedState = e; d.refs = ja; d.context = Va(a, g); null != a.type && null != a.type.prototype && !0 === a.type.prototype.unstable_isAsyncReactComponent && (a.internalContextTag |= 1); "function" === typeof d.componentWillMount && (e = d.state, d.componentWillMount(), e !== d.state && f.enqueueReplaceState(d, d.state, null), e = a.updateQueue,
                    null !== e && (d.state = xc(c, a, e, d, h, b))); "function" === typeof d.componentDidMount && (a.effectTag |= 4)
            }, updateClassInstance: function (a, b, e) {
                var g = b.stateNode; g.props = b.memoizedProps; g.state = b.memoizedState; var h = b.memoizedProps, k = b.pendingProps; k || (k = h, null == k ? l("159") : void 0); var v = g.context, K = Ta(b); K = Va(b, K); "function" !== typeof g.componentWillReceiveProps || h === k && v === K || (v = g.state, g.componentWillReceiveProps(k, K), g.state !== v && f.enqueueReplaceState(g, g.state, null)); v = b.memoizedState; e = null !== b.updateQueue ?
                    xc(a, b, b.updateQueue, g, k, e) : v; if (!(h !== k || v !== e || J.current || null !== b.updateQueue && b.updateQueue.hasForceUpdate)) return "function" !== typeof g.componentDidUpdate || h === a.memoizedProps && v === a.memoizedState || (b.effectTag |= 4), !1; var L = k; if (null === h || null !== b.updateQueue && b.updateQueue.hasForceUpdate) L = !0; else { var R = b.stateNode, n = b.type; L = "function" === typeof R.shouldComponentUpdate ? R.shouldComponentUpdate(L, e, K) : n.prototype && n.prototype.isPureReactComponent ? !oc(h, L) || !oc(v, e) : !0 } L ? ("function" === typeof g.componentWillUpdate &&
                        g.componentWillUpdate(k, e, K), "function" === typeof g.componentDidUpdate && (b.effectTag |= 4)) : ("function" !== typeof g.componentDidUpdate || h === a.memoizedProps && v === a.memoizedState || (b.effectTag |= 4), c(b, k), d(b, e)); g.props = k; g.state = e; g.context = K; return L
            }
        }
    }, cb = "function" === typeof Symbol && Symbol["for"], Db = cb ? Symbol["for"]("react.element") : 60103, Eb = cb ? Symbol["for"]("react.call") : 60104, Fb = cb ? Symbol["for"]("react.return") : 60105, Ya = cb ? Symbol["for"]("react.portal") : 60106, sa = cb ? Symbol["for"]("react.fragment") : 60107,
        ke = "function" === typeof Symbol && Symbol.iterator, Gb = Array.isArray, db = le(!0), Mb = le(!1), bg = function (a, b, c, d, e) {
            function f(a, b, c) { var d = b.expirationTime; b.child = null === a ? Mb(b, null, c, d) : db(b, a.child, c, d) } function g(a, b) { var c = b.ref; null === c || a && a.ref === c || (b.effectTag |= 128) } function h(a, b, c, d) { g(a, b); if (!c) return d && de(b, !1), m(a, b); c = b.stateNode; bb.current = b; var e = c.render(); b.effectTag |= 1; f(a, b, e); b.memoizedState = c.state; b.memoizedProps = c.props; d && de(b, !0); return b.child } function k(a) {
                var b = a.stateNode;
                b.pendingContext ? be(a, b.pendingContext, b.pendingContext !== b.context) : b.context && be(a, b.context, !1); R(a, b.containerInfo)
            } function m(a, b) { null !== a && b.child !== a.child ? l("153") : void 0; if (null !== b.child) { a = b.child; var c = yb(a, a.pendingProps, a.expirationTime); b.child = c; for (c["return"] = b; null !== a.sibling;)a = a.sibling, c = c.sibling = yb(a, a.pendingProps, a.expirationTime), c["return"] = b; c.sibling = null } return b.child } function D(a, b) { switch (b.tag) { case 3: k(b); break; case 2: xb(b); break; case 4: R(b, b.stateNode.containerInfo) }return null }
            var A = a.shouldSetTextContent, v = a.useSyncScheduling, n = a.shouldDeprioritizeSubtree, L = b.pushHostContext, R = b.pushHostContainer, r = c.enterHydrationState, w = c.resetHydrationState, y = c.tryToClaimNextHydratableInstance; a = ag(d, e, function (a, b) { a.memoizedProps = b }, function (a, b) { a.memoizedState = b }); var x = a.adoptClassInstance, t = a.constructClassInstance, z = a.mountClassInstance, yc = a.updateClassInstance; return {
                beginWork: function (a, b, c) {
                    if (0 === b.expirationTime || b.expirationTime > c) return D(a, b); switch (b.tag) {
                        case 0: null !==
                            a ? l("155") : void 0; var d = b.type, e = b.pendingProps, q = Ta(b); q = Va(b, q); d = d(e, q); b.effectTag |= 1; "object" === typeof d && null !== d && "function" === typeof d.render ? (b.tag = 2, e = xb(b), x(b, d), z(b, c), b = h(a, b, !0, e)) : (b.tag = 1, f(a, b, d), b.memoizedProps = e, b = b.child); return b; case 1: a: { e = b.type; c = b.pendingProps; d = b.memoizedProps; if (J.current) null === c && (c = d); else if (null === c || d === c) { b = m(a, b); break a } d = Ta(b); d = Va(b, d); e = e(c, d); b.effectTag |= 1; f(a, b, e); b.memoizedProps = c; b = b.child } return b; case 2: return e = xb(b), d = void 0, null ===
                                a ? b.stateNode ? l("153") : (t(b, b.pendingProps), z(b, c), d = !0) : d = yc(a, b, c), h(a, b, d, e); case 3: return k(b), e = b.updateQueue, null !== e ? (d = b.memoizedState, e = xc(a, b, e, null, null, c), d === e ? (w(), b = m(a, b)) : (d = e.element, q = b.stateNode, (null === a || null === a.child) && q.hydrate && r(b) ? (b.effectTag |= 2, b.child = Mb(b, null, d, c)) : (w(), f(a, b, d)), b.memoizedState = e, b = b.child)) : (w(), b = m(a, b)), b; case 5: L(b); null === a && y(b); e = b.type; var p = b.memoizedProps; d = b.pendingProps; null === d && (d = p, null === d ? l("154") : void 0); q = null !== a ? a.memoizedProps :
                                    null; J.current || null !== d && p !== d ? (p = d.children, A(e, d) ? p = null : q && A(e, q) && (b.effectTag |= 16), g(a, b), 2147483647 !== c && !v && n(e, d) ? (b.expirationTime = 2147483647, b = null) : (f(a, b, p), b.memoizedProps = d, b = b.child)) : b = m(a, b); return b; case 6: return null === a && y(b), a = b.pendingProps, null === a && (a = b.memoizedProps), b.memoizedProps = a, null; case 8: b.tag = 7; case 7: e = b.pendingProps; if (J.current) null === e && (e = a && a.memoizedProps, null === e ? l("154") : void 0); else if (null === e || b.memoizedProps === e) e = b.memoizedProps; d = e.children; b.stateNode =
                                        null === a ? Mb(b, b.stateNode, d, c) : db(b, b.stateNode, d, c); b.memoizedProps = e; return b.stateNode; case 9: return null; case 4: a: { R(b, b.stateNode.containerInfo); e = b.pendingProps; if (J.current) null === e && (e = a && a.memoizedProps, null == e ? l("154") : void 0); else if (null === e || b.memoizedProps === e) { b = m(a, b); break a } null === a ? b.child = db(b, null, e, c) : f(a, b, e); b.memoizedProps = e; b = b.child } return b; case 10: a: {
                                            c = b.pendingProps; if (J.current) null === c && (c = b.memoizedProps); else if (null === c || b.memoizedProps === c) { b = m(a, b); break a } f(a,
                                                b, c); b.memoizedProps = c; b = b.child
                                        } return b; default: l("156")
                    }
                }, beginFailedWork: function (a, b, c) { switch (b.tag) { case 2: xb(b); break; case 3: k(b); break; default: l("157") }b.effectTag |= 64; null === a ? b.child = null : b.child !== a.child && (b.child = a.child); if (0 === b.expirationTime || b.expirationTime > c) return D(a, b); b.firstEffect = null; b.lastEffect = null; b.child = null === a ? Mb(b, null, null, c) : db(b, a.child, null, c); 2 === b.tag && (a = b.stateNode, b.memoizedProps = a.props, b.memoizedState = a.state); return b.child }
            }
        }, cg = function (a, b, c) {
            function d(a) {
            a.effectTag |=
                4
            } var e = a.createInstance, f = a.createTextInstance, g = a.appendInitialChild, h = a.finalizeInitialChildren, k = a.prepareUpdate, m = a.persistence, D = b.getRootHostContainer, A = b.popHostContext, v = b.getHostContext, n = b.popHostContainer, L = c.prepareToHydrateHostInstance, R = c.prepareToHydrateHostTextInstance, r = c.popHydrationState, w = void 0, y = void 0, x = void 0; a.mutation ? (w = function (a) { }, y = function (a, b, c, e, f, g, h) { (b.updateQueue = c) && d(b) }, x = function (a, b, c, e) { c !== e && d(b) }) : m ? l("235") : l("236"); return {
                completeWork: function (a, b,
                    c) {
                        var t = b.pendingProps; if (null === t) t = b.memoizedProps; else if (2147483647 !== b.expirationTime || 2147483647 === c) b.pendingProps = null; switch (b.tag) {
                            case 1: return null; case 2: return ae(b), null; case 3: n(b); I(J, b); I(ia, b); t = b.stateNode; t.pendingContext && (t.context = t.pendingContext, t.pendingContext = null); if (null === a || null === a.child) r(b), b.effectTag &= -3; w(b); return null; case 5: A(b); c = D(); var z = b.type; if (null !== a && null != b.stateNode) {
                                var m = a.memoizedProps, K = b.stateNode, yc = v(); K = k(K, z, m, t, c, yc); y(a, b, K, z, m, t, c);
                                a.ref !== b.ref && (b.effectTag |= 128)
                            } else { if (!t) return null === b.stateNode ? l("166") : void 0, null; a = v(); if (r(b)) L(b, c, a) && d(b); else { a = e(z, t, c, a, b); a: for (m = b.child; null !== m;) { if (5 === m.tag || 6 === m.tag) g(a, m.stateNode); else if (4 !== m.tag && null !== m.child) { m.child["return"] = m; m = m.child; continue } if (m === b) break; for (; null === m.sibling;) { if (null === m["return"] || m["return"] === b) break a; m = m["return"] } m.sibling["return"] = m["return"]; m = m.sibling } h(a, z, t, c) && d(b); b.stateNode = a } null !== b.ref && (b.effectTag |= 128) } return null;
                            case 6: if (a && null != b.stateNode) x(a, b, a.memoizedProps, t); else { if ("string" !== typeof t) return null === b.stateNode ? l("166") : void 0, null; a = D(); c = v(); r(b) ? R(b) && d(b) : b.stateNode = f(t, a, c, b) } return null; case 7: (t = b.memoizedProps) ? void 0 : l("165"); b.tag = 8; z = []; a: for ((m = b.stateNode) && (m["return"] = b); null !== m;) {
                                if (5 === m.tag || 6 === m.tag || 4 === m.tag) l("247"); else if (9 === m.tag) z.push(m.type); else if (null !== m.child) { m.child["return"] = m; m = m.child; continue } for (; null === m.sibling;) {
                                    if (null === m["return"] || m["return"] ===
                                        b) break a; m = m["return"]
                                } m.sibling["return"] = m["return"]; m = m.sibling
                            } m = t.handler; t = m(t.props, z); b.child = db(b, null !== a ? a.child : null, t, c); return b.child; case 8: return b.tag = 7, null; case 9: return null; case 10: return null; case 4: return n(b), w(b), null; case 0: l("167"); default: l("156")
                        }
                }
            }
        }, dg = function (a, b) {
            function c(a) { var c = a.ref; if (null !== c) try { c(null) } catch (z) { b(a, z) } } function d(a) {
            "function" === typeof ge && ge(a); switch (a.tag) {
                case 2: c(a); var d = a.stateNode; if ("function" === typeof d.componentWillUnmount) try {
                d.props =
                    a.memoizedProps, d.state = a.memoizedState, d.componentWillUnmount()
                } catch (z) { b(a, z) } break; case 5: c(a); break; case 7: e(a.stateNode); break; case 4: k && g(a)
            }
            } function e(a) { for (var b = a; ;)if (d(b), null === b.child || k && 4 === b.tag) { if (b === a) break; for (; null === b.sibling;) { if (null === b["return"] || b["return"] === a) return; b = b["return"] } b.sibling["return"] = b["return"]; b = b.sibling } else b.child["return"] = b, b = b.child } function f(a) { return 5 === a.tag || 3 === a.tag || 4 === a.tag } function g(a) {
                for (var b = a, c = !1, f = void 0, g = void 0; ;) {
                    if (!c) {
                        c =
                        b["return"]; a: for (; ;) { null === c ? l("160") : void 0; switch (c.tag) { case 5: f = c.stateNode; g = !1; break a; case 3: f = c.stateNode.containerInfo; g = !0; break a; case 4: f = c.stateNode.containerInfo; g = !0; break a }c = c["return"] } c = !0
                    } if (5 === b.tag || 6 === b.tag) e(b), g ? y(f, b.stateNode) : w(f, b.stateNode); else if (4 === b.tag ? f = b.stateNode.containerInfo : d(b), null !== b.child) { b.child["return"] = b; b = b.child; continue } if (b === a) break; for (; null === b.sibling;) { if (null === b["return"] || b["return"] === a) return; b = b["return"]; 4 === b.tag && (c = !1) } b.sibling["return"] =
                        b["return"]; b = b.sibling
                }
            } var h = a.getPublicInstance, k = a.mutation; a = a.persistence; k || (a ? l("235") : l("236")); var m = k.commitMount, D = k.commitUpdate, A = k.resetTextContent, v = k.commitTextUpdate, n = k.appendChild, L = k.appendChildToContainer, R = k.insertBefore, r = k.insertInContainerBefore, w = k.removeChild, y = k.removeChildFromContainer; return {
                commitResetTextContent: function (a) { A(a.stateNode) }, commitPlacement: function (a) {
                    a: { for (var b = a["return"]; null !== b;) { if (f(b)) { var c = b; break a } b = b["return"] } l("160"); c = void 0 } var d =
                        b = void 0; switch (c.tag) { case 5: b = c.stateNode; d = !1; break; case 3: b = c.stateNode.containerInfo; d = !0; break; case 4: b = c.stateNode.containerInfo; d = !0; break; default: l("161") }c.effectTag & 16 && (A(b), c.effectTag &= -17); a: b: for (c = a; ;) {
                            for (; null === c.sibling;) { if (null === c["return"] || f(c["return"])) { c = null; break a } c = c["return"] } c.sibling["return"] = c["return"]; for (c = c.sibling; 5 !== c.tag && 6 !== c.tag;) { if (c.effectTag & 2) continue b; if (null === c.child || 4 === c.tag) continue b; else c.child["return"] = c, c = c.child } if (!(c.effectTag &
                                2)) { c = c.stateNode; break a }
                        } for (var e = a; ;) { if (5 === e.tag || 6 === e.tag) c ? d ? r(b, e.stateNode, c) : R(b, e.stateNode, c) : d ? L(b, e.stateNode) : n(b, e.stateNode); else if (4 !== e.tag && null !== e.child) { e.child["return"] = e; e = e.child; continue } if (e === a) break; for (; null === e.sibling;) { if (null === e["return"] || e["return"] === a) return; e = e["return"] } e.sibling["return"] = e["return"]; e = e.sibling }
                }, commitDeletion: function (a) { g(a); a["return"] = null; a.child = null; a.alternate && (a.alternate.child = null, a.alternate["return"] = null) }, commitWork: function (a,
                    b) { switch (b.tag) { case 2: break; case 5: var c = b.stateNode; if (null != c) { var d = b.memoizedProps; a = null !== a ? a.memoizedProps : d; var e = b.type, f = b.updateQueue; b.updateQueue = null; null !== f && D(c, f, e, a, d, b) } break; case 6: null === b.stateNode ? l("162") : void 0; c = b.memoizedProps; v(b.stateNode, null !== a ? a.memoizedProps : c, c); break; case 3: break; default: l("163") } }, commitLifeCycles: function (a, b) {
                        switch (b.tag) {
                            case 2: var c = b.stateNode; if (b.effectTag & 4) if (null === a) c.props = b.memoizedProps, c.state = b.memoizedState, c.componentDidMount();
                            else { var d = a.memoizedProps; a = a.memoizedState; c.props = b.memoizedProps; c.state = b.memoizedState; c.componentDidUpdate(d, a) } b = b.updateQueue; null !== b && je(b, c); break; case 3: c = b.updateQueue; null !== c && je(c, null !== b.child ? b.child.stateNode : null); break; case 5: c = b.stateNode; null === a && b.effectTag & 4 && m(c, b.type, b.memoizedProps, b); break; case 6: break; case 4: break; default: l("163")
                        }
                    }, commitAttachRef: function (a) { var b = a.ref; if (null !== b) { var c = a.stateNode; switch (a.tag) { case 5: b(h(c)); break; default: b(c) } } }, commitDetachRef: function (a) {
                        a =
                        a.ref; null !== a && a(null)
                    }
            }
        }, la = {}, eg = function (a) {
            function b(a) { a === la ? l("174") : void 0; return a } var c = a.getChildHostContext, d = a.getRootHostContext, e = { current: la }, f = { current: la }, g = { current: la }; return {
                getHostContext: function () { return b(e.current) }, getRootHostContainer: function () { return b(g.current) }, popHostContainer: function (a) { I(e, a); I(f, a); I(g, a) }, popHostContext: function (a) { f.current === a && (I(e, a), I(f, a)) }, pushHostContainer: function (a, b) { M(g, b, a); b = d(b); M(f, a, a); M(e, b, a) }, pushHostContext: function (a) {
                    var d =
                        b(g.current), h = b(e.current); d = c(h, a.type, d); h !== d && (M(f, a, a), M(e, d, a))
                }, resetHostContainer: function () { e.current = la; g.current = la }
            }
        }, fg = function (a) {
            function b(a, b) { var c = new Q(5, null, 0); c.type = "DELETED"; c.stateNode = b; c["return"] = a; c.effectTag = 8; null !== a.lastEffect ? (a.lastEffect.nextEffect = c, a.lastEffect = c) : a.firstEffect = a.lastEffect = c } function c(a, b) {
                switch (a.tag) {
                    case 5: return b = f(b, a.type, a.pendingProps), null !== b ? (a.stateNode = b, !0) : !1; case 6: return b = g(b, a.pendingProps), null !== b ? (a.stateNode = b, !0) :
                        !1; default: return !1
                }
            } function d(a) { for (a = a["return"]; null !== a && 5 !== a.tag && 3 !== a.tag;)a = a["return"]; A = a } var e = a.shouldSetTextContent; a = a.hydration; if (!a) return { enterHydrationState: function () { return !1 }, resetHydrationState: function () { }, tryToClaimNextHydratableInstance: function () { }, prepareToHydrateHostInstance: function () { l("175") }, prepareToHydrateHostTextInstance: function () { l("176") }, popHydrationState: function (a) { return !1 } }; var f = a.canHydrateInstance, g = a.canHydrateTextInstance, h = a.getNextHydratableSibling,
                k = a.getFirstHydratableChild, m = a.hydrateInstance, D = a.hydrateTextInstance, A = null, v = null, n = !1; return {
                    enterHydrationState: function (a) { v = k(a.stateNode.containerInfo); A = a; return n = !0 }, resetHydrationState: function () { v = A = null; n = !1 }, tryToClaimNextHydratableInstance: function (a) { if (n) { var d = v; if (d) { if (!c(a, d)) { d = h(d); if (!d || !c(a, d)) { a.effectTag |= 2; n = !1; A = a; return } b(A, v) } A = a; v = k(d) } else a.effectTag |= 2, n = !1, A = a } }, prepareToHydrateHostInstance: function (a, b, c) {
                        b = m(a.stateNode, a.type, a.memoizedProps, b, c, a); a.updateQueue =
                            b; return null !== b ? !0 : !1
                    }, prepareToHydrateHostTextInstance: function (a) { return D(a.stateNode, a.memoizedProps, a) }, popHydrationState: function (a) { if (a !== A) return !1; if (!n) return d(a), n = !0, !1; var c = a.type; if (5 !== a.tag || "head" !== c && "body" !== c && !e(c, a.memoizedProps)) for (c = v; c;)b(a, c), c = h(c); d(a); v = A ? h(a.stateNode) : null; return !0 }
                }
        }, gg = function (a) {
            function b(a) {
                X = Ba = !0; var b = a.stateNode; b.current === a ? l("177") : void 0; b.isReadyForCommit = !1; bb.current = null; if (1 < a.effectTag) if (null !== a.lastEffect) {
                    a.lastEffect.nextEffect =
                    a; var c = a.firstEffect
                } else c = a; else c = a.firstEffect; za(); for (u = c; null !== u;) { var d = !1, e = void 0; try { for (; null !== u;) { var f = u.effectTag; f & 16 && aa(u); if (f & 128) { var g = u.alternate; null !== g && va(g) } switch (f & -242) { case 2: V(u); u.effectTag &= -3; break; case 6: V(u); u.effectTag &= -3; ca(u.alternate, u); break; case 4: ca(u.alternate, u); break; case 8: ka = !0, na(u), ka = !1 }u = u.nextEffect } } catch (Qc) { d = !0, e = Qc } d && (null === u ? l("178") : void 0, h(u, e), null !== u && (u = u.nextEffect)) } Aa(); b.current = a; for (u = c; null !== u;) {
                    c = !1; d = void 0; try {
                        for (; null !==
                            u;) { var k = u.effectTag; k & 36 && sa(u.alternate, u); k & 128 && ta(u); if (k & 64) switch (e = u, f = void 0, null !== S && (f = S.get(e), S["delete"](e), null == f && null !== e.alternate && (e = e.alternate, f = S.get(e), S["delete"](e))), null == f ? l("184") : void 0, e.tag) { case 2: e.stateNode.componentDidCatch(f.error, { componentStack: f.componentStack }); break; case 3: null === ma && (ma = f.error); break; default: l("157") }var Ma = u.nextEffect; u.nextEffect = null; u = Ma }
                    } catch (Qc) { c = !0, d = Qc } c && (null === u ? l("178") : void 0, h(u, d), null !== u && (u = u.nextEffect))
                } Ba = X = !1;
                "function" === typeof fe && fe(a.stateNode); ua && (ua.forEach(w), ua = null); null !== ma && (a = ma, ma = null, G(a)); b = b.current.expirationTime; 0 === b && (Ia = S = null); return b
            } function c(a) {
                for (; ;) {
                    var b = Y(a.alternate, a, F), c = a["return"], d = a.sibling; var e = a; if (2147483647 === F || 2147483647 !== e.expirationTime) { if (2 !== e.tag && 3 !== e.tag) var f = 0; else f = e.updateQueue, f = null === f ? 0 : f.expirationTime; for (var g = e.child; null !== g;)0 !== g.expirationTime && (0 === f || f > g.expirationTime) && (f = g.expirationTime), g = g.sibling; e.expirationTime = f } if (null !==
                        b) return b; null !== c && (null === c.firstEffect && (c.firstEffect = a.firstEffect), null !== a.lastEffect && (null !== c.lastEffect && (c.lastEffect.nextEffect = a.firstEffect), c.lastEffect = a.lastEffect), 1 < a.effectTag && (null !== c.lastEffect ? c.lastEffect.nextEffect = a : c.firstEffect = a, c.lastEffect = a)); if (null !== d) return d; if (null !== c) a = c; else { a.stateNode.isReadyForCommit = !0; break }
                } return null
            } function d(a) { var b = Q(a.alternate, a, F); null === b && (b = c(a)); bb.current = null; return b } function e(a) {
                var b = T(a.alternate, a, F); null ===
                    b && (b = c(a)); bb.current = null; return b
            } function f(a) { if (null !== S) { if (!(0 === F || F > a)) if (F <= ha) for (; null !== B;)B = k(B) ? e(B) : d(B); else for (; null !== B && !z();)B = k(B) ? e(B) : d(B) } else if (!(0 === F || F > a)) if (F <= ha) for (; null !== B;)B = d(B); else for (; null !== B && !z();)B = d(B) } function g(a, b) {
                Ba ? l("243") : void 0; Ba = !0; a.isReadyForCommit = !1; if (a !== Ja || b !== F || null === B) { for (; -1 < ra;)vb[ra] = null, ra--; wb = ja; ia.current = ja; J.current = !1; P(); Ja = a; F = b; B = yb(Ja.current, null, b) } var c = !1, d = null; try { f(b) } catch (Pc) { c = !0, d = Pc } for (; c;) {
                    if (U) {
                        ma =
                        d; break
                    } var g = B; if (null === g) U = !0; else { var k = h(g, d); null === k ? l("183") : void 0; if (!U) { try { c = k; d = b; for (k = c; null !== g;) { switch (g.tag) { case 2: ae(g); break; case 5: O(g); break; case 3: I(g); break; case 4: I(g) }if (g === k || g.alternate === k) break; g = g["return"] } B = e(c); f(d) } catch (Pc) { c = !0; d = Pc; continue } break } }
                } b = ma; U = Ba = !1; ma = null; null !== b && G(b); return a.isReadyForCommit ? a.current.alternate : null
            } function h(a, b) {
                var c = bb.current = null, d = !1, e = !1, f = null; if (3 === a.tag) c = a, m(a) && (U = !0); else for (var g = a["return"]; null !== g && null ===
                    c;) { 2 === g.tag ? "function" === typeof g.stateNode.componentDidCatch && (d = !0, f = Pa(g), c = g, e = !0) : 3 === g.tag && (c = g); if (m(g)) { if (ka || null !== ua && (ua.has(g) || null !== g.alternate && ua.has(g.alternate))) return null; c = null; e = !1 } g = g["return"] } if (null !== c) {
                    null === Ia && (Ia = new Set); Ia.add(c); var h = ""; g = a; do {
                        a: switch (g.tag) {
                            case 0: case 1: case 2: case 5: var k = g._debugOwner, l = g._debugSource; var Ma = Pa(g); var p = null; k && (p = Pa(k)); k = l; Ma = "\n    in " + (Ma || "Unknown") + (k ? " (at " + k.fileName.replace(/^.*[\\\/]/, "") + ":" + k.lineNumber +
                                ")" : p ? " (created by " + p + ")" : ""); break a; default: Ma = ""
                        }h += Ma; g = g["return"]
                    } while (g); g = h; a = Pa(a); null === S && (S = new Map); b = { componentName: a, componentStack: g, error: b, errorBoundary: d ? c.stateNode : null, errorBoundaryFound: d, errorBoundaryName: f, willRetry: e }; S.set(c, b); try { var n = b.error; n && n.suppressReactErrorLogging || console.error(n) } catch (Rc) { Rc && Rc.suppressReactErrorLogging || console.error(Rc) } X ? (null === ua && (ua = new Set), ua.add(c)) : w(c); return c
                    } null === ma && (ma = b); return null
            } function k(a) {
                return null !== S &&
                    (S.has(a) || null !== a.alternate && S.has(a.alternate))
            } function m(a) { return null !== Ia && (Ia.has(a) || null !== a.alternate && Ia.has(a.alternate)) } function n() { return 20 * (((y() + 100) / 20 | 0) + 1) } function A(a) { return 0 !== Ca ? Ca : Ba ? X ? 1 : F : !ya || a.internalContextTag & 1 ? n() : 1 } function v(a, b) { return r(a, b, !1) } function r(a, b, c) {
                for (; null !== a;) {
                    if (0 === a.expirationTime || a.expirationTime > b) a.expirationTime = b; null !== a.alternate && (0 === a.alternate.expirationTime || a.alternate.expirationTime > b) && (a.alternate.expirationTime = b); if (null ===
                        a["return"]) if (3 === a.tag) { c = a.stateNode; !Ba && c === Ja && b < F && (B = Ja = null, F = 0); var d = c, e = b; fa > Ga && l("185"); if (null === d.nextScheduledRoot) d.remainingExpirationTime = e, null === N ? (Ka = N = d, d.nextScheduledRoot = d) : (N = N.nextScheduledRoot = d, N.nextScheduledRoot = Ka); else { var f = d.remainingExpirationTime; if (0 === f || e < f) d.remainingExpirationTime = e } Na || (Da ? ea && (Ea = d, Fa = 1, t(Ea, Fa)) : 1 === e ? x(1, null) : C(e)); !Ba && c === Ja && b < F && (B = Ja = null, F = 0) } else break; a = a["return"]
                }
            } function w(a) { r(a, 1, !0) } function y() {
                return ha = ((ba() - qa) /
                    10 | 0) + 2
            } function C(a) { if (0 !== Z) { if (a > Z) return; xa(la) } var b = ba() - qa; Z = a; la = wa(H, { timeout: 10 * (a - 2) - b }) } function E() {
                var a = 0, b = null; if (null !== N) for (var c = N, d = Ka; null !== d;) {
                    var e = d.remainingExpirationTime; if (0 === e) {
                    null === c || null === N ? l("244") : void 0; if (d === d.nextScheduledRoot) { Ka = N = d.nextScheduledRoot = null; break } else if (d === Ka) Ka = e = d.nextScheduledRoot, N.nextScheduledRoot = e, d.nextScheduledRoot = null; else if (d === N) { N = c; N.nextScheduledRoot = Ka; d.nextScheduledRoot = null; break } else c.nextScheduledRoot = d.nextScheduledRoot,
                        d.nextScheduledRoot = null; d = c.nextScheduledRoot
                    } else { if (0 === a || e < a) a = e, b = d; if (d === N) break; c = d; d = d.nextScheduledRoot }
                } c = Ea; null !== c && c === b ? fa++ : fa = 0; Ea = b; Fa = a
            } function H(a) { x(0, a) } function x(a, b) { W = b; for (E(); null !== Ea && 0 !== Fa && (0 === a || Fa <= a) && !oa;)t(Ea, Fa), E(); null !== W && (Z = 0, la = -1); 0 !== Fa && C(Fa); W = null; oa = !1; fa = 0; if (da) throw a = pa, pa = null, da = !1, a; } function t(a, c) {
                Na ? l("245") : void 0; Na = !0; if (c <= y()) {
                    var d = a.finishedWork; null !== d ? (a.finishedWork = null, a.remainingExpirationTime = b(d)) : (a.finishedWork = null,
                        d = g(a, c), null !== d && (a.remainingExpirationTime = b(d)))
                } else d = a.finishedWork, null !== d ? (a.finishedWork = null, a.remainingExpirationTime = b(d)) : (a.finishedWork = null, d = g(a, c), null !== d && (z() ? a.finishedWork = d : a.remainingExpirationTime = b(d))); Na = !1
            } function z() { return null === W || W.timeRemaining() > Ha ? !1 : oa = !0 } function G(a) { null === Ea ? l("246") : void 0; Ea.remainingExpirationTime = 0; da || (da = !0, pa = a) } var q = eg(a), p = fg(a), I = q.popHostContainer, O = q.popHostContext, P = q.resetHostContainer, M = bg(a, q, p, v, A), Q = M.beginWork, T = M.beginFailedWork,
                Y = cg(a, q, p).completeWork; q = dg(a, h); var aa = q.commitResetTextContent, V = q.commitPlacement, na = q.commitDeletion, ca = q.commitWork, sa = q.commitLifeCycles, ta = q.commitAttachRef, va = q.commitDetachRef, ba = a.now, wa = a.scheduleDeferredCallback, xa = a.cancelDeferredCallback, ya = a.useSyncScheduling, za = a.prepareForCommit, Aa = a.resetAfterCommit, qa = ba(), ha = 2, Ca = 0, Ba = !1, B = null, Ja = null, F = 0, u = null, S = null, Ia = null, ua = null, ma = null, U = !1, X = !1, ka = !1, Ka = null, N = null, Z = 0, la = -1, Na = !1, Ea = null, Fa = 0, oa = !1, da = !1, pa = null, W = null, Da = !1, ea = !1,
                    Ga = 1E3, fa = 0, Ha = 1; return { computeAsyncExpiration: n, computeExpirationForFiber: A, scheduleWork: v, batchedUpdates: function (a, b) { var c = Da; Da = !0; try { return a(b) } finally { (Da = c) || Na || x(1, null) } }, unbatchedUpdates: function (a) { if (Da && !ea) { ea = !0; try { return a() } finally { ea = !1 } } return a() }, flushSync: function (a) { var b = Da; Da = !0; try { a: { var c = Ca; Ca = 1; try { var d = a(); break a } finally { Ca = c } d = void 0 } return d } finally { Da = b, Na ? l("187") : void 0, x(1, null) } }, deferredUpdates: function (a) { var b = Ca; Ca = n(); try { return a() } finally { Ca = b } } }
        },
        Te = function (a) {
            function b(a) { a = wf(a); return null === a ? null : a.stateNode } var c = a.getPublicInstance; a = gg(a); var d = a.computeAsyncExpiration, e = a.computeExpirationForFiber, f = a.scheduleWork; return {
                createContainer: function (a, b) { var c = new Q(3, null, 0); a = { current: c, containerInfo: a, pendingChildren: null, remainingExpirationTime: 0, isReadyForCommit: !1, finishedWork: null, context: null, pendingContext: null, hydrate: b, nextScheduledRoot: null }; return c.stateNode = a }, updateContainer: function (a, b, c, m) {
                    var g = b.current; if (c) {
                        c =
                        c._reactInternalFiber; var h; b: { 2 === Qa(c) && 2 === c.tag ? void 0 : l("170"); for (h = c; 3 !== h.tag;) { if (Ua(h)) { h = h.stateNode.__reactInternalMemoizedMergedChildContext; break b } (h = h["return"]) ? void 0 : l("171") } h = h.stateNode.context } c = Ua(c) ? ce(c, h) : h
                    } else c = ja; null === b.context ? b.context = c : b.pendingContext = c; b = m; b = void 0 === b ? null : b; m = null != a && null != a.type && null != a.type.prototype && !0 === a.type.prototype.unstable_isAsyncReactComponent ? d() : e(g); Bb(g, {
                        expirationTime: m, partialState: { element: a }, callback: b, isReplace: !1, isForced: !1,
                        nextCallback: null, next: null
                    }); f(g, m)
                }, batchedUpdates: a.batchedUpdates, unbatchedUpdates: a.unbatchedUpdates, deferredUpdates: a.deferredUpdates, flushSync: a.flushSync, getPublicRootInstance: function (a) { a = a.current; if (!a.child) return null; switch (a.child.tag) { case 5: return c(a.child.stateNode); default: return a.child.stateNode } }, findHostInstance: b, findHostInstanceWithNoPortals: function (a) { a = xf(a); return null === a ? null : a.stateNode }, injectIntoDevTools: function (a) {
                    var c = a.findFiberByHostInstance; return Af(C({},
                        a, { findHostInstanceByFiber: function (a) { return b(a) }, findFiberByHostInstance: function (a) { return c ? c(a) : null } }))
                }
            }
        }, Ue = Object.freeze({ default: Te }), Sc = Ue && Te || Ue, hg = Sc["default"] ? Sc["default"] : Sc, Ve = "object" === typeof performance && "function" === typeof performance.now, Nb = void 0; Nb = Ve ? function () { return performance.now() } : function () { return Date.now() }; var Ob = void 0, Pb = void 0; if (P.canUseDOM) if ("function" !== typeof requestIdleCallback || "function" !== typeof cancelIdleCallback) {
            var Qb = null, Rb = !1, eb = -1, fb = !1, gb =
                0, Sb = 33, hb = 33; var Tc = Ve ? { didTimeout: !1, timeRemaining: function () { var a = gb - performance.now(); return 0 < a ? a : 0 } } : { didTimeout: !1, timeRemaining: function () { var a = gb - Date.now(); return 0 < a ? a : 0 } }; var We = "__reactIdleCallback$" + Math.random().toString(36).slice(2); window.addEventListener("message", function (a) { if (a.source === window && a.data === We) { Rb = !1; a = Nb(); if (0 >= gb - a) if (-1 !== eb && eb <= a) Tc.didTimeout = !0; else { fb || (fb = !0, requestAnimationFrame(Xe)); return } else Tc.didTimeout = !1; eb = -1; a = Qb; Qb = null; null !== a && a(Tc) } }, !1);
            var Xe = function (a) { fb = !1; var b = a - gb + hb; b < hb && Sb < hb ? (8 > b && (b = 8), hb = b < Sb ? Sb : b) : Sb = b; gb = a + hb; Rb || (Rb = !0, window.postMessage(We, "*")) }; Ob = function (a, b) { Qb = a; null != b && "number" === typeof b.timeout && (eb = Nb() + b.timeout); fb || (fb = !0, requestAnimationFrame(Xe)); return 0 }; Pb = function () { Qb = null; Rb = !1; eb = -1 }
        } else Ob = window.requestIdleCallback, Pb = window.cancelIdleCallback; else Ob = function (a) { return setTimeout(function () { a({ timeRemaining: function () { return Infinity } }) }) }, Pb = function (a) { clearTimeout(a) }; var Df = /^[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$/,
            ne = {}, me = {}, Tb = void 0, Be = function (a) { return "undefined" !== typeof MSApp && MSApp.execUnsafeLocalFunction ? function (b, c, d, e) { MSApp.execUnsafeLocalFunction(function () { return a(b, c, d, e) }) } : a }(function (a, b) { if ("http://www.w3.org/2000/svg" !== a.namespaceURI || "innerHTML" in a) a.innerHTML = b; else { Tb = Tb || document.createElement("div"); Tb.innerHTML = "\x3csvg\x3e" + b + "\x3c/svg\x3e"; for (b = Tb.firstChild; a.firstChild;)a.removeChild(a.firstChild); for (; b.firstChild;)a.appendChild(b.firstChild) } }), Ic = function (a, b) {
                if (b) {
                    var c =
                        a.firstChild; if (c && c === a.lastChild && 3 === c.nodeType) { c.nodeValue = b; return }
                } a.textContent = b
            }, Za = {
                animationIterationCount: !0, borderImageOutset: !0, borderImageSlice: !0, borderImageWidth: !0, boxFlex: !0, boxFlexGroup: !0, boxOrdinalGroup: !0, columnCount: !0, columns: !0, flex: !0, flexGrow: !0, flexPositive: !0, flexShrink: !0, flexNegative: !0, flexOrder: !0, gridRow: !0, gridRowEnd: !0, gridRowSpan: !0, gridRowStart: !0, gridColumn: !0, gridColumnEnd: !0, gridColumnSpan: !0, gridColumnStart: !0, fontWeight: !0, lineClamp: !0, lineHeight: !0, opacity: !0,
                order: !0, orphans: !0, tabSize: !0, widows: !0, zIndex: !0, zoom: !0, fillOpacity: !0, floodOpacity: !0, stopOpacity: !0, strokeDasharray: !0, strokeDashoffset: !0, strokeMiterlimit: !0, strokeOpacity: !0, strokeWidth: !0
            }, ig = ["Webkit", "ms", "Moz", "O"]; Object.keys(Za).forEach(function (a) { ig.forEach(function (b) { b = b + a.charAt(0).toUpperCase() + a.substring(1); Za[b] = Za[a] }) }); var Ff = C({ menuitem: !0 }, { area: !0, base: !0, br: !0, col: !0, embed: !0, hr: !0, img: !0, input: !0, keygen: !0, link: !0, meta: !0, param: !0, source: !0, track: !0, wbr: !0 }), $a = G.thatReturns(""),
                Z = {
                    topAbort: "abort", topCanPlay: "canplay", topCanPlayThrough: "canplaythrough", topDurationChange: "durationchange", topEmptied: "emptied", topEncrypted: "encrypted", topEnded: "ended", topError: "error", topLoadedData: "loadeddata", topLoadedMetadata: "loadedmetadata", topLoadStart: "loadstart", topPause: "pause", topPlay: "play", topPlaying: "playing", topProgress: "progress", topRateChange: "ratechange", topSeeked: "seeked", topSeeking: "seeking", topStalled: "stalled", topSuspend: "suspend", topTimeUpdate: "timeupdate", topVolumeChange: "volumechange",
                    topWaiting: "waiting"
                }, jg = Object.freeze({
                    createElement: ye, createTextNode: ze, setInitialProperties: Ae, diffProperties: Ce, updateProperties: De, diffHydratedProperties: Ee, diffHydratedText: Fe, warnForUnmatchedText: function (a, b) { }, warnForDeletedHydratableElement: function (a, b) { }, warnForDeletedHydratableText: function (a, b) { }, warnForInsertedHydratedElement: function (a, b, c) { }, warnForInsertedHydratedText: function (a, b) { }, restoreControlledState: function (a, b, c) {
                        switch (b) {
                            case "input": Cc(a, c); b = c.name; if ("radio" === c.type &&
                                null != b) { for (c = a; c.parentNode;)c = c.parentNode; c = c.querySelectorAll("input[name\x3d" + JSON.stringify("" + b) + '][type\x3d"radio"]'); for (b = 0; b < c.length; b++) { var d = c[b]; if (d !== a && d.form === a.form) { var e = fd(d); e ? void 0 : l("90"); Bd(d); Cc(d, e) } } } break; case "textarea": ue(a, c); break; case "select": b = c.value, null != b && ka(a, !!c.multiple, b, !1)
                        }
                    }
                }); Qe.injectFiberControlledHostComponent(jg); var Uc = null, Vc = null, E = hg({
                    getRootHostContext: function (a) {
                        var b = a.nodeType; switch (b) {
                            case 9: case 11: a = (a = a.documentElement) ? a.namespaceURI :
                                Fc(null, ""); break; default: b = 8 === b ? a.parentNode : a, a = b.namespaceURI || null, b = b.tagName, a = Fc(a, b)
                        }return a
                    }, getChildHostContext: function (a, b) { return Fc(a, b) }, getPublicInstance: function (a) { return a }, prepareForCommit: function () {
                        Uc = Ra; var a = nc(); if (lc(a)) {
                            if ("selectionStart" in a) var b = { start: a.selectionStart, end: a.selectionEnd }; else a: {
                                var c = window.getSelection && window.getSelection(); if (c && 0 !== c.rangeCount) {
                                    b = c.anchorNode; var d = c.anchorOffset, e = c.focusNode; c = c.focusOffset; try { b.nodeType, e.nodeType } catch (K) {
                                        b =
                                        null; break a
                                    } var f = 0, g = -1, h = -1, k = 0, l = 0, n = a, r = null; b: for (; ;) { for (var v; ;) { n !== b || 0 !== d && 3 !== n.nodeType || (g = f + d); n !== e || 0 !== c && 3 !== n.nodeType || (h = f + c); 3 === n.nodeType && (f += n.nodeValue.length); if (null === (v = n.firstChild)) break; r = n; n = v } for (; ;) { if (n === a) break b; r === b && ++k === d && (g = f); r === e && ++l === c && (h = f); if (null !== (v = n.nextSibling)) break; n = r; r = n.parentNode } n = v } b = -1 === g || -1 === h ? null : { start: g, end: h }
                                } else b = null
                            } b = b || { start: 0, end: 0 }
                        } else b = null; Vc = { focusedElem: a, selectionRange: b }; ic(!1)
                    }, resetAfterCommit: function () {
                        var a =
                            Vc, b = nc(), c = a.focusedElem, d = a.selectionRange; if (b !== c && Nd(document.documentElement, c)) {
                                if (lc(c)) if (b = d.start, a = d.end, void 0 === a && (a = b), "selectionStart" in c) c.selectionStart = b, c.selectionEnd = Math.min(a, c.value.length); else if (window.getSelection) {
                                    b = window.getSelection(); var e = c[jd()].length; a = Math.min(d.start, e); d = void 0 === d.end ? a : Math.min(d.end, e); !b.extend && a > d && (e = d, d = a, a = e); e = Qd(c, a); var f = Qd(c, d); if (e && f && (1 !== b.rangeCount || b.anchorNode !== e.node || b.anchorOffset !== e.offset || b.focusNode !== f.node ||
                                        b.focusOffset !== f.offset)) { var g = document.createRange(); g.setStart(e.node, e.offset); b.removeAllRanges(); a > d ? (b.addRange(g), b.extend(f.node, f.offset)) : (g.setEnd(f.node, f.offset), b.addRange(g)) }
                                } b = []; for (a = c; a = a.parentNode;)1 === a.nodeType && b.push({ element: a, left: a.scrollLeft, top: a.scrollTop }); try { c.focus() } catch (h) { } for (c = 0; c < b.length; c++)a = b[c], a.element.scrollLeft = a.left, a.element.scrollTop = a.top
                            } Vc = null; ic(Uc); Uc = null
                    }, createInstance: function (a, b, c, d, e) { a = ye(a, b, c, d); a[O] = e; a[ea] = b; return a }, appendInitialChild: function (a,
                        b) { a.appendChild(b) }, finalizeInitialChildren: function (a, b, c, d) { Ae(a, b, c, d); a: { switch (b) { case "button": case "input": case "select": case "textarea": a = !!c.autoFocus; break a }a = !1 } return a }, prepareUpdate: function (a, b, c, d, e, f) { return Ce(a, b, c, d, e) }, shouldSetTextContent: function (a, b) { return "textarea" === a || "string" === typeof b.children || "number" === typeof b.children || "object" === typeof b.dangerouslySetInnerHTML && null !== b.dangerouslySetInnerHTML && "string" === typeof b.dangerouslySetInnerHTML.__html }, shouldDeprioritizeSubtree: function (a,
                            b) { return !!b.hidden }, createTextInstance: function (a, b, c, d) { a = ze(a, b); a[O] = d; return a }, now: Nb, mutation: {
                                commitMount: function (a, b, c, d) { a.focus() }, commitUpdate: function (a, b, c, d, e, f) { a[ea] = e; De(a, b, c, d, e) }, resetTextContent: function (a) { a.textContent = "" }, commitTextUpdate: function (a, b, c) { a.nodeValue = c }, appendChild: function (a, b) { a.appendChild(b) }, appendChildToContainer: function (a, b) { 8 === a.nodeType ? a.parentNode.insertBefore(b, a) : a.appendChild(b) }, insertBefore: function (a, b, c) { a.insertBefore(b, c) }, insertInContainerBefore: function (a,
                                    b, c) { 8 === a.nodeType ? a.parentNode.insertBefore(b, c) : a.insertBefore(b, c) }, removeChild: function (a, b) { a.removeChild(b) }, removeChildFromContainer: function (a, b) { 8 === a.nodeType ? a.parentNode.removeChild(b) : a.removeChild(b) }
                            }, hydration: {
                                canHydrateInstance: function (a, b, c) { return 1 !== a.nodeType || b.toLowerCase() !== a.nodeName.toLowerCase() ? null : a }, canHydrateTextInstance: function (a, b) { return "" === b || 3 !== a.nodeType ? null : a }, getNextHydratableSibling: function (a) {
                                    for (a = a.nextSibling; a && 1 !== a.nodeType && 3 !== a.nodeType;)a =
                                        a.nextSibling; return a
                                }, getFirstHydratableChild: function (a) { for (a = a.firstChild; a && 1 !== a.nodeType && 3 !== a.nodeType;)a = a.nextSibling; return a }, hydrateInstance: function (a, b, c, d, e, f) { a[O] = f; a[ea] = c; return Ee(a, b, c, e, d) }, hydrateTextInstance: function (a, b, c) { a[O] = c; return Fe(a, b) }, didNotMatchHydratedContainerTextInstance: function (a, b, c) { }, didNotMatchHydratedTextInstance: function (a, b, c, d, e) { }, didNotHydrateContainerInstance: function (a, b) { }, didNotHydrateInstance: function (a, b, c, d) { }, didNotFindHydratableContainerInstance: function (a,
                                    b, c) { }, didNotFindHydratableContainerTextInstance: function (a, b) { }, didNotFindHydratableInstance: function (a, b, c, d, e) { }, didNotFindHydratableTextInstance: function (a, b, c, d) { }
                            }, scheduleDeferredCallback: Ob, cancelDeferredCallback: Pb, useSyncScheduling: !0
                }); ec = E.batchedUpdates; He.prototype.render = function (a, b) { E.updateContainer(a, this._reactRootContainer, null, b) }; He.prototype.unmount = function (a) { E.updateContainer(null, this._reactRootContainer, null, a) }; var Ye = {
                    createPortal: Ge, findDOMNode: function (a) {
                        if (null ==
                            a) return null; if (1 === a.nodeType) return a; var b = a._reactInternalFiber; if (b) return E.findHostInstance(b); "function" === typeof a.render ? l("188") : l("213", Object.keys(a))
                    }, hydrate: function (a, b, c) { return Hb(null, a, b, !0, c) }, render: function (a, b, c) { return Hb(null, a, b, !1, c) }, unstable_renderSubtreeIntoContainer: function (a, b, c, d) { null == a || void 0 === a._reactInternalFiber ? l("38") : void 0; return Hb(a, b, c, !1, d) }, unmountComponentAtNode: function (a) {
                        Jc(a) ? void 0 : l("40"); return a._reactRootContainer ? (E.unbatchedUpdates(function () {
                            Hb(null,
                                null, a, !1, function () { a._reactRootContainer = null })
                        }), !0) : !1
                    }, unstable_createPortal: Ge, unstable_batchedUpdates: cc, unstable_deferredUpdates: E.deferredUpdates, flushSync: E.flushSync, __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: { EventPluginHub: Mf, EventPluginRegistry: Lf, EventPropagators: Nf, ReactControlledComponent: Rf, ReactDOMComponentTree: Oe, ReactDOMEventListener: Uf }
                }; E.injectIntoDevTools({ findFiberByHostInstance: W, bundleType: 0, version: "16.2.0", rendererPackageName: "react-dom" }); var Ze = Object.freeze({ default: Ye }),
                    Wc = Ze && Ye || Ze; return Wc["default"] ? Wc["default"] : Wc
});;
//HEADROOM
var myElement = document.querySelector("nav");
if (myElement) {
    var headroom = new Headroom(myElement);
    headroom.init();
}
//TEXT ROTATOR
$(".rotate").textrotator({
    animation: "dissolve",
    separator: "|",
    speed: 5000 // How many milliseconds until the next word show.
});
$(".rotate").show();
//Smooth scroll
smoothScroll.init({
    selector: 'a[href^="#"]',
    selectorHeader: null,
    speed: 500,
    easing: 'easeInOutCubic',
    offset: 0,
    callback: function (anchor, toggle) { } // Function to run after scrolling
});

//set up the owl carosel
$(document).ready(function () {
    $(".owl-default").owlCarousel({
        autoplay: true,
        autoplayTimeout: 3000,
        autoplayHoverPause: true,
        nav: true,
        navText: ['<i class="fa fa-arrow-left"></i>', '<i class="fa fa-arrow-right"></i>'],
        items: 1,
        loop: true,
        responsive: {
            480: { items: 1 },
            768: { items: 3 },
            1024: {
                items: 4 // from 768 screen width to 1024 8 items
            }
        }
    });

    $(".owl-cover").owlCarousel({
        autoplay: true,
        autoplayTimeout: 5000,
        autoplayHoverPause: true,
        nav: true,
        navText: ['<i class="fa fa-arrow-left"></i>', '<i class="fa fa-arrow-right"></i>'],
        items: 1,
        loop: true,
        responsive: {
            480: { items: 1 },
            768: { items: 1 },
            1024: {
                items: 1
            }
        }
    });

    
    $(".initial-hidden").removeClass("hidden");
});

//set up the owl carosel
$(".owl-single-product").owlCarousel({
    autoplay: false,
    nav: true,
    navText: ['<i class="fa fa-arrow-left"></i>', '<i class="fa fa-arrow-right"></i>'],
    loop: true,
    items: 1
});

//MEGA MENU
$(".mega-menu").parent(".nav-item").hover((e) => {
    $(e.currentTarget).children(".mega-menu").addClass('fadeInUp animated').show();
}, (e) => {
    $(e.currentTarget).children(".mega-menu").removeClass('fadeInUp animated').hide();
});
;
var Constants;
(function (Constants) {
    Constants.SORT_ASC = "asc";
    Constants.SORT_DESC = "desc";
    Constants.PAGE_SIZE = 20;
    Constants.STATE_INITIAL = "init";
    Constants.STATE_READY = "ready";
    Constants.STATE_BUSY = "busy";
    Constants.STATE_ERROR = "error";
    Constants.REQUEST_VERIFICATION_TOKEN = $('input[name="__RequestVerificationToken"]').val();
    Constants.API_CLIENT_ID = "967691c1-b592-425d-aea6-a6e2bcb1e877";
    Constants.EXTRA_ONE_OFF_PRODUCT_VARIANT_ID = "2e2529e6-f2b8-44c3-ab22-13bf9674866f";
    Constants.AUTHENTICATED = $("#authenticated").val() == "True";
    Constants.GLOBAL_REFRESH = ko.observable();
})(Constants || (Constants = {}));
//# sourceMappingURL=constants.js.map;
/**************************************************
/* Bind any loaded models to the correct elements *
/**************************************************/
$(document).ready(function () {
    //bind any knockout models
    $('[data-model]').each(function (index, element) {
        if ($(element).data('model')) {
            var model = InstanceLoader.getInstance(window, $(element).data('model'))
                .createModel();
            ko.applyBindings(model, element);
        }
    });
    //append the browser offset to the server so it's available serverside
    $.ajaxPrefilter(function (options) {
        if (!options.beforeSend) {
            options.beforeSend = function (xhr) {
                xhr.setRequestHeader('timezone-offset', (new Date()).getTimezoneOffset());
            };
        }
    });
    $('.date-picker').datetimepicker({
        viewMode: 'years',
        format: 'DD/MM/YY'
    });
});
/*********************************************
/* Used to load models from their name
/********************************************/
var InstanceLoader = /** @class */ (function () {
    function InstanceLoader() {
    }
    InstanceLoader.getInstance = function (context, name) {
        var args = [];
        for (var _i = 2; _i < arguments.length; _i++) {
            args[_i - 2] = arguments[_i];
        }
        //Provide support for classes nested one module deep
        if (name.split('.').length == 2) {
            context = context[name.split('.')[0]];
            name = name.split('.')[1];
        }
        var instance = Object.create(context[name].prototype);
        instance.constructor.apply(instance, args);
        return instance;
    };
    return InstanceLoader;
}());
var BindablePageModel = /** @class */ (function () {
    function BindablePageModel() {
        this.pageReady = ko.observable(false);
        this.loading = ko.observable(true);
    }
    return BindablePageModel;
}());
var BindableIndexModel = /** @class */ (function () {
    function BindableIndexModel() {
        this.state = ko.observable(Constants.STATE_INITIAL);
        this.page = ko.observable(parseInt(Utilities.Default(StorageService.Get(this.key("page")), 1))); //current page
        this.pageSize = ko.observable(parseInt(Utilities.Default(StorageService.Get(this.key("pageSize")), 25)));
        this.sort = ko.observable(Utilities.Default(StorageService.Get(this.key("sort")), "Created"));
        this.sortDirection = ko.observable(Utilities.Default(StorageService.Get(this.key("sortDirection")), Constants.SORT_DESC));
        this.search = ko.observable(StorageService.Get(this.key("search")));
        this.queryFilters = ko.observableArray();
        this.filteredTo = ko.observable();
        this.filter = ko.observable(StorageService.Get(this.key("filter")));
        this.data = ko.observableArray(); //data to display
        this.total = ko.observable(); //total number of items
        var self = this;
        //Persist existing filters
        var existingFilters = StorageService.Get(self.key("queryFilters"));
        if (existingFilters) {
            self.queryFilters(JSON.parse(existingFilters));
        }
        ko.computed(function () {
            var page = self.page();
            if (page) {
                StorageService.Store(self.key("page"), page + "");
            }
        });
        ko.computed(function () {
            var queryFilters = self.queryFilters();
            if (queryFilters) {
                StorageService.Store(self.key("queryFilters"), JSON.stringify(queryFilters));
            }
            $("[data-filter]").each(function (i, element) {
                var filterKey = $(element).data("filter");
                var existing = _(queryFilters).find(function (e) {
                    return e.key == filterKey;
                });
                $(element).find("li").removeClass("active");
                if (existing) {
                    $(element).find('*[data-filter-value="' + existing.value + '"]').parent("li").addClass("active");
                }
                else {
                    $(element).find('*[data-filter-value=""]').parent("li").addClass("active");
                }
            });
        });
        ko.computed(function () {
            var pageSize = self.pageSize();
            if (pageSize) {
                StorageService.Store(self.key("pageSize"), pageSize + "");
            }
        });
        ko.computed(function () {
            var sort = self.sort();
            if (sort) {
                StorageService.Store(self.key("sort"), sort);
            }
        });
        ko.computed(function () {
            var sortDirection = self.sortDirection();
            if (sortDirection) {
                StorageService.Store(self.key("sortDirection"), sortDirection);
            }
        });
        ko.computed(function () {
            var search = self.search();
            if (search) {
                StorageService.Store(self.key("search"), search);
            }
            else {
                StorageService.Clear(self.key("search"));
            }
        });
        self.toggleFilter = function (filter) {
            if (self.filter() == filter) {
                self.filter(undefined);
            }
            else {
                self.filter(filter);
            }
        };
        self.toggleSort = function (sort) {
            if (self.sort() == sort) {
                if (self.sortDirection() == Constants.SORT_ASC) {
                    self.sortDirection(Constants.SORT_DESC);
                }
                else {
                    self.sortDirection(Constants.SORT_ASC);
                }
            }
            else {
                self.sort(sort);
            }
        };
        //Link up filters
        $("[data-filter]").each(function (i, element) {
            var filterKey = $(element).data("filter");
            $(element).find("[data-filter-value]").click(function (eventData) {
                var filterValue = $(eventData.target).data("filter-value");
                var currentFilters = self.queryFilters();
                var existing = _(currentFilters).find(function (e) {
                    return e.key == filterKey;
                });
                if (filterValue) {
                    if (existing) {
                        existing.value = filterValue;
                        self.queryFilters.valueHasMutated();
                    }
                    else {
                        self.queryFilters.push({
                            key: filterKey,
                            value: filterValue
                        });
                    }
                }
                else {
                    if (existing) {
                        self.queryFilters.remove(existing);
                    }
                }
                return false;
            });
        });
    }
    return BindableIndexModel;
}());
//# sourceMappingURL=init.js.map;
ko.bindingHandlers.initValue = {
    init: function (element, valueAccessor) {
        valueAccessor()($(element).val());
    }
};
ko.bindingHandlers.money = {
    update: function (element, valueAccessor, allBindingsAccessor) {
        var value = ko.utils.unwrapObservable(valueAccessor());
        var parsedVal = (Math.round(parseFloat(value) * 100) / 100).toFixed(2);
        ko.bindingHandlers.text.update(element, function () { return parsedVal; });
    }
};
ko.bindingHandlers.markdown = {
    update: function (element, valueAccessor, allBindingsAccessor) {
        var value = ko.utils.unwrapObservable(valueAccessor());
        var converter = new showdown.Converter();
        ko.bindingHandlers.html.update(element, function () { return converter.makeHtml(value); });
    }
};
ko.bindingHandlers.foreachprop = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        var value = ko.utils.unwrapObservable(valueAccessor());
        var properties = Utilities.GetProperties(value);
        ko.applyBindingsToNode(element, { foreach: properties }, bindingContext);
        return { controlsDescendantBindings: true };
    }
};
ko.bindingHandlers.nzDate = {
    update: function (element, valueAccessor, allBindingsAccessor) {
        var value = ko.utils.unwrapObservable(valueAccessor());
        var dt = moment.utc(value).local().locale('en-NZ');
        ko.bindingHandlers.text.update(element, function () { return dt.format("DD/MM/YYYY hh:mm a"); });
    },
};
ko.bindingHandlers.nzDateOnly = {
    update: function (element, valueAccessor, allBindingsAccessor) {
        var value = ko.utils.unwrapObservable(valueAccessor());
        var dt = moment.utc(value).local().locale('en-NZ');
        ko.bindingHandlers.text.update(element, function () { return dt.format('LL'); });
    },
};
ko.bindingHandlers.nzDateShort = {
    update: function (element, valueAccessor, allBindingsAccessor) {
        var value = ko.utils.unwrapObservable(valueAccessor());
        var dt = moment.utc(value).local().locale('en-NZ');
        ko.bindingHandlers.text.update(element, function () { return dt.format("DD/MM/YY"); });
    },
};
ko.bindingHandlers.capitalise = {
    update: function (element, valueAccessor, allBindingsAccessor) {
        var value = ko.utils.unwrapObservable(valueAccessor());
        ko.bindingHandlers.text.update(element, function () { return value.charAt(0).toUpperCase() + value.slice(1); });
    },
};
ko.bindingHandlers.nzHumanDate = {
    update: function (element, valueAccessor, allBindingsAccessor) {
        var value = ko.utils.unwrapObservable(valueAccessor());
        var dt = moment.utc(value);
        var now = moment.utc();
        if (moment.duration(now.diff(dt)).asHours() < 23) {
            ko.bindingHandlers.text.update(element, function () { return moment.duration(dt.diff(now)).humanize(true); });
        }
        else if (moment.duration(now.diff(dt)).asDays() < 365) {
            ko.bindingHandlers.text.update(element, function () { return dt.local().locale('en-NZ').format('MMM DD, h:mm a'); });
        }
        else {
            ko.bindingHandlers.text.update(element, function () { return dt.local().locale('en-NZ').format('DD/MM/YY'); });
        }
    }
};
ko.bindingHandlers.birthdayWithYears = {
    update: function (element, valueAccessor, allBindingsAccessor) {
        var value = ko.utils.unwrapObservable(valueAccessor());
        var dt = moment.utc(value);
        ko.bindingHandlers.text.update(element, function () { return dt.local().locale('en-NZ').format('DD/MM/YY') + ", age: " + moment().diff(dt, 'years'); });
    }
};
ko.bindingHandlers.numberToText = {
    update: function (element, valueAccessor, allBindingsAccessor) {
        var value = ko.utils.unwrapObservable(valueAccessor());
        var number = "";
        if (value == 0)
            number = "Zero";
        if (value == 1)
            number = "One";
        if (value == 2)
            number = "Two";
        if (value == 3)
            number = "Three";
        if (value == 4)
            number = "Four";
        if (value == 5)
            number = "Five";
        if (value == 6)
            number = "Six";
        if (value == 7)
            number = "Seven";
        if (value == 8)
            number = "Eight";
        if (value == 9)
            number = "Nine";
        if (value == 10)
            number = "Ten";
        if (value == 11)
            number = "Eleven";
        if (value == 12)
            number = "Twelve";
        ko.bindingHandlers.text.update(element, function () { return number; });
    },
};
ko.bindingHandlers.yesNo = {
    update: function (element, valueAccessor) {
        // defaults to false
        var val = ko.utils.unwrapObservable(valueAccessor()) || false;
        if (val)
            $(element).text("Yes");
        else
            $(element).text("No");
    }
};
ko.bindingHandlers.fadeVisible = {
    init: function (element, valueAccessor) {
        // Initially set the element to be instantly visible/hidden depending on the value
        var value = ko.utils.unwrapObservable(valueAccessor()) || false;
        $(element).toggle(ko.unwrap(value)); // Use "unwrapObservable" so we can handle values that may or may not be observable
    },
    update: function (element, valueAccessor) {
        // Whenever the value subsequently changes, slowly fade the element in or out
        var value = ko.utils.unwrapObservable(valueAccessor()) || false;
        ko.unwrap(value) ? $(element).fadeIn() : $(element).fadeOut();
    }
};
//# sourceMappingURL=knockout.bindings.js.map;
$(document).ready(function () {
    $('[data-react-model]').each(function (index, element) {
        if ($(element).data('react-model')) {
            $(element).attr('id', $(element).data('react-model'));
            var modelScript = document.createElement('script');
            modelScript.setAttribute('src', '/scripts/app/' + $(element).data('react-model') + '.js');
            document.head.appendChild(modelScript);
        }
    });
});
//# sourceMappingURL=react-bootstrap.js.map;
/*********************************************
/* Common functions across Bark Bag
/********************************************/
var Utilities;
(function (Utilities) {
    function CalculateWeightOfOrder(order) {
        var weight = 0;
        _(order.orderLineItems).each(function (ol) {
            if (ol.requiresShipping && ol.fulfilled != null && ol.shipmentId == null) {
                weight += ol.productVariant.grams;
            }
        });
        return Math.max(1, weight / 1000);
    }
    Utilities.CalculateWeightOfOrder = CalculateWeightOfOrder;
    ;
    function GetProperties(obj) {
        var properties = [];
        for (var key in obj) {
            if (obj.hasOwnProperty(key)) {
                properties.push({ key: key, value: obj[key] });
            }
        }
        return properties;
    }
    Utilities.GetProperties = GetProperties;
    function NearBarkday(dog) {
        if (dog && dog.birthday) {
            var barkday = moment.utc(dog.birthday).year(moment().year()).add('days', 1);
            var daysDiff = barkday.diff(moment.utc(), 'days');
            console.log(dog.birthday);
            return (daysDiff > -10 && daysDiff < 20);
        }
        return false;
    }
    Utilities.NearBarkday = NearBarkday;
    function DaysUntilBarkday(dog) {
        if (dog && dog.birthday) {
            var barkday = moment.utc(dog.birthday).year(moment().year()).add('days', 1);
            return barkday.diff(moment.utc(), 'days');
        }
    }
    Utilities.DaysUntilBarkday = DaysUntilBarkday;
    function Default(value, defaultValue) {
        if (value == null)
            return defaultValue;
        return value;
    }
    Utilities.Default = Default;
    function CapitaliseFirstLetter(str) {
        return str.charAt(0).toUpperCase() + str.slice(1);
    }
    Utilities.CapitaliseFirstLetter = CapitaliseFirstLetter;
    function RemoveURLParameters(url) {
        return url.split("?")[0];
    }
    Utilities.RemoveURLParameters = RemoveURLParameters;
    function GetUrlParam(name, url) {
        if (!url) {
            url = window.location.href;
        }
        name = name.replace(/[\[\]]/g, "\\$&");
        var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"), results = regex.exec(url);
        if (!results)
            return null;
        if (!results[2])
            return '';
        return decodeURIComponent(results[2].replace(/\+/g, " "));
    }
    Utilities.GetUrlParam = GetUrlParam;
    function ApplyFormErrors(errors) {
        if (errors) {
            if (errors.errors) {
                for (var i = 0; i < errors.errors.length; i++) {
                    var error = errors.errors[i];
                    $(".validation-error[data-for='" + error.key + "']").text(error.error);
                }
            }
        }
    }
    Utilities.ApplyFormErrors = ApplyFormErrors;
    function ApplyFormError(key, error) {
        $(".validation-error[data-for='" + key + "']").text(error);
    }
    Utilities.ApplyFormError = ApplyFormError;
    function ClearFormErrors() {
        $(".validation-error").text("");
    }
    Utilities.ClearFormErrors = ClearFormErrors;
    function RenewalPeriod(bags, frequency, insertLineBreak) {
        if (insertLineBreak === void 0) { insertLineBreak = true; }
        var months = 0;
        if (frequency == "monthly") {
            months = bags;
        }
        else if (frequency = "bimonthly") {
            months = bags * 2;
        }
        else {
            return;
        }
        if (months == 12)
            return "for" + (insertLineBreak ? "<br />" : " ") + "1 year";
        if (months == 1)
            return (insertLineBreak ? "<br />" : "") + "each month";
        if (months == 2)
            return "every" + (insertLineBreak ? "<br />" : " ") + "second month";
        return "for" + (insertLineBreak ? "<br />" : " ") + months + " months";
    }
    Utilities.RenewalPeriod = RenewalPeriod;
    function Back(fallback) {
        fallback = fallback || '/dashboard';
        var prevPage = window.location.href;
        window.history.go(-1);
        setTimeout(function () {
            if (window.location.href == prevPage) {
                window.location.href = fallback;
            }
        }, 500);
    }
    Utilities.Back = Back;
})(Utilities || (Utilities = {}));
//# sourceMappingURL=utilities.js.map;
var BaseService;
(function (BaseService) {
    var Service = /** @class */ (function () {
        function Service(endpoint, version) {
            if (version === void 0) { version = "1"; }
            this.endpoint = endpoint;
            this.args = new Object();
            this.version = version;
        }
        Service.prototype.Delete = function (id, callback) {
            if (callback === void 0) { callback = undefined; }
            return HTTPServiceCalls.Delete(this.version, this.endpoint, id, callback);
        };
        Service.prototype.UpdateSingle = function (id, property, value, callback) {
            if (callback === void 0) { callback = undefined; }
            var properties = new Object();
            properties[property] = value;
            return this.Update(id, properties, callback);
        };
        Service.prototype.Update = function (id, properties, callback) {
            if (callback === void 0) { callback = undefined; }
            var patchOperations = new Array();
            for (var propertyName in properties) {
                patchOperations.push({
                    op: "replace",
                    path: propertyName,
                    value: properties[propertyName]
                });
            }
            return HTTPServiceCalls.Patch(this.version, this.endpoint, id, patchOperations, callback);
        };
        Service.prototype.Create = function (model, callback) {
            if (callback === void 0) { callback = undefined; }
            return HTTPServiceCalls.Post(this.version, this.endpoint, model, callback);
        };
        Service.prototype.GetDetail = function (id, callback) {
            if (callback === void 0) { callback = undefined; }
            return HTTPServiceCalls.GetDetail(this.version, this.endpoint, id, callback);
        };
        Service.prototype.Get = function (skip, take, callback) {
            if (callback === void 0) { callback = undefined; }
            return HTTPServiceCalls.Get(this.version, this.endpoint, skip, take, this.args, callback);
        };
        Service.prototype.GetAll = function (callback) {
            if (callback === void 0) { callback = undefined; }
            return HTTPServiceCalls.GetAll(this.version, this.endpoint, this.args, callback);
        };
        Service.prototype.Action = function (id, action, model, callback) {
            return HTTPServiceCalls.Post(this.version, this.endpoint + "/" + id + "/" + action, model, callback);
        };
        Service.prototype.With = function (arg, value) {
            this.args[arg] = value;
            return this;
        };
        Service.prototype.Sorted = function (sort, direction) {
            this.With("sort", sort);
            this.With("direction", direction);
            return this;
        };
        Service.prototype.WithTimeFrame = function (start, end) {
            this.With("start", start);
            this.With("end", end);
            return this;
        };
        return Service;
    }());
    BaseService.Service = Service;
})(BaseService || (BaseService = {}));
var HTTPServiceCalls;
(function (HTTPServiceCalls) {
    function Get(version, endpoint, skip, take, args, callback) {
        if (callback === void 0) { callback = undefined; }
        var dfd = $.Deferred();
        var query = "";
        for (var property in args) {
            if (args.hasOwnProperty(property)) {
                var val = args[property];
                if (val != null) {
                    if (val instanceof Date)
                        query = query + "&" + property + "=" + val.toISOString();
                    else
                        query = query + "&" + property + "=" + val;
                }
            }
        }
        $.ajax("/api/v" + version + "/" + endpoint + "?skip=" + skip + "&take=" + take + query, {
            type: "GET",
            headers: {
                'Content-Type': 'application/json'
            },
            success: function (response) {
                dfd.resolve();
                if (response) {
                    if (callback) {
                        callback(response);
                    }
                }
                else {
                    if (callback) {
                        callback(undefined);
                    }
                }
            },
            error: function (xhr) {
                dfd.reject();
                if (xhr.status == 401) {
                    window.location.href = "/account/signin";
                }
                else if (callback) {
                    callback(undefined, xhr.response);
                }
            },
            cache: false
        });
        return dfd.promise();
    }
    HTTPServiceCalls.Get = Get;
    function GetAll(version, endpoint, args, callback) {
        if (callback === void 0) { callback = undefined; }
        var dfd = $.Deferred();
        var query = "";
        for (var property in args) {
            if (args.hasOwnProperty(property)) {
                var val = args[property];
                if (val != null) {
                    if (val instanceof Date)
                        query = query + "&" + property + "=" + val.toISOString();
                    else
                        query = query + "&" + property + "=" + val;
                }
            }
        }
        Get(version, endpoint, 0, 0, args, function (result) {
            $.ajax("/api/v" + version + "/" + endpoint + "?skip=0&take=" + result.total + query, {
                type: "GET",
                headers: {
                    'Content-Type': 'application/json'
                },
                success: function (response) {
                    dfd.resolve();
                    if (response) {
                        if (callback) {
                            callback(response);
                        }
                    }
                    else {
                        if (callback) {
                            callback(undefined);
                        }
                    }
                },
                error: function (xhr) {
                    dfd.reject();
                    if (xhr.status == 401) {
                        window.location.href = "/account/signin";
                    }
                    else if (callback) {
                        callback(undefined, xhr.responseJSON);
                    }
                },
                cache: false
            });
        });
        return dfd.promise();
    }
    HTTPServiceCalls.GetAll = GetAll;
    function GetDetail(version, endpoint, id, callback) {
        if (callback === void 0) { callback = undefined; }
        var dfd = $.Deferred();
        $.ajax("/api/v" + version + "/" + endpoint + "/" + id + "?permisionHinting=true", {
            type: "GET",
            headers: {
                'Content-Type': 'application/json'
            },
            success: function (response) {
                dfd.resolve();
                if (response) {
                    if (callback) {
                        callback(response);
                    }
                }
                else {
                    if (callback) {
                        callback(undefined);
                    }
                }
            },
            error: function (xhr) {
                dfd.reject();
                if (xhr.status == 401) {
                    window.location.href = "/account/signin";
                }
                else if (callback) {
                    callback(undefined, xhr.responseJSON);
                }
            },
            cache: false
        });
        return dfd.promise();
    }
    HTTPServiceCalls.GetDetail = GetDetail;
    function Delete(version, endpoint, id, callback) {
        if (callback === void 0) { callback = undefined; }
        var dfd = $.Deferred();
        $.ajax("/api/v" + version + "/" + endpoint + "/" + id, {
            type: "DELETE",
            headers: {
                'Content-Type': 'application/json'
            },
            success: function (response) {
                dfd.resolve();
                if (callback) {
                    callback(true);
                }
            },
            error: function (xhr) {
                dfd.reject();
                if (xhr.status == 401) {
                    window.location.href = "/account/signin";
                }
                else if (callback) {
                    callback(false, xhr.responseJSON);
                }
            },
            cache: false
        });
        return dfd.promise();
    }
    HTTPServiceCalls.Delete = Delete;
    function Patch(version, endpoint, id, data, callback) {
        if (callback === void 0) { callback = undefined; }
        var dfd = $.Deferred();
        $.ajax("/api/v" + version + "/" + endpoint + "/" + id, {
            type: "PATCH",
            headers: {
                'Content-Type': 'application/json-patch+json'
            },
            data: JSON.stringify(data),
            success: function (response) {
                dfd.resolve();
                if (callback) {
                    callback(true);
                }
            },
            error: function (xhr) {
                dfd.reject();
                if (xhr.status == 401) {
                    window.location.href = "/account/signin";
                }
                else if (callback) {
                    callback(false, xhr.responseJSON);
                }
            },
            cache: false
        });
        return dfd.promise();
    }
    HTTPServiceCalls.Patch = Patch;
    function Post(version, endpoint, data, callback) {
        if (callback === void 0) { callback = undefined; }
        var dfd = $.Deferred();
        $.ajax("/api/v" + version + "/" + endpoint, {
            type: "POST",
            headers: {
                'Content-Type': 'application/json'
            },
            data: JSON.stringify(data),
            success: function (response) {
                dfd.resolve();
                if (callback) {
                    callback(response);
                }
            },
            error: function (xhr) {
                dfd.reject();
                if (xhr.status == 401) {
                    window.location.href = "/account/signin";
                }
                else if (callback) {
                    callback(undefined, xhr.responseJSON);
                }
            },
            cache: false
        });
        return dfd.promise();
    }
    HTTPServiceCalls.Post = Post;
})(HTTPServiceCalls || (HTTPServiceCalls = {}));
//# sourceMappingURL=base-service.js.map;
/******************************************
|| BASE MODELS
******************************************/
//# sourceMappingURL=models.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var AddressService;
(function (AddressService) {
    function New() {
        return new Service();
    }
    AddressService.New = New;
    var Service = /** @class */ (function (_super) {
        __extends(Service, _super);
        function Service() {
            return _super.call(this, "addresses", "1") || this;
        }
        Service.prototype.GetShippingRates = function (bagId, weight, callback) {
            this.With("weight", weight);
            return HTTPServiceCalls.Get("1", "addresses/" + bagId + "/shipping-estimates", 0, 3, this.args, callback);
        };
        return Service;
    }(BaseService.Service));
})(AddressService || (AddressService = {}));
//# sourceMappingURL=address-service.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var AttributeService;
(function (AttributeService) {
    function New() {
        return new Service();
    }
    AttributeService.New = New;
    var Service = /** @class */ (function (_super) {
        __extends(Service, _super);
        function Service() {
            return _super.call(this, "attributes", "1") || this;
        }
        return Service;
    }(BaseService.Service));
})(AttributeService || (AttributeService = {}));
//# sourceMappingURL=attribute-service.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var AttributeTypeService;
(function (AttributeTypeService) {
    function New() {
        return new Service();
    }
    AttributeTypeService.New = New;
    var Service = /** @class */ (function (_super) {
        __extends(Service, _super);
        function Service() {
            return _super.call(this, "attributetypes", "1") || this;
        }
        return Service;
    }(BaseService.Service));
})(AttributeTypeService || (AttributeTypeService = {}));
//# sourceMappingURL=attributetype-service.js.map;
var AuthenticationService;
(function (AuthenticationService) {
    function GetNewTokenWithAuthToken(authToken, callback) {
        if (callback === void 0) { callback = undefined; }
        $.ajax({
            url: '/Token',
            type: 'POST',
            data: {
                grant_type: 'auth_token',
                client_id: Constants.API_CLIENT_ID,
                token: authToken,
                issue_cookie: "true"
            },
            success: function (response) {
                if (response && response.access_token) {
                    if (callback) {
                        callback(true);
                    }
                }
                else {
                    if (callback) {
                        callback(false);
                    }
                }
            },
            error: function () {
                if (callback) {
                    callback(false);
                }
            }
        });
    }
    AuthenticationService.GetNewTokenWithAuthToken = GetNewTokenWithAuthToken;
    function GetNewTokenWithFBCode(code, state, callback) {
        if (callback === void 0) { callback = undefined; }
        $.ajax({
            url: '/Token',
            type: 'POST',
            data: {
                grant_type: 'fb_code_auth',
                client_id: Constants.API_CLIENT_ID,
                state: state,
                code: code,
                issue_cookie: "true"
            },
            success: function (response) {
                if (response && response.access_token) {
                    if (callback) {
                        callback(true);
                    }
                }
                else {
                    if (callback) {
                        callback(false);
                    }
                }
            },
            error: function (response) {
                if (callback) {
                    callback(false);
                }
            }
        });
    }
    AuthenticationService.GetNewTokenWithFBCode = GetNewTokenWithFBCode;
    function GetNewTokenWithFBToken(uuid, authToken, callback) {
        if (callback === void 0) { callback = undefined; }
        $.ajax({
            url: '/Token',
            type: 'POST',
            data: {
                grant_type: 'fb_auth',
                client_id: Constants.API_CLIENT_ID,
                username: uuid,
                token: authToken,
                issue_cookie: "true"
            },
            success: function (response) {
                if (response && response.access_token) {
                    if (callback) {
                        callback(true);
                    }
                }
                else {
                    if (callback) {
                        callback(false);
                    }
                }
            },
            error: function () {
                if (callback) {
                    callback(false);
                }
            }
        });
    }
    AuthenticationService.GetNewTokenWithFBToken = GetNewTokenWithFBToken;
    function GetNewTokenWithCredentials(email, password, callback) {
        if (callback === void 0) { callback = undefined; }
        $.ajax({
            url: '/Token',
            type: 'POST',
            data: {
                grant_type: 'password',
                client_id: Constants.API_CLIENT_ID,
                username: email,
                password: password,
                issue_cookie: "true"
            },
            success: function (response) {
                if (response && response.access_token) {
                    if (callback) {
                        callback(true);
                    }
                }
                else {
                    if (callback) {
                        callback(false);
                    }
                }
            },
            error: function () {
                if (callback) {
                    callback(false);
                }
            }
        });
    }
    AuthenticationService.GetNewTokenWithCredentials = GetNewTokenWithCredentials;
})(AuthenticationService || (AuthenticationService = {}));
//# sourceMappingURL=authentication-service.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var AuthorisationTokenService;
(function (AuthorisationTokenService) {
    function New() {
        return new Service();
    }
    AuthorisationTokenService.New = New;
    var Service = /** @class */ (function (_super) {
        __extends(Service, _super);
        function Service() {
            return _super.call(this, "authorisationTokens", "1") || this;
        }
        return Service;
    }(BaseService.Service));
})(AuthorisationTokenService || (AuthorisationTokenService = {}));
//# sourceMappingURL=authorisation-token-service.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var BagService;
(function (BagService) {
    function New() {
        return new Service();
    }
    BagService.New = New;
    var Service = /** @class */ (function (_super) {
        __extends(Service, _super);
        function Service() {
            return _super.call(this, "bags", "1") || this;
        }
        Service.prototype.GetShippingRates = function (bagId, weight, callback) {
            this.With("weight", weight);
            return HTTPServiceCalls.Get("1", "bags/" + bagId + "/shipping-estimates", 0, 3, this.args, callback);
        };
        return Service;
    }(BaseService.Service));
})(BagService || (BagService = {}));
//# sourceMappingURL=bag-service.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var BagItemService;
(function (BagItemService) {
    function New() {
        return new Service();
    }
    BagItemService.New = New;
    var Service = /** @class */ (function (_super) {
        __extends(Service, _super);
        function Service() {
            return _super.call(this, "bagitems", "1") || this;
        }
        return Service;
    }(BaseService.Service));
})(BagItemService || (BagItemService = {}));
//# sourceMappingURL=bagitem-service.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var BatchService;
(function (BatchService) {
    function New() {
        return new Service();
    }
    BatchService.New = New;
    var Service = /** @class */ (function (_super) {
        __extends(Service, _super);
        function Service() {
            return _super.call(this, "batches", "1") || this;
        }
        return Service;
    }(BaseService.Service));
})(BatchService || (BatchService = {}));
//# sourceMappingURL=batch-service.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var BrandService;
(function (BrandService) {
    function New() {
        return new Service();
    }
    BrandService.New = New;
    var Service = /** @class */ (function (_super) {
        __extends(Service, _super);
        function Service() {
            return _super.call(this, "brands", "1") || this;
        }
        return Service;
    }(BaseService.Service));
})(BrandService || (BrandService = {}));
//# sourceMappingURL=brand-service.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var BreedService;
(function (BreedService) {
    function New() {
        return new Service();
    }
    BreedService.New = New;
    var Service = /** @class */ (function (_super) {
        __extends(Service, _super);
        function Service() {
            return _super.call(this, "breeds", "1") || this;
        }
        return Service;
    }(BaseService.Service));
    function Merge(breedFrom, breedTo, callback) {
        HTTPServiceCalls.Post("1", "breeds/merge", {
            breedFromId: breedFrom,
            breedToId: breedTo
        }, callback);
    }
    BreedService.Merge = Merge;
})(BreedService || (BreedService = {}));
//# sourceMappingURL=breed-service.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var CartDogService;
(function (CartDogService) {
    function New() {
        return new Service();
    }
    CartDogService.New = New;
    var Service = /** @class */ (function (_super) {
        __extends(Service, _super);
        function Service() {
            return _super.call(this, "cartdogs", "1") || this;
        }
        return Service;
    }(BaseService.Service));
})(CartDogService || (CartDogService = {}));
//# sourceMappingURL=cart-dog-service.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var CartItemService;
(function (CartItemService) {
    function New() {
        return new Service();
    }
    CartItemService.New = New;
    var Service = /** @class */ (function (_super) {
        __extends(Service, _super);
        function Service() {
            return _super.call(this, "cartitems", "1") || this;
        }
        return Service;
    }(BaseService.Service));
})(CartItemService || (CartItemService = {}));
//# sourceMappingURL=cart-item-service.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var CartService;
(function (CartService) {
    function New() {
        return new Service();
    }
    CartService.New = New;
    var Service = /** @class */ (function (_super) {
        __extends(Service, _super);
        function Service() {
            return _super.call(this, "carts", "1") || this;
        }
        return Service;
    }(BaseService.Service));
    function CartId() {
        var cartId = $("#cart-id").val();
        if (cartId == null || cartId == undefined) {
            cartId = StorageService.Get("cart:id:current");
        }
        else {
            StorageService.Store("cart:id:current", cartId);
        }
        return cartId;
    }
    CartService.CartId = CartId;
})(CartService || (CartService = {}));
//# sourceMappingURL=cart-service.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var CollectionService;
(function (CollectionService) {
    function New() {
        return new Service();
    }
    CollectionService.New = New;
    var Service = /** @class */ (function (_super) {
        __extends(Service, _super);
        function Service() {
            return _super.call(this, "collections", "1") || this;
        }
        return Service;
    }(BaseService.Service));
})(CollectionService || (CollectionService = {}));
//# sourceMappingURL=collection-service.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var ContactService;
(function (ContactService) {
    function New() {
        return new Service();
    }
    ContactService.New = New;
    var Service = /** @class */ (function (_super) {
        __extends(Service, _super);
        function Service() {
            return _super.call(this, "contact", "1") || this;
        }
        return Service;
    }(BaseService.Service));
})(ContactService || (ContactService = {}));
//# sourceMappingURL=contact-service.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var CreditCardService;
(function (CreditCardService) {
    function New() {
        return new Service();
    }
    CreditCardService.New = New;
    var Service = /** @class */ (function (_super) {
        __extends(Service, _super);
        function Service() {
            return _super.call(this, "creditcards", "1") || this;
        }
        return Service;
    }(BaseService.Service));
})(CreditCardService || (CreditCardService = {}));
//# sourceMappingURL=creditcard-service.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var DogService;
(function (DogService) {
    function New() {
        return new Service();
    }
    DogService.New = New;
    var Service = /** @class */ (function (_super) {
        __extends(Service, _super);
        function Service() {
            return _super.call(this, "dogs", "1") || this;
        }
        return Service;
    }(BaseService.Service));
})(DogService || (DogService = {}));
//# sourceMappingURL=dog-service.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var FeedbackService;
(function (FeedbackService) {
    function New() {
        return new Service();
    }
    FeedbackService.New = New;
    var Service = /** @class */ (function (_super) {
        __extends(Service, _super);
        function Service() {
            return _super.call(this, "feedback", "1") || this;
        }
        return Service;
    }(BaseService.Service));
})(FeedbackService || (FeedbackService = {}));
//# sourceMappingURL=feedback-service.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var InvoiceService;
(function (InvoiceService) {
    function New() {
        return new Service();
    }
    InvoiceService.New = New;
    var Service = /** @class */ (function (_super) {
        __extends(Service, _super);
        function Service() {
            return _super.call(this, "invoices", "1") || this;
        }
        return Service;
    }(BaseService.Service));
})(InvoiceService || (InvoiceService = {}));
//# sourceMappingURL=invoice-service.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var InvoiceLineItemService;
(function (InvoiceLineItemService) {
    function New() {
        return new Service();
    }
    InvoiceLineItemService.New = New;
    var Service = /** @class */ (function (_super) {
        __extends(Service, _super);
        function Service() {
            return _super.call(this, "invoicelineitems", "1") || this;
        }
        return Service;
    }(BaseService.Service));
})(InvoiceLineItemService || (InvoiceLineItemService = {}));
//# sourceMappingURL=invoicelineitem-service.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var JobService;
(function (JobService) {
    function New() {
        return new Service();
    }
    JobService.New = New;
    var Service = /** @class */ (function (_super) {
        __extends(Service, _super);
        function Service() {
            return _super.call(this, "jobs", "1") || this;
        }
        return Service;
    }(BaseService.Service));
})(JobService || (JobService = {}));
//# sourceMappingURL=job-service.js.map;
var LoaderService;
(function (LoaderService) {
    function Start() {
        $(".loader-container").removeClass("hidden");
        $(".loader-container").addClass("fadeIn");
    }
    LoaderService.Start = Start;
    function Stop() {
        $(".loader-container").addClass("hidden");
        $(".loader-container").removeClass("fadeIn");
    }
    LoaderService.Stop = Stop;
    function StartOverlay(text) {
        $.LoadingOverlay("show", {
            custom: $('<div class="loader-container arc-rotate2 animated"><div class="loader black"><div class="arc"></div></div></div><p style="position: relative; top: 40px;">' + text + '</p>'),
        });
    }
    LoaderService.StartOverlay = StartOverlay;
    function StopOverlay() {
        $.LoadingOverlay("hide");
    }
    LoaderService.StopOverlay = StopOverlay;
})(LoaderService || (LoaderService = {}));
//# sourceMappingURL=loader-service.js.map;
var LoggingService;
(function (LoggingService) {
    function Log(message) {
        //if (Constants.IS_DEBUG) {
        console.log(message);
        //}
    }
    LoggingService.Log = Log;
})(LoggingService || (LoggingService = {}));
//# sourceMappingURL=logging-service.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var NewsletterService;
(function (NewsletterService) {
    function New() {
        return new Service();
    }
    NewsletterService.New = New;
    var Service = /** @class */ (function (_super) {
        __extends(Service, _super);
        function Service() {
            return _super.call(this, "signups/newsletter", "1") || this;
        }
        return Service;
    }(BaseService.Service));
})(NewsletterService || (NewsletterService = {}));
//# sourceMappingURL=newsletter-service.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var NoteService;
(function (NoteService) {
    function New() {
        return new Service();
    }
    NoteService.New = New;
    var Service = /** @class */ (function (_super) {
        __extends(Service, _super);
        function Service() {
            return _super.call(this, "notes", "1") || this;
        }
        return Service;
    }(BaseService.Service));
})(NoteService || (NoteService = {}));
//# sourceMappingURL=note-service.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var OrderLineService;
(function (OrderLineService) {
    function New() {
        return new Service();
    }
    OrderLineService.New = New;
    var Service = /** @class */ (function (_super) {
        __extends(Service, _super);
        function Service() {
            return _super.call(this, "orderlineitems", "1") || this;
        }
        return Service;
    }(BaseService.Service));
})(OrderLineService || (OrderLineService = {}));
//# sourceMappingURL=order-line-service.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var OrderService;
(function (OrderService) {
    function New() {
        return new Service();
    }
    OrderService.New = New;
    var Service = /** @class */ (function (_super) {
        __extends(Service, _super);
        function Service() {
            return _super.call(this, "orders", "1") || this;
        }
        return Service;
    }(BaseService.Service));
})(OrderService || (OrderService = {}));
//# sourceMappingURL=order-service.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var PasswordResetTokenService;
(function (PasswordResetTokenService) {
    function New() {
        return new Service();
    }
    PasswordResetTokenService.New = New;
    var Service = /** @class */ (function (_super) {
        __extends(Service, _super);
        function Service() {
            return _super.call(this, "passwordResetTokens", "1") || this;
        }
        return Service;
    }(BaseService.Service));
})(PasswordResetTokenService || (PasswordResetTokenService = {}));
//# sourceMappingURL=passwordResetToken-service.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var PasswordUpdateService;
(function (PasswordUpdateService) {
    function New() {
        return new Service();
    }
    PasswordUpdateService.New = New;
    var Service = /** @class */ (function (_super) {
        __extends(Service, _super);
        function Service() {
            return _super.call(this, "passwordUpdate", "1") || this;
        }
        return Service;
    }(BaseService.Service));
})(PasswordUpdateService || (PasswordUpdateService = {}));
//# sourceMappingURL=passwordUpdate-service.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var PlanService;
(function (PlanService) {
    function New() {
        return new Service();
    }
    PlanService.New = New;
    var Service = /** @class */ (function (_super) {
        __extends(Service, _super);
        function Service() {
            return _super.call(this, "plans", "1") || this;
        }
        return Service;
    }(BaseService.Service));
})(PlanService || (PlanService = {}));
//# sourceMappingURL=plan-service.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var PlanDogService;
(function (PlanDogService) {
    function New() {
        return new Service();
    }
    PlanDogService.New = New;
    var Service = /** @class */ (function (_super) {
        __extends(Service, _super);
        function Service() {
            return _super.call(this, "plandogs", "1") || this;
        }
        return Service;
    }(BaseService.Service));
})(PlanDogService || (PlanDogService = {}));
//# sourceMappingURL=plandog-service.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var PlanShipmentService;
(function (PlanShipmentService) {
    function New() {
        return new Service();
    }
    PlanShipmentService.New = New;
    var Service = /** @class */ (function (_super) {
        __extends(Service, _super);
        function Service() {
            return _super.call(this, "planshipments", "1") || this;
        }
        return Service;
    }(BaseService.Service));
})(PlanShipmentService || (PlanShipmentService = {}));
//# sourceMappingURL=planshipment-service.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var ProductService;
(function (ProductService) {
    function New() {
        return new Service();
    }
    ProductService.New = New;
    var Service = /** @class */ (function (_super) {
        __extends(Service, _super);
        function Service() {
            return _super.call(this, "products", "1") || this;
        }
        return Service;
    }(BaseService.Service));
})(ProductService || (ProductService = {}));
//# sourceMappingURL=product-service.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var ProductVariantService;
(function (ProductVariantService) {
    function New() {
        return new Service();
    }
    ProductVariantService.New = New;
    var Service = /** @class */ (function (_super) {
        __extends(Service, _super);
        function Service() {
            return _super.call(this, "productVariants", "1") || this;
        }
        return Service;
    }(BaseService.Service));
})(ProductVariantService || (ProductVariantService = {}));
//# sourceMappingURL=productVariant-service.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var PromoCodeService;
(function (PromoCodeService) {
    function New() {
        return new Service();
    }
    PromoCodeService.New = New;
    var Service = /** @class */ (function (_super) {
        __extends(Service, _super);
        function Service() {
            return _super.call(this, "promocodes", "1") || this;
        }
        return Service;
    }(BaseService.Service));
})(PromoCodeService || (PromoCodeService = {}));
//# sourceMappingURL=promocode-service.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var PromoCodeDefinitionService;
(function (PromoCodeDefinitionService) {
    function New() {
        return new Service();
    }
    PromoCodeDefinitionService.New = New;
    var Service = /** @class */ (function (_super) {
        __extends(Service, _super);
        function Service() {
            return _super.call(this, "promocodedefinitions", "1") || this;
        }
        return Service;
    }(BaseService.Service));
})(PromoCodeDefinitionService || (PromoCodeDefinitionService = {}));
//# sourceMappingURL=promocodedefinition-service.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var ShipmentService;
(function (ShipmentService) {
    function New() {
        return new Service();
    }
    ShipmentService.New = New;
    var Service = /** @class */ (function (_super) {
        __extends(Service, _super);
        function Service() {
            return _super.call(this, "shipments", "1") || this;
        }
        return Service;
    }(BaseService.Service));
})(ShipmentService || (ShipmentService = {}));
//# sourceMappingURL=shipment-service.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var StatisticService;
(function (StatisticService) {
    function New() {
        return new Service();
    }
    StatisticService.New = New;
    var Service = /** @class */ (function (_super) {
        __extends(Service, _super);
        function Service() {
            return _super.call(this, "statistics", "1") || this;
        }
        return Service;
    }(BaseService.Service));
})(StatisticService || (StatisticService = {}));
//# sourceMappingURL=statistics-service.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var StockService;
(function (StockService) {
    function New() {
        return new Service();
    }
    StockService.New = New;
    var Service = /** @class */ (function (_super) {
        __extends(Service, _super);
        function Service() {
            return _super.call(this, "stock", "1") || this;
        }
        return Service;
    }(BaseService.Service));
})(StockService || (StockService = {}));
//# sourceMappingURL=stock-service.js.map;
var StorageService;
(function (StorageService) {
    function Get(key) {
        try {
            return localStorage.getItem(key);
        }
        catch (e) {
            return null;
        }
    }
    StorageService.Get = Get;
    function Store(key, value) {
        try {
            localStorage.setItem(key, value);
        }
        catch (e) { }
    }
    StorageService.Store = Store;
    function Clear(key) {
        try {
            localStorage.removeItem(key);
        }
        catch (e) { }
    }
    StorageService.Clear = Clear;
})(StorageService || (StorageService = {}));
//# sourceMappingURL=storage-service.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var SupplierService;
(function (SupplierService) {
    function New() {
        return new Service();
    }
    SupplierService.New = New;
    var Service = /** @class */ (function (_super) {
        __extends(Service, _super);
        function Service() {
            return _super.call(this, "suppliers", "1") || this;
        }
        return Service;
    }(BaseService.Service));
})(SupplierService || (SupplierService = {}));
//# sourceMappingURL=supplier-service.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var SupplierProductService;
(function (SupplierProductService) {
    function New() {
        return new Service();
    }
    SupplierProductService.New = New;
    var Service = /** @class */ (function (_super) {
        __extends(Service, _super);
        function Service() {
            return _super.call(this, "supplierproducts", "1") || this;
        }
        return Service;
    }(BaseService.Service));
})(SupplierProductService || (SupplierProductService = {}));
//# sourceMappingURL=supplierproduct-service.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var TransactionService;
(function (TransactionService) {
    function New() {
        return new Service();
    }
    TransactionService.New = New;
    var Service = /** @class */ (function (_super) {
        __extends(Service, _super);
        function Service() {
            return _super.call(this, "transactions", "1") || this;
        }
        return Service;
    }(BaseService.Service));
})(TransactionService || (TransactionService = {}));
//# sourceMappingURL=transaction-service.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var UserService;
(function (UserService) {
    function New() {
        return new Service();
    }
    UserService.New = New;
    var Service = /** @class */ (function (_super) {
        __extends(Service, _super);
        function Service() {
            return _super.call(this, "users", "1") || this;
        }
        return Service;
    }(BaseService.Service));
})(UserService || (UserService = {}));
//# sourceMappingURL=user-service.js.map;
var Admin;
(function (Admin) {
    var AttributeDetails = /** @class */ (function () {
        function AttributeDetails() {
            this.name = ko.observable();
            this.friendlyId = ko.observable();
            this.isDefault = ko.observable(true);
            this.isLoading = ko.observable(false);
            this.isAddAttributeMode = ko.observable(false);
            this.refresh = ko.observable(false);
            this.attributes = ko.observableArray();
        }
        AttributeDetails.prototype.createModel = function () {
            var self = this;
            self.isLoading(true);
            AttributeTypeService.New().GetDetail($("#id").val(), function (result, error) {
                self.isLoading(false);
                if (result) {
                    self.name(result.name);
                    self.friendlyId(result.friendlyId);
                    self.isDefault(result.isDefault);
                }
                else {
                    $('[data-error="General"]').text("Woops something went wrong");
                    $('[data-error="General"]').show();
                }
                setTimeout(function () {
                    $("#editable-attr-name").editable({
                        pk: 1,
                        mode: "inline",
                        type: 'text',
                        success: function (response, newValue) {
                            AttributeTypeService.New().UpdateSingle($("#id").val(), "name", newValue);
                        }
                    }).on('shown', function (e, editable) {
                        editable.input.$input.val($(e.currentTarget).text().trim());
                    });
                    $("#editable-attr-friendlyId").editable({
                        pk: 1,
                        mode: "inline",
                        type: 'text',
                        success: function (response, newValue) {
                            AttributeTypeService.New().UpdateSingle($("#id").val(), "friendlyId", newValue);
                        }
                    }).on('shown', function (e, editable) {
                        editable.input.$input.val($(e.currentTarget).text().trim());
                    });
                }, 10);
            });
            $('#nameToAdd').on('keydown', function (e) {
                if (e.which == 13) {
                    e.preventDefault();
                    self.addAttribute();
                }
            });
            self.addAttribute = function () {
                if ($("#nameToAdd").val()) {
                    AttributeService.New().Create({
                        attributeTypeId: $("#id").val(),
                        name: $("#nameToAdd").val()
                    }, function () {
                        self.refresh.valueHasMutated();
                        $("#nameToAdd").val("").trigger('change');
                        alertify.success("Attribute option added");
                    });
                }
            };
            self.deleteAttribute = function (item) {
                AttributeService.New()
                    .Delete(item.id, function () {
                    self.refresh.valueHasMutated();
                    alertify.success("Attribute option removed");
                });
                return false;
            };
            ko.computed(function () {
                var refresh = self.refresh();
                AttributeService.New()
                    .With("attributeTypeId", $("#id").val())
                    .GetAll(function (result, error) {
                    if (result) {
                        self.attributes.removeAll();
                        (_a = self.attributes).push.apply(_a, result.data);
                        setTimeout(function () {
                            $(".editable-name").editable({
                                pk: 1,
                                mode: "inline",
                                type: 'text',
                                success: function (response, newValue) {
                                    AttributeService.New().UpdateSingle($(this).attr("id"), "name", newValue);
                                }
                            }).on('shown', function (e, editable) {
                                editable.input.$input.val($(e.currentTarget).text().trim());
                            });
                        }, 10);
                    }
                    var _a;
                });
            });
            $("#delete-button").click(function () {
                self.isLoading(true);
                AttributeTypeService.New().Delete($("#id").val(), function (result) {
                    self.isLoading(false);
                    if (result) {
                        window.location.pathname = "/admin/attributes";
                    }
                    else {
                        $('[data-error="General"]').text("Woops something went wrong");
                        $('[data-error="General"]').show();
                    }
                });
                return false;
            });
            return self;
        };
        return AttributeDetails;
    }());
    Admin.AttributeDetails = AttributeDetails;
})(Admin || (Admin = {}));
//# sourceMappingURL=Admin.AttributeDetails.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var Admin;
(function (Admin) {
    var AttributeIndex = /** @class */ (function (_super) {
        __extends(AttributeIndex, _super);
        function AttributeIndex() {
            var _this = _super !== null && _super.apply(this, arguments) || this;
            _this.isDefaultFilter = ko.observable(StorageService.Get(_this.key("isDefault")));
            _this.isAddMode = ko.observable(false);
            return _this;
        }
        AttributeIndex.prototype.key = function (key) {
            return "attribute-v2-" + key;
        };
        AttributeIndex.prototype.createModel = function () {
            var self = this;
            var canRun = true;
            $('#nameToAdd').on('keydown', function (e) {
                if (e.which == 13) {
                    e.preventDefault();
                    self.addAttribute();
                }
            });
            self.addAttribute = function () {
                if ($("#nameToAdd").val()) {
                    AttributeTypeService.New().Create({
                        name: $("#nameToAdd").val()
                    }, function (result, error) {
                        if (result) {
                            self.isAddMode(false);
                            alertify.success("Attribute added");
                            self.page.valueHasMutated();
                            $("#nameToAdd").val("");
                        }
                        else {
                            alertify.error("Cannot add attribute");
                        }
                    });
                }
                else {
                    alertify.error("Please enter in a value");
                }
                return false;
            };
            if (!self.sort()) {
                self.sort("Name");
                self.sortDirection(Constants.SORT_ASC);
            }
            ko.computed(function () {
                var page = self.page();
                var pageSize = self.pageSize();
                var search = self.search();
                var dir = self.sortDirection();
                var sort = self.sort();
                var isDefaultFilter = self.isDefaultFilter();
                if (canRun) {
                    canRun = false;
                    if (self.state() == Constants.STATE_READY)
                        self.state(Constants.STATE_BUSY);
                    var service = AttributeTypeService.New()
                        .With("status", "active")
                        .With("direction", dir)
                        .With("sort", sort)
                        .With("isDefault", isDefaultFilter)
                        .With("q", search)
                        .Get((page - 1) * pageSize, pageSize, function (result) {
                        self.state(Constants.STATE_READY);
                        self.total(result.total);
                        self.data.removeAll();
                        for (var i = 0; i < result.data.length; i++) {
                            self.data.push(result.data[i]);
                        }
                        canRun = true;
                        setTimeout(function () {
                            $(".editable-name").editable({
                                pk: 1,
                                mode: "inline",
                                type: 'text',
                                success: function (response, newValue) {
                                    AttributeTypeService.New().UpdateSingle($(this).attr("id"), "name", newValue);
                                }
                            }).on('shown', function (e, editable) {
                                editable.input.$input.val($(e.currentTarget).text().trim());
                            });
                        }, 10);
                    });
                }
            });
            ko.computed(function () {
                var defaultFilter = self.isDefaultFilter();
                if (defaultFilter) {
                    StorageService.Store(self.key("isDefault"), defaultFilter);
                }
                else {
                    StorageService.Clear(self.key("isDefault"));
                }
            });
            return self;
        };
        return AttributeIndex;
    }(BindableIndexModel));
    Admin.AttributeIndex = AttributeIndex;
})(Admin || (Admin = {}));
//# sourceMappingURL=Admin.AttributeIndex.js.map;
var Admin;
(function (Admin) {
    var BagAdd = /** @class */ (function () {
        function BagAdd() {
            this.isLoading = ko.observable(false);
            this.userId = ko.observable();
            this.notes = ko.observable();
            this.isGift = ko.observable();
            this.isBilled = ko.observable();
            this.price = ko.observable();
            this.quantity = ko.observable(1);
            this.shipment = ko.observable(moment.utc().local().add(2, 'day').format("DD/MM/YY"));
        }
        BagAdd.prototype.createModel = function () {
            var self = this;
            $("#userToAdd").change(function () {
                self.userId($("#userToAdd").val());
                $("#addressToAdd").val("").trigger('change');
                $("#dogsToAdd").val("").trigger('change');
            });
            $("#add-address").click(function () {
                alertify
                    .confirm("Add an address to selected user", function () {
                    if (self.userId() && $("#street").val() && $("#suburb").val() && $("#city").val()) {
                        AddressService.New()
                            .Create({
                            userId: self.userId(),
                            street: $("#street").val(),
                            suburb: $("#suburb").val(),
                            city: $("#city").val(),
                            isRuralDelivery: $("#isRural").is(':checked')
                        }, function (result) {
                            if (result) {
                                var s2 = $("#addressToAdd").data('select2');
                                s2.trigger('select', {
                                    data: {
                                        id: result.id,
                                        text: result.street + ", " + result.suburb + ", " + result.city
                                    }
                                });
                                alertify.success("Address added");
                            }
                            else {
                                alertify.error("Unable to add address");
                            }
                        });
                    }
                });
                var htmlText = '<div class="row" style="text-align: left;">';
                htmlText += '<div class="col-md-6"><div class="form-group"> <label for="street">Street*</label><input class="form-control" id="street" value="" placeholder="12 Bark Street" /></div></div>';
                htmlText += '<div class="col-md-6"><div class="form-group"><label for="suburb">Suburb</label><input class="form-control" id="suburb" value="" placeholder="Treatville" /></div></div>';
                htmlText += '</div>';
                htmlText += '<div class="row" style="text-align: left;">';
                htmlText += '<div class="col-md-6"><div class="form-group"><label for="city">City (NZ only)*</label><input class="form-control" id="city" value="" placeholder="Puppy Town" /></div></div>';
                htmlText += '<div class="col-md-6"><div class="form-group"><input name="isRural" type="checkbox" class="styled" value="true" id="isRural"><label class="os" for="isRural">Is rural address <i>($5 extra to ship rurally)</i></label></div></div>';
                htmlText += '</div>';
                $(htmlText).insertAfter(".alertify .msg");
                return false;
            });
            $("#productToAdd").select2({
                ajax: {
                    url: "/api/v1/productvariants",
                    dataType: 'json',
                    delay: 250,
                    data: function (query) {
                        var search = "";
                        if (query.term)
                            search = "q=" + query.term;
                        if (query.page) {
                            if (search.length > 0)
                                search = search + "&";
                            search = search + "skip=" + (query.page - 1) * 5 + "&take=5";
                        }
                        if (search.length > 0)
                            search = search + "&";
                        search = search + "isSubscription=False&isBarkBag=True&type=bark-bag";
                        return search;
                    },
                    processResults: function (data, params) {
                        var results = [{
                                id: "",
                                text: "Search for a bag type to create"
                            }];
                        if (data && data.data) {
                            for (var i = 0; i < data.data.length; i++) {
                                results.push({
                                    id: data.data[i].id,
                                    text: data.data[i].title
                                });
                            }
                        }
                        return {
                            results: results
                        };
                    },
                    cache: true
                },
                minimumInputLength: 0
            });
            $("#userToAdd").select2({
                ajax: {
                    url: "/api/v1/users",
                    dataType: 'json',
                    delay: 250,
                    data: function (query) {
                        var search = "";
                        if (query.term)
                            search = "q=" + query.term;
                        if (query.page) {
                            if (search.length > 0)
                                search = search + "&";
                            search = search + "skip=" + (query.page - 1) * 5 + "&take=5";
                        }
                        return search;
                    },
                    processResults: function (data, params) {
                        var results = [{
                                id: "",
                                text: "Search for a user to assign this bag to"
                            }];
                        if (data && data.data) {
                            for (var i = 0; i < data.data.length; i++) {
                                results.push({
                                    id: data.data[i].id,
                                    text: data.data[i].name ? data.data[i].name + " (" + data.data[i].email + ")" : data.data[i].email
                                });
                            }
                        }
                        return {
                            results: results
                        };
                    },
                    cache: true
                },
                minimumInputLength: 0
            });
            $("#addressToAdd").select2({
                ajax: {
                    url: "/api/v1/addresses",
                    dataType: 'json',
                    delay: 250,
                    data: function (query) {
                        var search = "";
                        if (query.term)
                            search = "q=" + query.term;
                        if (query.page) {
                            if (search.length > 0)
                                search = search + "&";
                            search = search + "skip=" + (query.page - 1) * 5 + "&take=5";
                        }
                        if (search.length > 0)
                            search = search + "&";
                        search = search + "userId=" + self.userId();
                        return search;
                    },
                    processResults: function (data, params) {
                        var results = [{
                                id: "",
                                text: "Search for a user to assign this bag to"
                            }];
                        if (data && data.data) {
                            for (var i = 0; i < data.data.length; i++) {
                                results.push({
                                    id: data.data[i].id,
                                    text: data.data[i].street + ", " + data.data[i].suburb + ", " + data.data[i].city
                                });
                            }
                        }
                        return {
                            results: results
                        };
                    },
                    cache: true
                },
                minimumInputLength: 0
            });
            $("#dogsToAdd").select2({
                ajax: {
                    url: "/api/v1/dogs",
                    dataType: 'json',
                    delay: 250,
                    data: function (query) {
                        var search = "";
                        if (query.term)
                            search = "q=" + query.term;
                        if (query.page) {
                            if (search.length > 0)
                                search = search + "&";
                            search = search + "skip=" + (query.page - 1) * 5 + "&take=5";
                        }
                        if (search.length > 0)
                            search = search + "&";
                        search = search + "userId=" + self.userId();
                        return search;
                    },
                    processResults: function (data, params) {
                        var results = [{
                                id: "",
                                text: "Search for a dog to add"
                            }];
                        if (data && data.data) {
                            for (var i = 0; i < data.data.length; i++) {
                                results.push({
                                    id: data.data[i].id,
                                    text: data.data[i].name
                                });
                            }
                        }
                        return {
                            results: results
                        };
                    },
                    cache: true
                },
                minimumInputLength: 0
            });
            $("#save-button").click(function () {
                $('#save-button').attr("disabled", "disabled");
                self.isLoading(true);
                $("[data-error]").hide();
                console.log($("#dogsToAdd").val());
                BagService.New().Create({
                    userId: self.userId(),
                    dogIds: $("#dogsToAdd").val(),
                    productVariantId: $("#productToAdd").val(),
                    addressId: $("#addressToAdd").val(),
                    isGift: self.isGift(),
                    price: self.price(),
                    expectedShipmentDate: moment(self.shipment(), "DD/MM/YYYY").toISOString(),
                    quantity: self.quantity(),
                    billed: self.isBilled()
                }, function (result, error) {
                    $('#save-button').removeAttr("disabled");
                    self.isLoading(false);
                    if (result) {
                        for (var i = 0; i < result.length; i++) {
                            NoteService.New().Create({
                                userId: self.userId(),
                                bagId: result[i],
                                message: self.notes()
                            }, function (result) {
                                window.location.pathname = "/admin/bags";
                            });
                        }
                    }
                    else if (error && error.errors) {
                        for (var i = 0, len = error.errors.length; i < len; i++) {
                            $('[data-error="' + error.errors[i].key + '"]').text(error.errors[i].error);
                            $('[data-error="' + error.errors[i].key + '"]').show();
                        }
                    }
                    else {
                        $('[data-error="General"]').text("Woops something went wrong");
                        $('[data-error="General"]').show();
                    }
                });
                //ProductVariantService.New().Create({
                //    productId: <string>$("#productToAdd").val(),
                //    title: self.name(),
                //    barcode: self.barcode(),
                //    grams: self.grams(),
                //    inventoryPolicy: self.inventoryPolicy(),
                //    position: 0,
                //    price: self.price(),
                //    description: self.description(),
                //    shippingUnits: self.shippingUnits(),
                //    shipsOnSpecificDay: self.shipsOnSpecificDay(),
                //    isSubscription: self.isSubscription(),
                //    isAvailable: true,
                //    requiresDogInfo: self.requiredDogInfo(),
                //    attributes: $("#attributesToAdd").val()
                //}, function (result: ProductVariantModel, error) {
                //});
                return false;
            });
            return self;
        };
        return BagAdd;
    }());
    Admin.BagAdd = BagAdd;
})(Admin || (Admin = {}));
//# sourceMappingURL=Admin.BagAdd.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var Admin;
(function (Admin) {
    var BagBagItemIndex = /** @class */ (function (_super) {
        __extends(BagBagItemIndex, _super);
        function BagBagItemIndex() {
            var _this = _super !== null && _super.apply(this, arguments) || this;
            _this.notPickedUp = ko.observable();
            return _this;
        }
        BagBagItemIndex.prototype.key = function (key) {
            return "bagbagitem-v2-" + key;
        };
        BagBagItemIndex.prototype.createModel = function () {
            var self = this;
            var canRun = true;
            self.bagRRPTotal = ko.computed(function () {
                var data = self.data();
                var runingTotal = 0;
                if (data) {
                    for (var i = 0; i < data.length; i++)
                        runingTotal = runingTotal + (data[i].productVariant.price * data[i].quantity);
                }
                return runingTotal;
            });
            self.bagCostTotal = ko.computed(function () {
                var data = self.data();
                var runingTotal = 0;
                if (data) {
                    for (var i = 0; i < data.length; i++) {
                        if (data[i].stock) {
                            runingTotal = runingTotal + (data[i].stock.unitCost * data[i].quantity);
                        }
                    }
                }
                return runingTotal;
            });
            self.removeProduct = function (id) {
                BagItemService.New()
                    .Delete(id, function () {
                    self.sort.valueHasMutated();
                });
                return false;
            };
            self.editTitle = function (id, text) {
                alertify.confirm("What do you want to update the title to?", function () {
                    BagItemService.New().UpdateSingle(id, "name", $("#itemTitle").val(), function () {
                        self.sort.valueHasMutated();
                    });
                });
                $('<input type="text" id="itemTitle" value="' + text + '" class="form-control" />').insertAfter(".alertify .msg");
                return false;
            };
            self.checkStock = function (bagItem, e) {
                var l = Ladda.create($(event.currentTarget)[0]);
                l.start();
                StockService.New()
                    .With("productVariantId", bagItem.productVariant.id)
                    .With("hasAvailable", true)
                    .With("expired", false)
                    .Get(0, 1, function (result) {
                    if (result && result.total == 1) {
                        BagItemService.New()
                            .UpdateSingle(bagItem.id, "stockId", result.data[0].id, function (result2) {
                            if (result2) {
                                self.sort.valueHasMutated();
                                alertify.success("Bag item updated");
                            }
                            else {
                                alertify.error("No stock available");
                            }
                        });
                    }
                    else {
                        alertify.error("No stock available");
                    }
                    l.stop();
                });
                console.log(bagItem);
                console.log(e);
                return false;
            };
            if (!self.sort()) {
                self.sort("Name");
                self.sortDirection(Constants.SORT_ASC);
            }
            $("#add-product").click(function () {
                var productId = $("#productToAdd").val();
                if (productId && productId.length > 0) {
                    BagItemService.New()
                        .Create({
                        bagId: $("#id").val(),
                        productVariantId: productId,
                        quantity: 1,
                        reason: "human"
                    }, function () {
                        alertify.success("Product added to bag");
                        $("#productToAdd").val(null).trigger("change");
                        self.sort.valueHasMutated();
                    });
                }
                else {
                    alertify.error("Please select a product to add");
                }
                return false;
            });
            $("#productToAdd").select2({
                ajax: {
                    url: "/api/v1/productvariants",
                    dataType: 'json',
                    delay: 250,
                    data: function (query) {
                        var search = "";
                        if (query.term)
                            search = "q=" + query.term;
                        if (query.page) {
                            if (search.length > 0)
                                search = search + "&";
                            search = search + "skip=" + (query.page - 1) * 5 + "&take=5";
                        }
                        return search;
                    },
                    processResults: function (data, params) {
                        var results = [{
                                id: "",
                                text: "Search for product to add"
                            }];
                        if (data && data.data) {
                            for (var i = 0; i < data.data.length; i++) {
                                results.push({
                                    id: data.data[i].id,
                                    text: data.data[i].title
                                });
                            }
                        }
                        return {
                            results: results
                        };
                    },
                    cache: true
                },
                minimumInputLength: 0
            }).on('select2:open', function () {
                $('.select2-dropdown--below').attr('id', 'fix');
                $('#fix').removeClass('select2-dropdown--below');
                $('#fix').addClass('select2-dropdown--above');
            });
            ;
            ko.computed(function () {
                var dir = self.sortDirection();
                var sort = self.sort();
                if (canRun) {
                    canRun = false;
                    if (self.state() == Constants.STATE_READY)
                        self.state(Constants.STATE_BUSY);
                    var service = BagService.New()
                        .GetDetail($("#id").val(), function (result) {
                        self.state(Constants.STATE_READY);
                        self.total(result.bagItems.length);
                        self.data.removeAll();
                        for (var i = 0; i < result.bagItems.length; i++) {
                            self.data.push(result.bagItems[i]);
                        }
                        if (result.shipment == null || result.shipment.pickedUp == null)
                            self.notPickedUp(true);
                        else
                            self.notPickedUp(false);
                        canRun = true;
                    });
                }
            });
            return self;
        };
        return BagBagItemIndex;
    }(BindableIndexModel));
    Admin.BagBagItemIndex = BagBagItemIndex;
})(Admin || (Admin = {}));
//# sourceMappingURL=Admin.BagBagItemIndex.js.map;
var Admin;
(function (Admin) {
    var BagDetails = /** @class */ (function () {
        function BagDetails() {
            this.bag = ko.observable();
            this.address = ko.observable();
            this.plan = ko.observable();
            this.invoice = ko.observable();
            this.dogs = ko.observableArray();
            this.notes = ko.observableArray();
            this.userNotes = ko.observableArray();
            this.order = ko.observable();
            this.cartItem = ko.observable();
            this.numberOfBags = ko.observable();
            this.numberOfBagsShipped = ko.observable();
            this.refresh = ko.observable();
            this.lastTransaction = ko.observable();
            this.isLoading = ko.observable(false);
        }
        BagDetails.prototype.createModel = function () {
            var self = this;
            self.confirmBag = function (d, e) {
                var l = Ladda.create($(e.currentTarget)[0]);
                l.start();
                BagService.New()
                    .UpdateSingle($("#id").val(), "confirmed", "True", function (updateBagResult) {
                    self.refresh.valueHasMutated();
                    l.stop();
                });
                return false;
            };
            self.upsertShipment = function (d, e) {
                var l = Ladda.create($(e.currentTarget)[0]);
                l.start();
                var existingShipmentId = $(e.currentTarget)[0].id;
                var provider = $(e.currentTarget).data("provider");
                var pickupLocation = $(e.currentTarget).data("pickup");
                if (existingShipmentId) {
                    self.updateShipment(existingShipmentId, provider, pickupLocation, $("#weight").val(), l);
                }
                else {
                    ShipmentService.New()
                        .Create({
                        pickupLocation: pickupLocation,
                        provider: "tbc",
                        addressId: self.bag().addressId,
                        weight: $("#weight").val()
                    }, function (createShipmentResult) {
                        if (createShipmentResult) {
                            BagService.New()
                                .UpdateSingle(self.bag().id, "shipmentId", createShipmentResult.id, function (updateBagResult) {
                                if (updateBagResult) {
                                    self.refresh.valueHasMutated();
                                    self.updateShipment(existingShipmentId, provider, pickupLocation, $("#weight").val(), l);
                                }
                                else {
                                    alertify.error("Error creating shipment");
                                    l.stop();
                                }
                            });
                        }
                        else {
                            alertify.error("Error creating shipment");
                            l.stop();
                        }
                    });
                }
                return false;
            };
            self.updateShipment = function (existingShipmentId, provider, pickupLocation, weight, l) {
                if (provider == "automatic") {
                    BagService.New()
                        .GetShippingRates(self.bag().id, weight, function (result) {
                        alertify
                            .confirm("Which courier?", function () {
                            var quote = $("input[name='shipping']:checked").val();
                            var shimpmentProvider = $("input[name='shipping']:checked").parent().data("provider");
                            console.log("quote: " + quote + " provider:" + shimpmentProvider);
                            ShipmentService.New()
                                .Update(existingShipmentId, {
                                provider: shimpmentProvider,
                                deliveryReference: quote,
                                weight: weight,
                                pickupLocation: pickupLocation
                            }, function () {
                                alertify.success("Shipment created");
                                self.refresh.valueHasMutated();
                            });
                        });
                        var htmlText = '<div class="form-group" style="text-align: left;">';
                        if (result.data.length > 0) {
                            _.each(result.data, function (rateOption) {
                                htmlText += '<label class="radio" data-provider="' + rateOption.provider + '" for="' + rateOption.quoteId + '"><input style="width: initial; position: relative; margin: 0;" type="radio" id="' + rateOption.quoteId + '" name="shipping" value="' + rateOption.quoteId + '" /> ' + rateOption.carrierName + ' (' + rateOption.deliveryType + '): $' + rateOption.cost + '</label>';
                                htmlText += "<p>" + rateOption.serviceStandard + (rateOption.isRuralDelivery ? " (RD)" : "") + "</p>";
                            });
                        }
                        else {
                            htmlText += '<p>No courier is available for that address</p>';
                        }
                        htmlText += '</div>';
                        $(htmlText).insertAfter(".alertify .msg");
                        l.stop();
                    });
                }
                else {
                    ShipmentService.New()
                        .Update(existingShipmentId, {
                        pickupLocation: pickupLocation,
                        provider: provider,
                        addressId: self.bag().addressId
                    }, function () {
                        alertify.success("Shipment created");
                        self.refresh.valueHasMutated();
                        l.stop();
                    });
                }
            };
            self.packBag = function (d, e) {
                var l = Ladda.create($(e.currentTarget)[0]);
                l.start();
                BagService.New()
                    .UpdateSingle(self.bag().id, "packed", "True", function (updateBagResult) {
                    if (updateBagResult) {
                        alertify.success("Bag marked as packed");
                        self.refresh.valueHasMutated();
                    }
                    else {
                        alertify.error("Error updating bag");
                    }
                    l.stop();
                });
                return false;
            };
            self.markBagAsPickedUp = function (d, e) {
                var l = Ladda.create($(e.currentTarget)[0]);
                l.start();
                ShipmentService.New()
                    .UpdateSingle(self.bag().shipment.id, "pickedUp", new Date().toISOString(), function (updateBagResult) {
                    if (updateBagResult) {
                        alertify.success("Bag marked as picked up (bag shipped email sent)");
                        self.refresh.valueHasMutated();
                    }
                    else {
                        alertify.error("Error updating shipment");
                    }
                    l.stop();
                });
                return true;
            };
            self.markBagAsDelivered = function (d, e) {
                var l = Ladda.create($(e.currentTarget)[0]);
                l.start();
                ShipmentService.New()
                    .UpdateSingle(self.bag().shipment.id, "delivered", new Date().toISOString(), function (updateBagResult) {
                    if (updateBagResult) {
                        alertify.success("Bag marked as delivered (rating email delivered in 3 days)");
                        self.refresh.valueHasMutated();
                    }
                    else {
                        alertify.error("Error updating shipment");
                    }
                    l.stop();
                });
                return false;
            };
            self.addNote = function (d, e) {
                var l = Ladda.create($(e.currentTarget)[0]);
                l.start();
                NoteService.New()
                    .Create({
                    userId: self.bag().userId,
                    bagId: self.bag().id,
                    message: $("#addNote").val()
                }, function () {
                    l.stop();
                    $("#addNote").val('');
                    self.refresh.valueHasMutated();
                });
            };
            self.addUserNote = function (d, e) {
                var l = Ladda.create($(e.currentTarget)[0]);
                l.start();
                NoteService.New()
                    .Create({
                    userId: self.bag().userId,
                    message: $("#addUserNote").val()
                }, function () {
                    l.stop();
                    $("#addUserNote").val('');
                    self.refresh.valueHasMutated();
                });
            };
            self.isLoading(true);
            ko.computed(function () {
                var r = self.refresh();
                BagService.New().GetDetail($("#id").val(), function (result, error) {
                    self.isLoading(false);
                    if (result) {
                        self.bag(result);
                        if (result.invoiceId) {
                            TransactionService.New()
                                .With("invoiceId", result.invoiceId)
                                .Get(0, 1, function (result) {
                                if (result && result.data.length == 1) {
                                    self.lastTransaction(result.data[0]);
                                }
                            });
                        }
                        if (result.orderId) {
                            OrderService.New()
                                .GetDetail(result.orderId, function (result) {
                                self.order(result);
                            });
                        }
                        DogService.New()
                            .With("bagId", result.id)
                            .GetAll(function (result) {
                            self.dogs.removeAll();
                            for (var i = 0; i < result.data.length; i++)
                                self.dogs.push(result.data[i]);
                        });
                        AddressService.New()
                            .GetDetail(result.addressId, function (result) {
                            self.address(result);
                        });
                        NoteService.New()
                            .With("bagId", result.id)
                            .With("type", "bag")
                            .GetAll(function (result) {
                            self.notes.removeAll();
                            for (var i = 0; i < result.data.length; i++)
                                self.notes.push(result.data[i]);
                        });
                        NoteService.New()
                            .With("userId", result.userId)
                            .With("type", "user")
                            .GetAll(function (result) {
                            self.userNotes.removeAll();
                            for (var i = 0; i < result.data.length; i++)
                                self.userNotes.push(result.data[i]);
                        });
                        if (result.planId) {
                            PlanService.New()
                                .GetDetail(result.planId, function (result) {
                                self.plan(result);
                            });
                        }
                        if (result.invoiceId) {
                            InvoiceService.New()
                                .GetDetail(result.invoiceId, function (result) {
                                self.invoice(result);
                            });
                        }
                        BagService.New()
                            .With("userId", result.userId)
                            .Get(0, 0, function (result) {
                            if (result)
                                self.numberOfBags(result.total);
                        });
                        BagService.New()
                            .With("userId", result.userId)
                            .With("isShipped", true)
                            .Get(0, 0, function (result) {
                            if (result)
                                self.numberOfBagsShipped(result.total);
                        });
                    }
                    else {
                        $('[data-error="General"]').text("Woops something went wrong");
                        $('[data-error="General"]').show();
                    }
                });
            });
            $("#delete-button").click(function () {
                self.isLoading(true);
                BagService.New().Delete($("#id").val(), function (result) {
                    self.isLoading(false);
                    if (result) {
                        window.location.pathname = "/admin/bags";
                    }
                    else {
                        $('[data-error="General"]').text("Woops something went wrong");
                        $('[data-error="General"]').show();
                    }
                });
                return false;
            });
            return self;
        };
        return BagDetails;
    }());
    Admin.BagDetails = BagDetails;
})(Admin || (Admin = {}));
//# sourceMappingURL=Admin.BagDetails.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var Admin;
(function (Admin) {
    var BagIndex = /** @class */ (function (_super) {
        __extends(BagIndex, _super);
        function BagIndex() {
            var _this = _super !== null && _super.apply(this, arguments) || this;
            _this.productIdFilter = ko.observable(StorageService.Get(_this.key("productIdFilter")));
            _this.productVariantIdFilter = ko.observable(Utilities.GetUrlParam("productVariantId", document.location));
            _this.reportFilter = ko.observable(StorageService.Get(_this.key("reportFilter")));
            _this.products = ko.observableArray();
            return _this;
        }
        BagIndex.prototype.key = function (key) {
            return "bag-v2-" + key;
        };
        BagIndex.prototype.createModel = function () {
            var self = this;
            var canRun = true;
            if (!self.sort()) {
                self.sort("Name");
                self.sortDirection(Constants.SORT_ASC);
            }
            ko.computed(function () {
                var reportFilter = self.reportFilter();
                if (reportFilter)
                    StorageService.Store(self.key("reportFilter"), reportFilter);
                else
                    StorageService.Clear(self.key("reportFilter"));
            });
            if (Utilities.GetUrlParam("productId", document.location))
                self.productIdFilter(Utilities.GetUrlParam("productId", document.location));
            ko.computed(function () {
                var productIdFilter = self.productIdFilter();
                if (productIdFilter)
                    StorageService.Store(self.key("productIdFilter"), productIdFilter);
                else
                    StorageService.Clear(self.key("productIdFilter"));
            });
            ProductService.New()
                .With("canBeSubscription", true)
                .GetAll(function (result) {
                self.products.removeAll();
                for (var i = 0; i < result.data.length; i++)
                    self.products.push(result.data[i]);
            });
            self.markBagAsPickedUp = function (data, event) {
                var l = Ladda.create($(event.currentTarget).parent().parent().parent().children("a")[0]);
                l.start();
                $(event.currentTarget).parent().parent().parent().removeClass("open");
                var id = $(event.currentTarget).data("id");
                var bag = _.find(self.data(), function (bag) {
                    return bag.id == id;
                });
                if (bag.packed == null) {
                    BagService.New()
                        .UpdateSingle(id, "packed", "True", function (updateBagResult) { });
                }
                ShipmentService.New()
                    .UpdateSingle(bag.shipment.id, "pickedUp", new Date().toISOString(), function (updateBagResult) {
                    if (updateBagResult) {
                        alertify.success("Bag marked as picked up (bag shipped email sent)");
                        self.page.valueHasMutated();
                    }
                    else {
                        alertify.error("Error updating shipment");
                    }
                    l.stop();
                });
                return true;
            };
            self.markBagAsDelivered = function (data, event) {
                var l = Ladda.create($(event.currentTarget).parent().parent().parent().children("a")[0]);
                l.start();
                $(event.currentTarget).parent().parent().parent().removeClass("open");
                var id = $(event.currentTarget).data("id");
                var bag = _.find(self.data(), function (bag) {
                    return bag.id == id;
                });
                if (bag.packed == null) {
                    BagService.New()
                        .UpdateSingle(id, "packed", "True", function (updateBagResult) { });
                }
                ShipmentService.New()
                    .UpdateSingle(bag.shipment.id, "delivered", new Date().toISOString(), function (updateBagResult) {
                    if (updateBagResult) {
                        alertify.success("Bag marked as delivered (rating email delivered in 3 days)");
                        self.page.valueHasMutated();
                    }
                    else {
                        alertify.error("Error updating shipment");
                    }
                    l.stop();
                });
                return true;
            };
            self.markBagAsPacked = function (data, event) {
                var l = Ladda.create($(event.currentTarget).parent().parent().parent().children("a")[0]);
                l.start();
                $(event.currentTarget).parent().parent().parent().removeClass("open");
                var id = $(event.currentTarget).data("id");
                BagService.New()
                    .UpdateSingle(id, "packed", "True", function (updateBagResult) {
                    if (updateBagResult) {
                        alertify.success("Bag marked as packed");
                        self.page.valueHasMutated();
                    }
                    else {
                        alertify.error("Error updating bag");
                    }
                    l.stop();
                });
                return true;
            };
            self.generateShipment = function (data, event) {
                var l = Ladda.create($(event.currentTarget).parent().parent().parent().children("a")[0]);
                l.start();
                $(event.currentTarget).parent().parent().parent().removeClass("open");
                var id = $(event.currentTarget).data("id");
                ShipmentService.New()
                    .Create({}, function (createShipmentResult) {
                    if (createShipmentResult) {
                        var bag = _.find(self.data(), function (bag) {
                            return bag.id == id;
                        });
                        if (bag.shipment) {
                            ShipmentService.New()
                                .Delete(bag.shipmentId);
                        }
                        BagService.New()
                            .UpdateSingle(id, "shipmentId", createShipmentResult.id, function (updateBagResult) {
                            if (updateBagResult) {
                                alertify.success("Shipping quoted - now printing");
                                self.page.valueHasMutated();
                            }
                            else {
                                alertify.error("Error creating shipment");
                            }
                            l.stop();
                        });
                    }
                    else {
                        alertify.error("Error creating shipment");
                        l.stop();
                    }
                });
                return true;
            };
            ko.computed(function () {
                var page = self.page();
                var pageSize = self.pageSize();
                var search = self.search();
                var dir = self.sortDirection();
                var sort = self.sort();
                var productIdFilter = self.productIdFilter();
                var productVariantIdFilter = self.productVariantIdFilter();
                var report = self.reportFilter();
                if (canRun) {
                    canRun = false;
                    if (self.state() == Constants.STATE_READY)
                        self.state(Constants.STATE_BUSY);
                    var service = BagService.New()
                        .With("status", "active")
                        .With("direction", dir)
                        .With("sort", sort)
                        .With("q", search);
                    if (productIdFilter)
                        service = service.With("productId", productIdFilter);
                    if (productVariantIdFilter)
                        service = service.With("productVariantId", productVariantIdFilter);
                    if (report)
                        service = service.With("report", report);
                    service.Get((page - 1) * pageSize, pageSize, function (result) {
                        self.state(Constants.STATE_READY);
                        self.total(result.total);
                        self.data.removeAll();
                        for (var i = 0; i < result.data.length; i++) {
                            self.data.push(result.data[i]);
                        }
                        canRun = true;
                    });
                }
            });
            ko.computed(function () {
                if (self.productIdFilter()) {
                    ProductService.New()
                        .GetDetail(self.productIdFilter(), function (result) {
                        if (result) {
                            self.filteredTo("the product " + result.title);
                        }
                    });
                }
                if (self.productVariantIdFilter()) {
                    ProductVariantService.New()
                        .GetDetail(self.productVariantIdFilter(), function (result) {
                        if (result) {
                            self.filteredTo("the product variant " + result.title);
                        }
                    });
                }
                if (self.productIdFilter() == null && self.productVariantIdFilter() == null)
                    self.filteredTo(null);
            });
            $("#clearFilter").click(function () {
                if (canRun) {
                    self.productIdFilter(null);
                    self.productVariantIdFilter(null);
                    return false;
                }
            });
            return self;
        };
        return BagIndex;
    }(BindableIndexModel));
    Admin.BagIndex = BagIndex;
})(Admin || (Admin = {}));
//# sourceMappingURL=Admin.BagIndex.js.map;
var Admin;
(function (Admin) {
    var BatchAdd = /** @class */ (function () {
        function BatchAdd() {
            this.isLoading = ko.observable(false);
        }
        BatchAdd.prototype.createModel = function () {
            var self = this;
            $("#supplierToAdd").select2({
                ajax: {
                    url: "/api/v1/suppliers",
                    dataType: 'json',
                    delay: 250,
                    data: function (query) {
                        var search = "";
                        if (query.term)
                            search = "q=" + query.term;
                        if (query.page) {
                            if (search.length > 0)
                                search = search + "&";
                            search = search + "skip=" + (query.page - 1) * 5 + "&take=5";
                        }
                        return search;
                    },
                    processResults: function (data, params) {
                        var results = [{
                                id: "",
                                text: "Search for supplier to add"
                            }];
                        if (data && data.data) {
                            for (var i = 0; i < data.data.length; i++) {
                                results.push({
                                    id: data.data[i].id,
                                    text: data.data[i].name
                                });
                            }
                        }
                        return {
                            results: results
                        };
                    },
                    cache: true
                },
                minimumInputLength: 0
            });
            $("#save-button").click(function () {
                $('#save-button').attr("disabled", "disabled");
                self.isLoading(true);
                $("[data-error]").hide();
                BatchService.New().Create({
                    supplierId: $("#supplierToAdd").val(),
                    name: $("#name").val(),
                    invoiceNumber: $("#invoiceNumber").val(),
                    cost: parseFloat($("#cost").val()),
                    expiry: $("#expiry").val().length > 0 ? moment($("#expiry").val(), "DD/MM/YY").toISOString() : null
                }, function (result, error) {
                    $('#save-button').removeAttr("disabled");
                    self.isLoading(false);
                    if (result) {
                        window.location.pathname = "/admin/batches/details/" + result.id;
                    }
                    else if (error && error.errors) {
                        for (var i = 0, len = error.errors.length; i < len; i++) {
                            $('[data-error="' + error.errors[i].key + '"]').text(error.errors[i].error);
                            $('[data-error="' + error.errors[i].key + '"]').show();
                        }
                    }
                    else {
                        $('[data-error="General"]').text("Woops something went wrong");
                        $('[data-error="General"]').show();
                    }
                });
                return false;
            });
            return self;
        };
        return BatchAdd;
    }());
    Admin.BatchAdd = BatchAdd;
})(Admin || (Admin = {}));
//# sourceMappingURL=Admin.BatchAdd.js.map;
var Admin;
(function (Admin) {
    var BatchEdit = /** @class */ (function () {
        function BatchEdit() {
            this.isLoading = ko.observable(false);
            this.isAvailable = ko.observable(false);
        }
        BatchEdit.prototype.createModel = function () {
            var self = this;
            BatchService.New().GetDetail($("#id").val(), function (result) {
                $("#name").val(result.name);
                if (result.expiry)
                    $("#expiry").val(moment.utc(result.expiry).local().format("DD/MM/YY"));
                $("#invoiceNumber").val(result.invoiceNumber);
                $("#cost").val(result.cost);
                self.isAvailable(result.isAvailable);
                $("#supplierToAdd")
                    .append('<option value="' + result.supplier.id + '">' + result.supplier.name + '</option>')
                    .val(result.supplier.id)
                    .trigger("change");
                $("#supplierToAdd").select2({
                    ajax: {
                        url: "/api/v1/suppliers",
                        dataType: 'json',
                        delay: 250,
                        data: function (query) {
                            var search = "";
                            if (query.term)
                                search = "q=" + query.term;
                            if (query.page) {
                                if (search.length > 0)
                                    search = search + "&";
                                search = search + "skip=" + (query.page - 1) * 5 + "&take=5";
                            }
                            return search;
                        },
                        processResults: function (data, params) {
                            var results = [{
                                    id: "",
                                    text: "Search for supplier to add"
                                }];
                            if (data && data.data) {
                                for (var i = 0; i < data.data.length; i++) {
                                    results.push({
                                        id: data.data[i].id,
                                        text: data.data[i].name
                                    });
                                }
                            }
                            return {
                                results: results
                            };
                        },
                        cache: true
                    },
                    minimumInputLength: 0
                });
            });
            $("#save-button").click(function () {
                $('#save-button').attr("disabled", "disabled");
                self.isLoading(true);
                $("[data-error]").hide();
                BatchService.New().Update($("#id").val(), {
                    supplierId: $("#supplierToAdd").val(),
                    name: $("#name").val(),
                    invoiceNumber: $("#invoiceNumber").val(),
                    cost: parseFloat($("#cost").val()),
                    isAvailable: self.isAvailable(),
                    expiry: $("#expiry").val().length > 0 ? moment($("#expiry").val(), "DD/MM/YY").toISOString() : null
                }, function (result, error) {
                    $('#save-button').removeAttr("disabled");
                    self.isLoading(false);
                    if (result) {
                        window.location.pathname = "/admin/batches/details/" + $("#id").val();
                    }
                    else if (error && error.errors) {
                        for (var i = 0, len = error.errors.length; i < len; i++) {
                            $('[data-error="' + error.errors[i].key + '"]').text(error.errors[i].error);
                            $('[data-error="' + error.errors[i].key + '"]').show();
                        }
                    }
                    else {
                        $('[data-error="General"]').text("Woops something went wrong");
                        $('[data-error="General"]').show();
                    }
                });
                return false;
            });
            return self;
        };
        return BatchEdit;
    }());
    Admin.BatchEdit = BatchEdit;
})(Admin || (Admin = {}));
//# sourceMappingURL=Admin.BatchEdit.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var Admin;
(function (Admin) {
    var BatchIndex = /** @class */ (function (_super) {
        __extends(BatchIndex, _super);
        function BatchIndex() {
            var _this = _super !== null && _super.apply(this, arguments) || this;
            _this.supplierIdFilter = ko.observable(Utilities.GetUrlParam("supplierId", document.location));
            _this.expiryFilter = ko.observable(StorageService.Get(_this.key("expiryFilter")));
            _this.isAvailable = ko.observable(StorageService.Get(_this.key("isAvailable")));
            return _this;
        }
        BatchIndex.prototype.key = function (key) {
            return "batch-v2-" + key;
        };
        BatchIndex.prototype.createModel = function () {
            var self = this;
            var canRun = true;
            if (!self.sort()) {
                self.sort("Name");
                self.sortDirection(Constants.SORT_ASC);
            }
            ko.computed(function () {
                var expiryFilter = self.expiryFilter();
                if (expiryFilter) {
                    StorageService.Store(self.key("expiryFilter"), expiryFilter);
                }
                else {
                    StorageService.Clear(self.key("expiryFilter"));
                }
            });
            ko.computed(function () {
                var isAvailable = self.isAvailable();
                if (isAvailable) {
                    StorageService.Store(self.key("isAvailable"), isAvailable);
                }
                else {
                    StorageService.Clear(self.key("isAvailable"));
                }
            });
            ko.computed(function () {
                var page = self.page();
                var pageSize = self.pageSize();
                var search = self.search();
                var dir = self.sortDirection();
                var sort = self.sort();
                var supplierIdFilter = self.supplierIdFilter();
                var isAvailable = self.isAvailable();
                var expiryFilter = self.expiryFilter();
                if (canRun) {
                    canRun = false;
                    if (self.state() == Constants.STATE_READY)
                        self.state(Constants.STATE_BUSY);
                    var service = BatchService.New()
                        .With("status", "active")
                        .With("direction", dir)
                        .With("sort", sort)
                        .With("q", search);
                    if (supplierIdFilter)
                        service = service.With("supplierId", supplierIdFilter);
                    if (isAvailable)
                        service = service.With("isAvailable", isAvailable);
                    if (expiryFilter) {
                        if (expiryFilter == "near-expiry")
                            service = service.With("nearExpiry", true);
                        if (expiryFilter == "expired")
                            service = service.With("expired", true);
                        if (expiryFilter == "not-expired")
                            service = service.With("expired", false);
                    }
                    service.Get((page - 1) * pageSize, pageSize, function (result) {
                        self.state(Constants.STATE_READY);
                        self.total(result.total);
                        self.data.removeAll();
                        for (var i = 0; i < result.data.length; i++) {
                            self.data.push(result.data[i]);
                        }
                        canRun = true;
                    });
                }
            });
            ko.computed(function () {
                if (self.supplierIdFilter()) {
                    SupplierService.New()
                        .GetDetail(self.supplierIdFilter(), function (result) {
                        if (result) {
                            self.filteredTo("the supplier " + result.name);
                        }
                    });
                }
                if (self.supplierIdFilter() == null)
                    self.filteredTo(null);
            });
            $("#clearFilter").click(function () {
                if (canRun) {
                    self.supplierIdFilter(null);
                    return false;
                }
            });
            return self;
        };
        return BatchIndex;
    }(BindableIndexModel));
    Admin.BatchIndex = BatchIndex;
})(Admin || (Admin = {}));
//# sourceMappingURL=Admin.BatchIndex.js.map;
var Admin;
(function (Admin) {
    var BrandDetails = /** @class */ (function () {
        function BrandDetails() {
            this.name = ko.observable();
            this.location = ko.observable();
            this.isLoading = ko.observable(false);
            this.productTotal = ko.observable();
            this.productVariantTotal = ko.observable();
            this.stockTotal = ko.observable();
        }
        BrandDetails.prototype.createModel = function () {
            var self = this;
            self.isLoading(true);
            BrandService.New().GetDetail($("#id").val(), function (result, error) {
                self.isLoading(false);
                if (result) {
                    self.name(result.name);
                    self.location(result.location);
                }
                else {
                    $('[data-error="General"]').text("Woops something went wrong");
                    $('[data-error="General"]').show();
                }
            });
            ProductService.New()
                .With("brandId", $("#id").val())
                .Get(0, 0, function (result) {
                if (result)
                    self.productTotal(result.total);
            });
            ProductVariantService.New()
                .With("brandId", $("#id").val())
                .Get(0, 0, function (result) {
                if (result)
                    self.productVariantTotal(result.total);
            });
            StockService.New()
                .With("brandId", $("#id").val())
                .With("hasAvailable", true)
                .Get(0, 0, function (result) {
                if (result)
                    self.stockTotal(result.total);
            });
            $("#delete-button").click(function () {
                self.isLoading(true);
                BrandService.New().Delete($("#id").val(), function (result) {
                    self.isLoading(false);
                    if (result) {
                        window.location.pathname = "/admin/brands";
                    }
                    else {
                        $('[data-error="General"]').text("Woops something went wrong");
                        $('[data-error="General"]').show();
                    }
                });
                return false;
            });
            return self;
        };
        return BrandDetails;
    }());
    Admin.BrandDetails = BrandDetails;
})(Admin || (Admin = {}));
//# sourceMappingURL=Admin.BrandDetails.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var Admin;
(function (Admin) {
    var BrandIndex = /** @class */ (function (_super) {
        __extends(BrandIndex, _super);
        function BrandIndex() {
            var _this = _super !== null && _super.apply(this, arguments) || this;
            _this.isAddMode = ko.observable(false);
            return _this;
        }
        BrandIndex.prototype.key = function (key) {
            return "brand-v2-" + key;
        };
        BrandIndex.prototype.createModel = function () {
            var self = this;
            var canRun = true;
            if (!self.sort()) {
                self.sort("Name");
                self.sortDirection(Constants.SORT_ASC);
            }
            $('#nameToAdd').on('keydown', function (e) {
                if (e.which == 13) {
                    e.preventDefault();
                    self.addEntity();
                }
            });
            $('#locationToAdd').on('keydown', function (e) {
                if (e.which == 13) {
                    e.preventDefault();
                    self.addEntity();
                }
            });
            self.addEntity = function () {
                if ($("#nameToAdd").val() && $("#locationToAdd").val()) {
                    BrandService.New().Create({
                        name: $("#nameToAdd").val(),
                        location: $("#locationToAdd").val()
                    }, function (result, error) {
                        if (result) {
                            self.isAddMode(false);
                            alertify.success("Brand added");
                            self.page.valueHasMutated();
                            $("#nameToAdd").val("");
                            $("#locationToAdd").val("");
                        }
                        else {
                            alertify.error("Cannot add brand");
                        }
                    });
                }
                else {
                    alertify.error("Please enter a value");
                }
                return false;
            };
            ko.computed(function () {
                var page = self.page();
                var pageSize = self.pageSize();
                var search = self.search();
                var dir = self.sortDirection();
                var sort = self.sort();
                if (canRun) {
                    canRun = false;
                    if (self.state() == Constants.STATE_READY)
                        self.state(Constants.STATE_BUSY);
                    var service = BrandService.New()
                        .With("status", "active")
                        .With("direction", dir)
                        .With("sort", sort)
                        .With("q", search)
                        .Get((page - 1) * pageSize, pageSize, function (result) {
                        self.state(Constants.STATE_READY);
                        self.total(result.total);
                        self.data.removeAll();
                        for (var i = 0; i < result.data.length; i++) {
                            self.data.push(result.data[i]);
                        }
                        canRun = true;
                        setTimeout(function () {
                            $(".editable-name").editable({
                                pk: 1,
                                mode: "inline",
                                type: 'text',
                                success: function (response, newValue) {
                                    BrandService.New().UpdateSingle($(this).attr("id"), "name", newValue);
                                }
                            }).on('shown', function (e, editable) {
                                editable.input.$input.val($(e.currentTarget).text().trim());
                            });
                            $(".editable-location").editable({
                                pk: 1,
                                mode: "inline",
                                type: 'text',
                                success: function (response, newValue) {
                                    BrandService.New().UpdateSingle($(this).attr("id"), "location", newValue);
                                }
                            }).on('shown', function (e, editable) {
                                editable.input.$input.val($(e.currentTarget).text().trim());
                            });
                        }, 10);
                    });
                }
            });
            return self;
        };
        return BrandIndex;
    }(BindableIndexModel));
    Admin.BrandIndex = BrandIndex;
})(Admin || (Admin = {}));
//# sourceMappingURL=Admin.BrandIndex.js.map;
var Admin;
(function (Admin) {
    var BreedDetails = /** @class */ (function () {
        function BreedDetails() {
            this.name = ko.observable();
            this.verified = ko.observable();
            this.isLoading = ko.observable(false);
            this.dogTotal = ko.observable();
            this.planTotal = ko.observable();
            this.bagTotal = ko.observable();
        }
        BreedDetails.prototype.createModel = function () {
            var self = this;
            self.isLoading(true);
            BreedService.New().GetDetail($("#id").val(), function (result, error) {
                self.isLoading(false);
                if (result) {
                    self.name(result.name);
                    self.verified(result.verified);
                }
                else {
                    $('[data-error="General"]').text("Woops something went wrong");
                    $('[data-error="General"]').show();
                }
            });
            BagService.New()
                .With("breedId", $("#id").val())
                .Get(0, 0, function (result) {
                if (result)
                    self.bagTotal(result.total);
            });
            PlanService.New()
                .With("breedId", $("#id").val())
                .Get(0, 0, function (result) {
                if (result)
                    self.planTotal(result.total);
            });
            DogService.New()
                .With("breedId", $("#id").val())
                .Get(0, 0, function (result) {
                if (result)
                    self.dogTotal(result.total);
            });
            $("#delete-button").click(function () {
                self.isLoading(true);
                BreedService.New().Delete($("#id").val(), function (result) {
                    self.isLoading(false);
                    if (result) {
                        window.location.pathname = "/admin/breeds";
                    }
                    else {
                        $('[data-error="General"]').text("Woops something went wrong");
                        $('[data-error="General"]').show();
                    }
                });
                return false;
            });
            return self;
        };
        return BreedDetails;
    }());
    Admin.BreedDetails = BreedDetails;
})(Admin || (Admin = {}));
//# sourceMappingURL=Admin.BreedDetails.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var Admin;
(function (Admin) {
    var BreedIndex = /** @class */ (function (_super) {
        __extends(BreedIndex, _super);
        function BreedIndex() {
            var _this = _super !== null && _super.apply(this, arguments) || this;
            _this.isVerifiedFilter = ko.observable(StorageService.Get(_this.key("isVerified")));
            _this.isMergeMode = ko.observable(false);
            _this.isAddMode = ko.observable(false);
            return _this;
        }
        BreedIndex.prototype.key = function (key) {
            return "breed-v2-" + key;
        };
        BreedIndex.prototype.createModel = function () {
            var self = this;
            var canRun = true;
            $('#nameToAdd').on('keydown', function (e) {
                if (e.which == 13) {
                    e.preventDefault();
                    self.addBreed();
                }
            });
            self.addBreed = function () {
                if ($("#nameToAdd").val()) {
                    BreedService.New().Create({
                        name: $("#nameToAdd").val()
                    }, function (result, error) {
                        if (result) {
                            self.isAddMode(false);
                            alertify.success("Breed added");
                            self.page.valueHasMutated();
                            $("#nameToAdd").val("");
                        }
                        else {
                            alertify.error("Cannot add breed");
                        }
                    });
                }
                else {
                    alertify.error("Please enter a value");
                }
                return false;
            };
            self.mergeBreeds = function () {
                BreedService.Merge($("#breedToMerge").val(), $("#breedToKeep").val(), function () {
                    self.isMergeMode(!self.isMergeMode());
                    self.page.valueHasMutated();
                    $("#breedToMerge").val("").trigger('change');
                    $("#breedToKeep").val("").trigger('change');
                });
            };
            if (!self.sort()) {
                self.sort("Name");
                self.sortDirection(Constants.SORT_ASC);
            }
            ko.computed(function () {
                var page = self.page();
                var pageSize = self.pageSize();
                var search = self.search();
                var dir = self.sortDirection();
                var sort = self.sort();
                var isVerifiedFilter = self.isVerifiedFilter();
                if (canRun) {
                    canRun = false;
                    if (self.state() == Constants.STATE_READY)
                        self.state(Constants.STATE_BUSY);
                    var service = BreedService.New()
                        .With("status", "active")
                        .With("direction", dir)
                        .With("sort", sort)
                        .With("verified", isVerifiedFilter)
                        .With("q", search)
                        .Get((page - 1) * pageSize, pageSize, function (result) {
                        self.state(Constants.STATE_READY);
                        self.total(result.total);
                        self.data.removeAll();
                        for (var i = 0; i < result.data.length; i++) {
                            self.data.push(result.data[i]);
                        }
                        canRun = true;
                        setTimeout(function () {
                            $(".editable-name").editable({
                                pk: 1,
                                mode: "inline",
                                type: 'text',
                                success: function (response, newValue) {
                                    BreedService.New().UpdateSingle($(this).attr("id"), "name", newValue);
                                }
                            }).on('shown', function (e, editable) {
                                editable.input.$input.val($(e.currentTarget).text().trim());
                            });
                            $(".editable-verified").editable({
                                pk: 2,
                                type: 'select',
                                mode: "inline",
                                source: [{ value: "Verified", text: "Verified" }, { value: "Not verified", text: "Not verified" }],
                                success: function (response, newValue) {
                                    if (newValue == "Verified") {
                                        BreedService.New().UpdateSingle($(this).attr("id"), "isVerified", "true");
                                    }
                                    else {
                                        BreedService.New().UpdateSingle($(this).attr("id"), "isVerified", "false");
                                    }
                                }
                            }).on('shown', function (e, editable) {
                                editable.input.$input.val($(e.currentTarget).text().trim());
                            });
                        }, 10);
                    });
                }
            });
            ko.computed(function () {
                var isVerifiedFilter = self.isVerifiedFilter();
                if (isVerifiedFilter) {
                    StorageService.Store(self.key("isVerified"), isVerifiedFilter);
                }
                else {
                    StorageService.Clear(self.key("isVerified"));
                }
            });
            $("#breedToKeep").select2({
                ajax: {
                    url: "/api/v1/breeds",
                    dataType: 'json',
                    delay: 250,
                    data: function (query) {
                        var search = "";
                        if (query.term)
                            search = "q=" + query.term;
                        if (query.page) {
                            if (search.length > 0)
                                search = search + "&";
                            search = search + "skip=" + (query.page - 1) * 5 + "&take=5";
                        }
                        return search;
                    },
                    processResults: function (data, params) {
                        var results = [{
                                id: "",
                                text: "Search for a breed"
                            }];
                        if (data && data.data) {
                            for (var i = 0; i < data.data.length; i++) {
                                results.push({
                                    id: data.data[i].id,
                                    text: data.data[i].name
                                });
                            }
                        }
                        return {
                            results: results
                        };
                    },
                    cache: true
                },
                minimumInputLength: 0
            });
            $("#breedToMerge").select2({
                ajax: {
                    url: "/api/v1/breeds",
                    dataType: 'json',
                    delay: 250,
                    data: function (query) {
                        var search = "";
                        if (query.term)
                            search = "q=" + query.term;
                        if (query.page) {
                            if (search.length > 0)
                                search = search + "&";
                            search = search + "skip=" + (query.page - 1) * 5 + "&take=5";
                        }
                        return search;
                    },
                    processResults: function (data, params) {
                        var results = [{
                                id: "",
                                text: "Search for a breed"
                            }];
                        if (data && data.data) {
                            for (var i = 0; i < data.data.length; i++) {
                                results.push({
                                    id: data.data[i].id,
                                    text: data.data[i].name
                                });
                            }
                        }
                        return {
                            results: results
                        };
                    },
                    cache: true
                },
                minimumInputLength: 0
            });
            return self;
        };
        return BreedIndex;
    }(BindableIndexModel));
    Admin.BreedIndex = BreedIndex;
})(Admin || (Admin = {}));
//# sourceMappingURL=Admin.BreedIndex.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var Admin;
(function (Admin) {
    var CartIndex = /** @class */ (function (_super) {
        __extends(CartIndex, _super);
        function CartIndex() {
            var _this = _super !== null && _super.apply(this, arguments) || this;
            _this.productIdFilter = ko.observable(StorageService.Get(_this.key("productIdFilter")));
            _this.productVariantIdFilter = ko.observable(Utilities.GetUrlParam("productVariantId", document.location));
            _this.reportFilter = ko.observable(StorageService.Get(_this.key("reportFilter")));
            _this.hasItemsFilter = ko.observable(StorageService.Get(_this.key("hasItemsFilter")));
            _this.products = ko.observableArray();
            return _this;
        }
        CartIndex.prototype.key = function (key) {
            return "cart-v2-" + key;
        };
        CartIndex.prototype.createModel = function () {
            var self = this;
            var canRun = true;
            var cpli = new Clipboard('.btn-copy');
            cpli.on('success', function (e) {
                alertify.success("Copied to clipboard");
                $(".alertify button").click();
            });
            if (!self.sort()) {
                self.sort("Name");
                self.sortDirection(Constants.SORT_ASC);
            }
            ko.computed(function () {
                var hasItemsFilter = self.hasItemsFilter();
                if (hasItemsFilter)
                    StorageService.Store(self.key("hasItemsFilter"), hasItemsFilter);
                else
                    StorageService.Clear(self.key("hasItemsFilter"));
            });
            ko.computed(function () {
                var reportFilter = self.reportFilter();
                if (reportFilter)
                    StorageService.Store(self.key("reportFilter"), reportFilter);
                else
                    StorageService.Clear(self.key("reportFilter"));
            });
            if (Utilities.GetUrlParam("productId", document.location))
                self.productIdFilter(Utilities.GetUrlParam("productId", document.location));
            ko.computed(function () {
                var productIdFilter = self.productIdFilter();
                if (productIdFilter)
                    StorageService.Store(self.key("productIdFilter"), productIdFilter);
                else
                    StorageService.Clear(self.key("productIdFilter"));
            });
            ProductService.New()
                .With("canBeSubscription", true)
                .GetAll(function (result) {
                self.products.removeAll();
                for (var i = 0; i < result.data.length; i++)
                    self.products.push(result.data[i]);
            });
            ko.computed(function () {
                var page = self.page();
                var pageSize = self.pageSize();
                var search = self.search();
                var dir = self.sortDirection();
                var sort = self.sort();
                var productIdFilter = self.productIdFilter();
                var productVariantIdFilter = self.productVariantIdFilter();
                var report = self.reportFilter();
                var hasItems = self.hasItemsFilter();
                if (canRun) {
                    canRun = false;
                    if (self.state() == Constants.STATE_READY)
                        self.state(Constants.STATE_BUSY);
                    var service = CartService.New()
                        .With("status", "active")
                        .With("direction", dir)
                        .With("sort", sort)
                        .With("q", search);
                    if (productIdFilter)
                        service = service.With("productId", productIdFilter);
                    if (productVariantIdFilter)
                        service = service.With("productVariantId", productVariantIdFilter);
                    if (report)
                        service = service.With("report", report);
                    if (hasItems)
                        service = service.With("hasItems", hasItems);
                    service.Get((page - 1) * pageSize, pageSize, function (result) {
                        self.state(Constants.STATE_READY);
                        self.total(result.total);
                        self.data.removeAll();
                        for (var i = 0; i < result.data.length; i++) {
                            self.data.push(result.data[i]);
                        }
                        canRun = true;
                    });
                }
            });
            ko.computed(function () {
                if (self.productIdFilter()) {
                    ProductService.New()
                        .GetDetail(self.productIdFilter(), function (result) {
                        if (result) {
                            self.filteredTo("the product " + result.title);
                        }
                    });
                }
                if (self.productVariantIdFilter()) {
                    ProductVariantService.New()
                        .GetDetail(self.productVariantIdFilter(), function (result) {
                        if (result) {
                            self.filteredTo("the product variant " + result.title);
                        }
                    });
                }
                if (self.productIdFilter() == null && self.productVariantIdFilter() == null)
                    self.filteredTo(null);
            });
            $("#clearFilter").click(function () {
                if (canRun) {
                    self.productIdFilter(null);
                    self.productVariantIdFilter(null);
                    return false;
                }
            });
            self.copySSOLink = function (data, event) {
                var l = Ladda.create($(event.currentTarget).parent().parent().parent().children("a")[0]);
                l.start();
                $(event.currentTarget).parent().parent().parent().removeClass("open");
                var id = $(event.currentTarget).data("id");
                var element = $(event.currentTarget);
                var cart = _.find(self.data(), function (cart) {
                    return cart.id == id;
                });
                AuthorisationTokenService.New()
                    .Create({
                    userId: cart.userId,
                    returnUrl: "/view/cart/" + cart.id
                }, function (result) {
                    if (result) {
                        alertify.alert("SSO link ready");
                        $('<button class="btn btn-primary btn-copy" data-clipboard-text="' + document.location.protocol + '//' + document.location.host + result.url + '">Copy to clipboard</button>').insertAfter(".alertify .msg");
                    }
                    else {
                        alertify.error("Error getting SSO token");
                    }
                    l.stop();
                });
                return true;
            };
            return self;
        };
        return CartIndex;
    }(BindableIndexModel));
    Admin.CartIndex = CartIndex;
})(Admin || (Admin = {}));
//# sourceMappingURL=Admin.CartIndex.js.map;
var Admin;
(function (Admin) {
    var CollectionDetails = /** @class */ (function () {
        function CollectionDetails() {
            this.name = ko.observable();
            this.friendlyId = ko.observable();
            this.isLoading = ko.observable(false);
            this.isAddProductMode = ko.observable(false);
            this.isAddAttributeMode = ko.observable(false);
            this.refresh = ko.observable(false);
            this.products = ko.observableArray();
            this.attributeTypes = ko.observableArray();
        }
        CollectionDetails.prototype.createModel = function () {
            var self = this;
            self.isLoading(true);
            CollectionService.New().GetDetail($("#id").val(), function (result, error) {
                self.isLoading(false);
                if (result) {
                    self.name(result.name);
                    self.friendlyId(result.friendlyId);
                }
                else {
                    $('[data-error="General"]').text("Woops something went wrong");
                    $('[data-error="General"]').show();
                }
                setTimeout(function () {
                    $("#editable-collection-name").editable({
                        pk: 1,
                        mode: "inline",
                        type: 'text',
                        success: function (response, newValue) {
                            CollectionService.New().UpdateSingle($("#id").val(), "name", newValue);
                        }
                    }).on('shown', function (e, editable) {
                        editable.input.$input.val($(e.currentTarget).text().trim());
                    });
                    $("#editable-collection-friendlyId").editable({
                        pk: 1,
                        mode: "inline",
                        type: 'text',
                        success: function (response, newValue) {
                            CollectionService.New().UpdateSingle($("#id").val(), "friendlyId", newValue);
                        }
                    }).on('shown', function (e, editable) {
                        editable.input.$input.val($(e.currentTarget).text().trim());
                    });
                }, 10);
            });
            ko.computed(function () {
                var refresh = self.refresh();
                ProductService.New()
                    .With("collectionId", $("#id").val())
                    .GetAll(function (result, error) {
                    if (result) {
                        self.products.removeAll();
                        (_a = self.products).push.apply(_a, result.data);
                    }
                    var _a;
                });
                AttributeTypeService.New()
                    .With("collectionId", $("#id").val())
                    .GetAll(function (result, error) {
                    if (result) {
                        self.attributeTypes.removeAll();
                        (_a = self.attributeTypes).push.apply(_a, result.data);
                    }
                    var _a;
                });
            });
            self.linkAttributeType = function () {
                if ($("#attributeToAdd").val()) {
                    CollectionService.New().Action($("#id").val(), "link-attribute-type", {
                        attributeTypeId: $("#attributeToAdd").val()
                    }, function () {
                        self.refresh.valueHasMutated();
                        $("#attributeToAdd").val("").trigger('change');
                    });
                }
            };
            self.unlinkAttributeType = function (data) {
                CollectionService.New().Action($("#id").val(), "unlink-attribute-type", {
                    attributeTypeId: data.id
                }, function () {
                    self.refresh.valueHasMutated();
                });
            };
            self.linkProduct = function () {
                if ($("#productToAdd").val()) {
                    CollectionService.New().Action($("#id").val(), "link-product", {
                        productId: $("#productToAdd").val()
                    }, function () {
                        self.refresh.valueHasMutated();
                        $("#productToAdd").val("").trigger('change');
                    });
                }
            };
            self.unlinkProduct = function (data) {
                CollectionService.New().Action($("#id").val(), "unlink-product", {
                    productId: data.id
                }, function () {
                    self.refresh.valueHasMutated();
                });
            };
            CollectionService.New().GetDetail($("#id").val(), function (result, error) {
                self.isLoading(false);
                if (result) {
                    self.name(result.name);
                    self.friendlyId(result.friendlyId);
                }
                else {
                    $('[data-error="General"]').text("Woops something went wrong");
                    $('[data-error="General"]').show();
                }
            });
            $("#productToAdd").select2({
                ajax: {
                    url: "/api/v1/products?skip=0&take=20&excludeCollectionId=" + $("#id").val(),
                    dataType: 'json',
                    delay: 250,
                    data: function (query) {
                        var search = "";
                        if (query.term)
                            search = "&q=" + query.term;
                        return search;
                    },
                    processResults: function (data, params) {
                        var results = [{
                                id: "",
                                text: "Search for a product"
                            }];
                        if (data && data.data) {
                            for (var i = 0; i < data.data.length; i++) {
                                results.push({
                                    id: data.data[i].id,
                                    text: data.data[i].title
                                });
                            }
                        }
                        return {
                            results: results
                        };
                    },
                    cache: true
                },
                minimumInputLength: 0
            });
            $("#attributeToAdd").select2({
                ajax: {
                    url: "/api/v1/attributetypes?skip=0&take=20&excludeCollectionId=" + $("#id").val(),
                    dataType: 'json',
                    delay: 250,
                    data: function (query) {
                        var search = "";
                        if (query.term)
                            search = "&q=" + query.term;
                        return search;
                    },
                    processResults: function (data, params) {
                        var results = [{
                                id: "",
                                text: "Search for a product"
                            }];
                        if (data && data.data) {
                            for (var i = 0; i < data.data.length; i++) {
                                results.push({
                                    id: data.data[i].id,
                                    text: data.data[i].name
                                });
                            }
                        }
                        return {
                            results: results
                        };
                    },
                    cache: true
                },
                minimumInputLength: 0
            });
            $("#delete-button").click(function () {
                self.isLoading(true);
                CollectionService.New().Delete($("#id").val(), function (result) {
                    self.isLoading(false);
                    if (result) {
                        window.location.pathname = "/admin/collections";
                    }
                    else {
                        $('[data-error="General"]').text("Woops something went wrong");
                        $('[data-error="General"]').show();
                    }
                });
                return false;
            });
            return self;
        };
        return CollectionDetails;
    }());
    Admin.CollectionDetails = CollectionDetails;
})(Admin || (Admin = {}));
//# sourceMappingURL=Admin.CollectionDetails.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var Admin;
(function (Admin) {
    var CollectionIndex = /** @class */ (function (_super) {
        __extends(CollectionIndex, _super);
        function CollectionIndex() {
            var _this = _super !== null && _super.apply(this, arguments) || this;
            _this.isAddMode = ko.observable(false);
            return _this;
        }
        CollectionIndex.prototype.key = function (key) {
            return "collection-v2-" + key;
        };
        CollectionIndex.prototype.createModel = function () {
            var self = this;
            var canRun = true;
            self.addEntity = function () {
                if ($("#nameToAdd").val()) {
                    CollectionService.New().Create({
                        name: $("#nameToAdd").val()
                    }, function (result, error) {
                        if (result) {
                            self.isAddMode(false);
                            alertify.success("Attribute added");
                            self.page.valueHasMutated();
                        }
                        else {
                            alertify.error("Cannot add attribute");
                        }
                    });
                }
                else {
                    alertify.error("Please enter in a value");
                }
                return false;
            };
            if (!self.sort()) {
                self.sort("Name");
                self.sortDirection(Constants.SORT_ASC);
            }
            ko.computed(function () {
                var page = self.page();
                var pageSize = self.pageSize();
                var search = self.search();
                var dir = self.sortDirection();
                var sort = self.sort();
                if (canRun) {
                    canRun = false;
                    if (self.state() == Constants.STATE_READY)
                        self.state(Constants.STATE_BUSY);
                    var service = CollectionService.New()
                        .With("status", "active")
                        .With("direction", dir)
                        .With("sort", sort)
                        .With("q", search)
                        .Get((page - 1) * pageSize, pageSize, function (result) {
                        self.state(Constants.STATE_READY);
                        self.total(result.total);
                        self.data.removeAll();
                        for (var i = 0; i < result.data.length; i++) {
                            self.data.push(result.data[i]);
                        }
                        canRun = true;
                        setTimeout(function () {
                            $(".editable-name").editable({
                                pk: 1,
                                mode: "inline",
                                type: 'text',
                                success: function (response, newValue) {
                                    CollectionService.New().UpdateSingle($(this).attr("id"), "name", newValue);
                                }
                            }).on('shown', function (e, editable) {
                                editable.input.$input.val($(e.currentTarget).text().trim());
                            });
                        }, 10);
                    });
                }
            });
            return self;
        };
        return CollectionIndex;
    }(BindableIndexModel));
    Admin.CollectionIndex = CollectionIndex;
})(Admin || (Admin = {}));
//# sourceMappingURL=Admin.CollectionIndex.js.map;
var Admin;
(function (Admin) {
    var Dashboard = /** @class */ (function () {
        function Dashboard() {
            this.loadingState = ko.observable(Constants.STATE_INITIAL);
            this.planCountStats = ko.observable();
            this.toplineStats = ko.observable();
            this.bagShippedBagStats = ko.observable();
            this.bagSoldBagStats = ko.observable();
            this.bagSalesBagStats = ko.observable();
            this.revenueOverviewStats = ko.observable();
        }
        Dashboard.prototype.createModel = function () {
            var self = this;
            ko.computed(function () {
                StatisticService.New()
                    .GetDetail("plan-counts", function (result) {
                    self.planCountStats(result);
                });
                StatisticService.New()
                    .GetDetail("topline", function (result) {
                    self.toplineStats(result);
                });
                StatisticService.New()
                    .GetDetail("bags-shipped-graph-month", function (result) {
                    self.bagShippedBagStats(result);
                    var canvas = document.getElementById("widget-chart-earnings");
                    var ctx = canvas.getContext('2d');
                    var myChart = new Chart(ctx, {
                        type: 'bar',
                        data: {
                            labels: _.map(result.graphData, function (item) {
                                return item.label;
                            }),
                            datasets: [{
                                    label: 'Bags',
                                    data: _.map(result.graphData, function (item) {
                                        return item.value;
                                    })
                                }]
                        },
                        options: {
                            legend: {
                                display: false
                            },
                            responsive: true,
                            maintainAspectRatio: false,
                            scales: {
                                xAxes: [{
                                        display: false
                                    }]
                            }
                        }
                    });
                });
                StatisticService.New()
                    .GetDetail("bags-sold-graph-month", function (result) {
                    self.bagSoldBagStats(result);
                    var canvas = document.getElementById("widget-chart-sold");
                    var ctx = canvas.getContext('2d');
                    var myChart = new Chart(ctx, {
                        type: 'bar',
                        data: {
                            labels: _.map(result.graphData, function (item) {
                                return item.label;
                            }),
                            datasets: [{
                                    label: 'Bags',
                                    data: _.map(result.graphData, function (item) {
                                        return item.value;
                                    })
                                }]
                        },
                        options: {
                            legend: {
                                display: false
                            },
                            responsive: true,
                            maintainAspectRatio: false,
                            scales: {
                                xAxes: [{
                                        display: false
                                    }]
                            }
                        }
                    });
                });
                StatisticService.New()
                    .GetDetail("bags-sales-graph-month", function (result) {
                    self.bagSalesBagStats(result);
                    var canvas = document.getElementById("widget-chart-sales");
                    var ctx = canvas.getContext('2d');
                    var myChart = new Chart(ctx, {
                        type: 'bar',
                        data: {
                            labels: _.map(result.graphData, function (item) {
                                return item.label;
                            }),
                            datasets: [{
                                    label: 'Settled',
                                    data: _.map(result.graphData, function (item) {
                                        return item.value;
                                    })
                                }]
                        },
                        options: {
                            legend: {
                                display: false
                            },
                            responsive: true,
                            maintainAspectRatio: false,
                            scales: {
                                xAxes: [{
                                        display: false
                                    }]
                            }
                        }
                    });
                });
                StatisticService.New()
                    .GetDetail("revenue-overview", function (result) {
                    self.revenueOverviewStats(result);
                    var canvas = document.getElementById("widget-chart-revenue-overview");
                    var ctx = canvas.getContext('2d');
                    var myChart = new Chart(ctx, {
                        type: 'bar',
                        data: {
                            labels: _.map(result.graphData, function (item) {
                                return item.label;
                            }),
                            datasets: [{
                                    label: 'Revenue',
                                    data: _.map(result.graphData, function (item) {
                                        return item.value;
                                    })
                                }]
                        },
                        options: {
                            legend: {
                                display: false
                            },
                            responsive: true,
                            maintainAspectRatio: false,
                            scales: {
                                xAxes: [{
                                        display: false
                                    }]
                            }
                        }
                    });
                });
            });
            return self;
        };
        return Dashboard;
    }());
    Admin.Dashboard = Dashboard;
})(Admin || (Admin = {}));
//# sourceMappingURL=Admin.Dashboard.js.map;
var Admin;
(function (Admin) {
    var DogAdd = /** @class */ (function () {
        function DogAdd() {
            this.isLoading = ko.observable(false);
            this.name = ko.observable();
            this.userId = ko.observable();
            this.breed = ko.observable();
            this.day = ko.observable();
            this.month = ko.observable();
            this.year = ko.observable();
            this.size = ko.observable();
            this.specialRequirements = ko.observable();
            this.isFriendsDog = ko.observable();
        }
        DogAdd.prototype.createModel = function () {
            var self = this;
            $("#ownerToAdd").change(function () {
                self.userId($("#ownerToAdd").val());
            });
            $("#breedToAdd").change(function () {
                self.breed($("#breedToAdd option:selected").text());
            });
            $("#breedToAdd").select2({
                ajax: {
                    url: "/api/v1/breeds",
                    dataType: 'json',
                    delay: 250,
                    data: function (query) {
                        var search = "";
                        if (query.term)
                            search = "q=" + query.term;
                        if (query.page) {
                            if (search.length > 0)
                                search = search + "&";
                            search = search + "skip=" + (query.page - 1) * 5 + "&take=5";
                        }
                        return search;
                    },
                    processResults: function (data, params) {
                        var results = [{
                                id: "",
                                text: "Search for this dog's breed"
                            }];
                        if (data && data.data) {
                            for (var i = 0; i < data.data.length; i++) {
                                results.push({
                                    id: data.data[i].id,
                                    text: data.data[i].name
                                });
                            }
                        }
                        return {
                            results: results
                        };
                    },
                    cache: true
                },
                minimumInputLength: 0
            });
            $("#ownerToAdd").select2({
                ajax: {
                    url: "/api/v1/users",
                    dataType: 'json',
                    delay: 250,
                    data: function (query) {
                        var search = "";
                        if (query.term)
                            search = "q=" + query.term;
                        if (query.page) {
                            if (search.length > 0)
                                search = search + "&";
                            search = search + "skip=" + (query.page - 1) * 5 + "&take=5";
                        }
                        return search;
                    },
                    processResults: function (data, params) {
                        var results = [{
                                id: "",
                                text: "Search for a user to assign this dog to"
                            }];
                        if (data && data.data) {
                            for (var i = 0; i < data.data.length; i++) {
                                results.push({
                                    id: data.data[i].id,
                                    text: data.data[i].name ? data.data[i].name + " (" + data.data[i].email + ")" : data.data[i].email
                                });
                            }
                        }
                        return {
                            results: results
                        };
                    },
                    cache: true
                },
                minimumInputLength: 0
            });
            $("#save-button").click(function () {
                $('#save-button').attr("disabled", "disabled");
                self.isLoading(true);
                $("[data-error]").hide();
                var dogBirthday = null;
                if (self.day() && self.month() && self.year())
                    dogBirthday = moment(self.day() + "/" + self.month() + "/" + self.year(), "DD/MM/YY").format("YYYY/MM/DD");
                if (dogBirthday == 'Invalid date')
                    dogBirthday = null;
                DogService.New()
                    .Create({
                    name: self.name(),
                    breed: self.breed(),
                    size: self.size(),
                    specialRequirements: self.specialRequirements(),
                    birthday: dogBirthday,
                    isFriendsDog: self.isFriendsDog(),
                    userId: self.userId()
                }, function (result, error) {
                    $('#save-button').removeAttr("disabled");
                    self.isLoading(false);
                    if (result) {
                        window.location.pathname = "/admin/dogs/details/" + result.id;
                    }
                    else if (error && error.errors) {
                        for (var i = 0, len = error.errors.length; i < len; i++) {
                            $('[data-error="' + error.errors[i].key + '"]').text(error.errors[i].error);
                            $('[data-error="' + error.errors[i].key + '"]').show();
                        }
                    }
                    else {
                        $('[data-error="General"]').text("Woops something went wrong");
                        $('[data-error="General"]').show();
                    }
                });
                return false;
            });
            return self;
        };
        return DogAdd;
    }());
    Admin.DogAdd = DogAdd;
})(Admin || (Admin = {}));
//# sourceMappingURL=Admin.DogAdd.js.map;
var Admin;
(function (Admin) {
    var DogDetails = /** @class */ (function () {
        function DogDetails() {
            this.result = ko.observable();
            this.bagTotal = ko.observable();
            this.itemsSentTotal = ko.observable();
            this.ratingTotal = ko.observable();
            this.isLoading = ko.observable(false);
        }
        DogDetails.prototype.createModel = function () {
            var self = this;
            self.isLoading(true);
            DogService.New().GetDetail($("#id").val(), function (result, error) {
                if (result) {
                    self.result(result);
                    self.isLoading(false);
                    $("#delete-button").click(function () {
                        self.isLoading(true);
                        DogService.New().Delete($("#id").val(), function (result) {
                            self.isLoading(false);
                            if (result) {
                                window.location.pathname = "/admin/dogs";
                            }
                            else {
                                $('[data-error="General"]').text("Woops something went wrong");
                                $('[data-error="General"]').show();
                            }
                        });
                        return false;
                    });
                }
                else {
                    $('[data-error="General"]').text("Woops something went wrong");
                    $('[data-error="General"]').show();
                }
            });
            BagService.New()
                .With("dogId", $("#id").val())
                .Get(0, 0, function (result) {
                if (result)
                    self.bagTotal(result.total);
            });
            FeedbackService.New()
                .With("status", "active")
                .With("dogId", $("#id").val())
                .With("itemsSentTotal", "True").Get(0, 0, function (result) {
                if (result)
                    self.itemsSentTotal(result.total);
            });
            FeedbackService.New()
                .With("status", "active")
                .With("dogId", $("#id").val())
                .With("hasFeedback", "True").Get(0, 0, function (result) {
                if (result)
                    self.ratingTotal(result.total);
            });
            return self;
        };
        return DogDetails;
    }());
    Admin.DogDetails = DogDetails;
})(Admin || (Admin = {}));
//# sourceMappingURL=Admin.DogDetails.js.map;
var Admin;
(function (Admin) {
    var DogEdit = /** @class */ (function () {
        function DogEdit() {
            this.isLoading = ko.observable(false);
            this.name = ko.observable();
            this.userId = ko.observable();
            this.breed = ko.observable();
            this.day = ko.observable();
            this.month = ko.observable();
            this.year = ko.observable();
            this.size = ko.observable();
            this.specialRequirements = ko.observable();
            this.isFriendsDog = ko.observable();
        }
        DogEdit.prototype.createModel = function () {
            var self = this;
            DogService.New().GetDetail($("#id").val(), function (result) {
                self.name(result.name);
                self.userId(result.userId);
                self.breed(result.breed);
                self.size(result.size);
                self.specialRequirements(result.specialRequirements);
                self.isFriendsDog(result.isFriendsDog + "");
                if (result.birthday) {
                    self.day(moment.utc(result.birthday).format('DD'));
                    self.month(moment.utc(result.birthday).format('MM'));
                    self.year(moment.utc(result.birthday).format('YY'));
                }
                if (result.userId) {
                    $("#ownerToAdd")
                        .append('<option selected value="' + result.user.id + '">' + (result.user.name ? result.user.name + " (" + result.user.email + ")" : result.user.email) + '</option>')
                        .val(result.user.id)
                        .trigger("change");
                }
                if (result.breedId) {
                    $("#breedToAdd")
                        .append('<option selected value="' + result.breedId + '">' + result.breed + '</option>')
                        .val(result.breedId)
                        .trigger("change");
                }
                $("#ownerToAdd").change(function () {
                    self.userId($("#ownerToAdd").val());
                });
                $("#breedToAdd").change(function () {
                    self.breed($("#breedToAdd option:selected").text());
                });
                $("#breedToAdd").select2({
                    ajax: {
                        url: "/api/v1/breeds",
                        dataType: 'json',
                        delay: 250,
                        data: function (query) {
                            var search = "";
                            if (query.term)
                                search = "q=" + query.term;
                            if (query.page) {
                                if (search.length > 0)
                                    search = search + "&";
                                search = search + "skip=" + (query.page - 1) * 5 + "&take=5";
                            }
                            return search;
                        },
                        processResults: function (data, params) {
                            var results = [{
                                    id: "",
                                    text: "Search for this dog's breed"
                                }];
                            if (data && data.data) {
                                for (var i = 0; i < data.data.length; i++) {
                                    results.push({
                                        id: data.data[i].id,
                                        text: data.data[i].name
                                    });
                                }
                            }
                            return {
                                results: results
                            };
                        },
                        cache: true
                    },
                    minimumInputLength: 0
                });
                $("#ownerToAdd").select2({
                    ajax: {
                        url: "/api/v1/users",
                        dataType: 'json',
                        delay: 250,
                        data: function (query) {
                            var search = "";
                            if (query.term)
                                search = "q=" + query.term;
                            if (query.page) {
                                if (search.length > 0)
                                    search = search + "&";
                                search = search + "skip=" + (query.page - 1) * 5 + "&take=5";
                            }
                            return search;
                        },
                        processResults: function (data, params) {
                            var results = [{
                                    id: "",
                                    text: "Search for a user to assign this dog to"
                                }];
                            if (data && data.data) {
                                for (var i = 0; i < data.data.length; i++) {
                                    results.push({
                                        id: data.data[i].id,
                                        text: data.data[i].name ? data.data[i].name + " (" + data.data[i].email + ")" : data.data[i].email
                                    });
                                }
                            }
                            return {
                                results: results
                            };
                        },
                        cache: true
                    },
                    minimumInputLength: 0
                });
                $("#save-button").click(function () {
                    $('#save-button').attr("disabled", "disabled");
                    self.isLoading(true);
                    $("[data-error]").hide();
                    var dogBirthday = null;
                    if (self.day() && self.month() && self.year())
                        dogBirthday = moment(self.day() + "/" + self.month() + "/" + self.year(), "DD/MM/YY").format("YYYY/MM/DD");
                    if (dogBirthday == 'Invalid date')
                        dogBirthday = null;
                    DogService.New().Update($("#id").val(), {
                        name: self.name(),
                        breed: self.breed(),
                        size: self.size(),
                        specialRequirements: self.specialRequirements(),
                        birthday: dogBirthday,
                        isFriendsDog: self.isFriendsDog(),
                        userId: self.userId()
                    }, function (result, error) {
                        $('#save-button').removeAttr("disabled");
                        self.isLoading(false);
                        if (result) {
                            window.location.pathname = "/admin/dogs/details/" + $("#id").val();
                        }
                        else if (error && error.errors) {
                            for (var i = 0, len = error.errors.length; i < len; i++) {
                                $('[data-error="' + error.errors[i].key + '"]').text(error.errors[i].error);
                                $('[data-error="' + error.errors[i].key + '"]').show();
                            }
                        }
                        else {
                            $('[data-error="General"]').text("Woops something went wrong");
                            $('[data-error="General"]').show();
                        }
                    });
                    return false;
                });
                return self;
            });
        };
        return DogEdit;
    }());
    Admin.DogEdit = DogEdit;
})(Admin || (Admin = {}));
//# sourceMappingURL=Admin.DogEdit.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var Admin;
(function (Admin) {
    var DogIndex = /** @class */ (function (_super) {
        __extends(DogIndex, _super);
        function DogIndex() {
            var _this = _super !== null && _super.apply(this, arguments) || this;
            _this.dogReportFilter = ko.observable(StorageService.Get(_this.key("dogReportFilter")));
            _this.dogSizeFilter = ko.observable(StorageService.Get(_this.key("dogSizeFilter")));
            _this.dogOwnershipFilter = ko.observable(StorageService.Get(_this.key("dogOwnershipFilter")));
            return _this;
        }
        DogIndex.prototype.key = function (key) {
            return "dog-v2-" + key;
        };
        DogIndex.prototype.createModel = function () {
            var self = this;
            var canRun = true;
            if (!self.sort()) {
                self.sort("Name");
                self.sortDirection(Constants.SORT_ASC);
            }
            ko.computed(function () {
                var dogReportFilter = self.dogReportFilter();
                if (dogReportFilter)
                    StorageService.Store(self.key("dogReportFilter"), dogReportFilter);
                else
                    StorageService.Clear(self.key("dogReportFilter"));
                var dogSizeFilter = self.dogSizeFilter();
                if (dogSizeFilter)
                    StorageService.Store(self.key("dogSizeFilter"), dogSizeFilter);
                else
                    StorageService.Clear(self.key("dogSizeFilter"));
                var dogOwnershipFilter = self.dogOwnershipFilter();
                if (dogOwnershipFilter)
                    StorageService.Store(self.key("dogOwnershipFilter"), dogOwnershipFilter);
                else
                    StorageService.Clear(self.key("dogOwnershipFilter"));
            });
            ko.computed(function () {
                var page = self.page();
                var pageSize = self.pageSize();
                var search = self.search();
                var dir = self.sortDirection();
                var sort = self.sort();
                var dogReportFilter = self.dogReportFilter();
                var dogOwnershipFilter = self.dogOwnershipFilter();
                var dogSizeFilter = self.dogSizeFilter();
                if (canRun) {
                    canRun = false;
                    if (self.state() == Constants.STATE_READY)
                        self.state(Constants.STATE_BUSY);
                    var service = DogService.New()
                        .With("status", "active")
                        .With("direction", dir)
                        .With("sort", sort)
                        .With("q", search);
                    if (dogSizeFilter) {
                        service = service.With("size", dogSizeFilter);
                    }
                    if (dogOwnershipFilter) {
                        if (dogOwnershipFilter == "friend") {
                            service = service.With("ownDogs", false);
                        }
                        else {
                            service = service.With("ownDogs", true);
                        }
                    }
                    if (dogReportFilter) {
                        service = service.With("report", dogReportFilter);
                    }
                    service.Get((page - 1) * pageSize, pageSize, function (result) {
                        self.state(Constants.STATE_READY);
                        self.total(result.total);
                        self.data.removeAll();
                        for (var i = 0; i < result.data.length; i++) {
                            self.data.push(result.data[i]);
                        }
                        canRun = true;
                    });
                }
            });
            $("#clearFilter").click(function () {
                if (canRun) {
                    return false;
                }
            });
            return self;
        };
        return DogIndex;
    }(BindableIndexModel));
    Admin.DogIndex = DogIndex;
})(Admin || (Admin = {}));
//# sourceMappingURL=Admin.DogIndex.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var Admin;
(function (Admin) {
    var FeedbackIndex = /** @class */ (function (_super) {
        __extends(FeedbackIndex, _super);
        function FeedbackIndex() {
            var _this = _super !== null && _super.apply(this, arguments) || this;
            _this.filter = ko.observable($("#vId").val());
            _this.feedbackFilter = ko.observable(StorageService.Get(_this.key("feedbackFilter")));
            _this.attributeFilter = ko.observable(StorageService.Get(_this.key("attributeFilter")));
            return _this;
        }
        FeedbackIndex.prototype.key = function (key) {
            return "feedbackindex-v2-" + key;
        };
        FeedbackIndex.prototype.createModel = function () {
            var self = this;
            var canRun = true;
            if (!self.sort()) {
                self.sort("Name");
                self.sortDirection(Constants.SORT_ASC);
            }
            ko.computed(function () {
                var feedbackFilter = self.feedbackFilter();
                if (feedbackFilter)
                    StorageService.Store(self.key("feedbackFilter"), feedbackFilter);
                else
                    StorageService.Clear(self.key("feedbackFilter"));
                var attributeFilter = self.attributeFilter();
                if (attributeFilter)
                    StorageService.Store(self.key("attributeFilter"), feedbackFilter);
                else
                    StorageService.Clear(self.key("attributeFilter"));
            });
            ko.computed(function () {
                var page = self.page();
                var pageSize = self.pageSize();
                var search = self.search();
                var dir = self.sortDirection();
                var sort = self.sort();
                var filter = self.filter();
                var feedbackFilter = self.feedbackFilter();
                var attributeFilter = self.attributeFilter();
                if (canRun) {
                    canRun = false;
                    if (self.state() == Constants.STATE_READY)
                        self.state(Constants.STATE_BUSY);
                    var service = FeedbackService.New()
                        .With("status", "active")
                        .With("direction", dir)
                        .With("sort", sort)
                        .With("q", search);
                    if (filter) {
                        if ($("#type").val() == "productVariant") {
                            service = service.With("productVariantId", filter);
                        }
                        else if ($("#type").val() == "product") {
                            service = service.With("productId", filter);
                        }
                        else if ($("#type").val() == "user") {
                            service = service.With("userId", filter);
                        }
                        else if ($("#type").val() == "dog") {
                            service = service.With("dogId", filter);
                        }
                    }
                    if (feedbackFilter) {
                        service = service.With("hasFeedback", "True");
                        if (feedbackFilter == "positive")
                            service = service.With("rating", "1");
                        if (feedbackFilter == "neutral")
                            service = service.With("rating", "0");
                        if (feedbackFilter == "negative")
                            service = service.With("rating", "-1");
                    }
                    if (attributeFilter)
                        service = service.With("attributeId", attributeFilter);
                    service.Get((page - 1) * pageSize, pageSize, function (result) {
                        self.state(Constants.STATE_READY);
                        self.total(result.total);
                        self.data.removeAll();
                        for (var i = 0; i < result.data.length; i++) {
                            self.data.push(result.data[i]);
                        }
                        canRun = true;
                    });
                }
            });
            return self;
        };
        return FeedbackIndex;
    }(BindableIndexModel));
    Admin.FeedbackIndex = FeedbackIndex;
})(Admin || (Admin = {}));
//# sourceMappingURL=Admin.FeedbackIndex.js.map;
var Admin;
(function (Admin) {
    var NavModel = /** @class */ (function () {
        function NavModel() {
        }
        NavModel.prototype.createModel = function () {
            var self = this;
            $(".trigger-navgroup a.sidebar-nav-menu").each(function (i, e) {
                var key = "navtab-" + $(e).data("navgroup");
                if (StorageService.Get(key) == "true") {
                    $(e).addClass("open");
                }
            });
            $(".trigger-navgroup a.sidebar-nav-menu").click(function (eArgs) {
                $(":data(navgroup)").each(function (i, e) {
                    var key = "navtab-" + $(e).data("navgroup");
                    if ($(eArgs.currentTarget).data("navgroup") == $(e).data("navgroup")) {
                        if ($(e).hasClass("open")) {
                            StorageService.Store(key, "false");
                        }
                        else {
                            StorageService.Store(key, "true");
                        }
                    }
                    else {
                        StorageService.Store(key, "false");
                    }
                });
            });
            return self;
        };
        return NavModel;
    }());
    Admin.NavModel = NavModel;
})(Admin || (Admin = {}));
//# sourceMappingURL=Admin.NavModel.js.map;
var Admin;
(function (Admin) {
    var OrderDetails = /** @class */ (function () {
        function OrderDetails() {
            this.result = ko.observable();
            this.dogs = ko.observableArray();
            this.recentOrders = ko.observableArray();
            this.address = ko.observable();
            this.notes = ko.observableArray();
            this.userNotes = ko.observableArray();
            this.isLoading = ko.observable(false);
            this.refresh = ko.observable();
        }
        OrderDetails.prototype.createModel = function () {
            var self = this;
            self.isLoading(true);
            ko.computed(function () {
                self.refresh();
                DogService.New()
                    .With("OrderId", $("#id").val())
                    .GetAll(function (result) {
                    if (result) {
                        (_a = self.dogs).push.apply(_a, result.data);
                    }
                    var _a;
                });
                OrderService.New().GetDetail($("#id").val(), function (result, error) {
                    if (result) {
                        self.result(result);
                        self.isLoading(false);
                        AddressService.New().GetDetail(result.addressId, function (addressResult) {
                            if (addressResult)
                                self.address(addressResult);
                        });
                        OrderService.New()
                            .With("UserId", result.userId)
                            .Get(0, 5, function (recentOrdersResult) {
                            if (recentOrdersResult)
                                self.recentOrders(recentOrdersResult.data);
                        });
                        NoteService.New()
                            .With("orderId", result.id)
                            .With("type", "order")
                            .GetAll(function (result) {
                            self.notes.removeAll();
                            for (var i = 0; i < result.data.length; i++)
                                self.notes.push(result.data[i]);
                        });
                        NoteService.New()
                            .With("userId", result.userId)
                            .With("type", "user")
                            .GetAll(function (result) {
                            self.userNotes.removeAll();
                            for (var i = 0; i < result.data.length; i++)
                                self.userNotes.push(result.data[i]);
                        });
                    }
                    else {
                        $('[data-error="General"]').text("Woops something went wrong");
                        $('[data-error="General"]').show();
                    }
                });
            });
            self.total = ko.computed(function () {
                var total = 0;
                if (self.result() && self.result().orderLineItems) {
                    for (var i = 0; i < self.result().orderLineItems.length; i++)
                        total = total + self.result().orderLineItems[i].total;
                }
                return total;
            });
            self.addNote = function (d, e) {
                var l = Ladda.create($(e.currentTarget)[0]);
                l.start();
                NoteService.New()
                    .Create({
                    userId: self.result().userId,
                    orderId: self.result().id,
                    message: $("#addNote").val()
                }, function () {
                    l.stop();
                    $("#addNote").val('');
                    self.refresh.valueHasMutated();
                });
            };
            self.fulfill = function (d, e) {
                console.log(d);
                console.log(e);
                var l = Ladda.create($(e.currentTarget)[0]);
                l.start();
                OrderLineService.New()
                    .UpdateSingle(d.id, "fulfilled", (new Date().toISOString()), function () {
                    l.stop();
                    self.refresh.valueHasMutated();
                });
            };
            self.addUserNote = function (d, e) {
                var l = Ladda.create($(e.currentTarget)[0]);
                l.start();
                NoteService.New()
                    .Create({
                    userId: self.result().userId,
                    message: $("#addUserNote").val()
                }, function () {
                    l.stop();
                    $("#addUserNote").val('');
                    self.refresh.valueHasMutated();
                });
            };
            self.showShippingBox = ko.computed(function () {
                if (self.result() && self.result().orderLineItems) {
                    for (var i = 0; i < self.result().orderLineItems.length; i++) {
                        if (self.result().orderLineItems[i].requiresShipping && self.result().orderLineItems[i].fulfilled != null && self.result().orderLineItems[i].shipmentId == null) {
                            console.log("true");
                            return true;
                        }
                    }
                }
                return false;
            });
            self.createShipment = function (d, e) {
                var l = Ladda.create($(e.currentTarget)[0]);
                l.start();
                AddressService.New()
                    .GetShippingRates(self.result().addressId, Utilities.CalculateWeightOfOrder(self.result()), function (result) {
                    alertify
                        .confirm("Which courier?", function () {
                        var quote = $("input[name='shipping']:checked").val();
                        var shimpmentProvider = $("input[name='shipping']:checked").parent().data("provider");
                        ShipmentService.New()
                            .Create({
                            pickupLocation: "home",
                            provider: "tbc",
                            addressId: self.result().addressId,
                            weight: Utilities.CalculateWeightOfOrder(self.result())
                        }, function (createShipmentResult) {
                            if (createShipmentResult) {
                                var promises = new Array();
                                _(self.result().orderLineItems).each(function (ol) {
                                    if (ol.requiresShipping && ol.fulfilled != null && ol.shipmentId == null) {
                                        var promise = $.Deferred();
                                        OrderLineService.New()
                                            .UpdateSingle(ol.id, "shipmentId", createShipmentResult.id, function () {
                                            promise.resolve();
                                        });
                                        promises.push(promise);
                                    }
                                });
                                $.when.apply($, promises).then(function () {
                                    ShipmentService.New()
                                        .Update(createShipmentResult.id, {
                                        provider: shimpmentProvider,
                                        deliveryReference: quote,
                                        weight: Utilities.CalculateWeightOfOrder(self.result()),
                                        pickupLocation: "home"
                                    }, function () {
                                        alertify.success("Shipment created");
                                        self.refresh.valueHasMutated();
                                    });
                                });
                            }
                            else {
                                alertify.error("Error creating shipment");
                                l.stop();
                            }
                        });
                    });
                    var htmlText = '<div class="form-group" style="text-align: left;">';
                    if (result.data.length > 0) {
                        _.each(result.data, function (rateOption) {
                            htmlText += '<label class="radio" data-provider="' + rateOption.provider + '" for="' + rateOption.quoteId + '"><input style="width: initial; position: relative; margin: 0;" type="radio" id="' + rateOption.quoteId + '" name="shipping" value="' + rateOption.quoteId + '" /> ' + rateOption.carrierName + ' (' + rateOption.deliveryType + '): $' + rateOption.cost + '</label>';
                            htmlText += "<p>" + rateOption.serviceStandard + (rateOption.isRuralDelivery ? " (RD)" : "") + "</p>";
                        });
                    }
                    else {
                        htmlText += '<p>No courier is available for that address</p>';
                    }
                    htmlText += '</div>';
                    $(htmlText).insertAfter(".alertify .msg");
                    l.stop();
                });
                return false;
            };
            return self;
        };
        return OrderDetails;
    }());
    Admin.OrderDetails = OrderDetails;
})(Admin || (Admin = {}));
//# sourceMappingURL=Admin.OrderDetails.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var Admin;
(function (Admin) {
    var OrderIndex = /** @class */ (function (_super) {
        __extends(OrderIndex, _super);
        function OrderIndex() {
            return _super !== null && _super.apply(this, arguments) || this;
        }
        OrderIndex.prototype.key = function (key) {
            return "order-v2-" + key;
        };
        OrderIndex.prototype.createModel = function () {
            var self = this;
            if (!self.sort()) {
                self.sort("Name");
                self.sortDirection(Constants.SORT_ASC);
            }
            self.writeOff = function (order) {
                if (order.invoiceId) {
                    self.state(Constants.STATE_BUSY);
                    InvoiceService.New()
                        .UpdateSingle(order.invoiceId, "writtenOff", "True", function () {
                        self.state(Constants.STATE_READY);
                        self.sort.valueHasMutated();
                    });
                }
                return false;
            };
            self.markAsPaid = function (order) {
                if (order.invoiceId) {
                    self.state(Constants.STATE_BUSY);
                    InvoiceService.New()
                        .UpdateSingle(order.invoiceId, "fullyPaid", "True", function () {
                        self.state(Constants.STATE_READY);
                        self.sort.valueHasMutated();
                    });
                }
                return false;
            };
            self.confirmPayment = function (order) {
                self.state(Constants.STATE_BUSY);
                OrderService.New()
                    .Action(order.id, "confirm-payment", null, function () {
                    self.state(Constants.STATE_READY);
                    self.sort.valueHasMutated();
                });
                return false;
            };
            self.fulfilOrder = function (order) {
                self.state(Constants.STATE_BUSY);
                var promises = new Array();
                _(order.orderLineItems).each(function (e) {
                    if (e.fulfilled == null) {
                        var promise = $.Deferred();
                        OrderLineService.New()
                            .UpdateSingle(e.id, "fulfilled", (new Date().toISOString()), function () {
                            promise.resolve();
                        });
                        promises.push(promise);
                    }
                });
                $.when.apply($, promises).then(function () {
                    self.state(Constants.STATE_READY);
                    self.sort.valueHasMutated();
                });
                return false;
            };
            self.voidPayment = function (order) {
                alertify
                    .confirm("Are you sure you want to void this order?", function () {
                    self.state(Constants.STATE_BUSY);
                    OrderService.New()
                        .Action(order.id, "void-payment", null, function () {
                        self.state(Constants.STATE_READY);
                        self.sort.valueHasMutated();
                    });
                });
                return false;
            };
            self.createShipment = function (order) {
                self.state(Constants.STATE_BUSY);
                AddressService.New()
                    .GetShippingRates(order.addressId, Utilities.CalculateWeightOfOrder(order), function (result) {
                    alertify
                        .confirm("Which courier?", function () {
                        var quote = $("input[name='shipping']:checked").val();
                        var shimpmentProvider = $("input[name='shipping']:checked").parent().data("provider");
                        ShipmentService.New()
                            .Create({
                            pickupLocation: "home",
                            provider: "tbc",
                            addressId: order.addressId,
                            weight: Utilities.CalculateWeightOfOrder(order)
                        }, function (createShipmentResult) {
                            if (createShipmentResult) {
                                var promises = new Array();
                                _(order.orderLineItems).each(function (ol) {
                                    if (ol.requiresShipping && ol.fulfilled != null && ol.shipmentId == null) {
                                        var promise = $.Deferred();
                                        OrderLineService.New()
                                            .UpdateSingle(ol.id, "shipmentId", createShipmentResult.id, function () {
                                            promise.resolve();
                                        });
                                        promises.push(promise);
                                    }
                                });
                                $.when.apply($, promises).then(function () {
                                    ShipmentService.New()
                                        .Update(createShipmentResult.id, {
                                        provider: shimpmentProvider,
                                        deliveryReference: quote,
                                        weight: Utilities.CalculateWeightOfOrder(order),
                                        pickupLocation: "home"
                                    }, function () {
                                        alertify.success("Shipment created");
                                        self.sort.valueHasMutated();
                                    });
                                });
                            }
                            else {
                                alertify.error("Error creating shipment");
                                self.state(Constants.STATE_READY);
                            }
                        });
                    });
                    var htmlText = '<div class="form-group" style="text-align: left;">';
                    if (result.data.length > 0) {
                        _.each(result.data, function (rateOption) {
                            htmlText += '<label class="radio" data-provider="' + rateOption.provider + '" for="' + rateOption.quoteId + '"><input style="width: initial; position: relative; margin: 0;" type="radio" id="' + rateOption.quoteId + '" name="shipping" value="' + rateOption.quoteId + '" /> ' + rateOption.carrierName + ' (' + rateOption.deliveryType + '): $' + rateOption.cost + '</label>';
                            htmlText += "<p>" + rateOption.serviceStandard + (rateOption.isRuralDelivery ? " (RD)" : "") + "</p>";
                        });
                    }
                    else {
                        htmlText += '<p>No courier is available for that address</p>';
                    }
                    htmlText += '</div>';
                    $(htmlText).insertAfter(".alertify .msg");
                    self.state(Constants.STATE_READY);
                });
            };
            self.createManualShipment = function (order) {
                self.state(Constants.STATE_BUSY);
                ShipmentService.New()
                    .Create({
                    pickupLocation: "home",
                    provider: "manual",
                    addressId: order.addressId,
                    weight: Utilities.CalculateWeightOfOrder(order)
                }, function (createShipmentResult) {
                    if (createShipmentResult) {
                        var promises = new Array();
                        _(order.orderLineItems).each(function (ol) {
                            if (ol.requiresShipping && ol.fulfilled != null && ol.shipmentId == null) {
                                var promise = $.Deferred();
                                OrderLineService.New()
                                    .UpdateSingle(ol.id, "shipmentId", createShipmentResult.id, function () {
                                    promise.resolve();
                                });
                                promises.push(promise);
                            }
                        });
                        $.when.apply($, promises).then(function () {
                            self.state(Constants.STATE_READY);
                            alertify.success("Shipment created");
                            self.sort.valueHasMutated();
                        });
                    }
                    else {
                        alertify.error("Error creating shipment");
                        self.state(Constants.STATE_READY);
                    }
                });
            };
            self.markAsPickedUp = function (order) {
                self.state(Constants.STATE_BUSY);
                OrderService.New()
                    .Action(order.id, "mark-as-pickedup", null, function () {
                    self.state(Constants.STATE_READY);
                    self.sort.valueHasMutated();
                });
            };
            ko.computed(function () {
                var page = self.page();
                var pageSize = self.pageSize();
                var search = self.search();
                var dir = self.sortDirection();
                var sort = self.sort();
                var queryFilters = self.queryFilters();
                self.state(Constants.STATE_BUSY);
                var service = OrderService.New()
                    .With("status", "active")
                    .With("direction", dir)
                    .With("sort", sort)
                    .With("q", search);
                if (queryFilters) {
                    _(queryFilters).each(function (item) {
                        service = service.With(item.key, item.value);
                    });
                }
                service.Get((page - 1) * pageSize, pageSize, function (result) {
                    self.state(Constants.STATE_READY);
                    self.total(result.total);
                    self.data.removeAll();
                    for (var i = 0; i < result.data.length; i++) {
                        self.data.push(result.data[i]);
                    }
                });
            });
            $("#clearFilter").click(function () {
                return false;
            });
            return self;
        };
        return OrderIndex;
    }(BindableIndexModel));
    Admin.OrderIndex = OrderIndex;
})(Admin || (Admin = {}));
//# sourceMappingURL=Admin.OrderIndex.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var Admin;
(function (Admin) {
    var PlanIndex = /** @class */ (function (_super) {
        __extends(PlanIndex, _super);
        function PlanIndex() {
            var _this = _super !== null && _super.apply(this, arguments) || this;
            _this.productIdFilter = ko.observable(StorageService.Get(_this.key("productIdFilter")));
            _this.productVariantIdFilter = ko.observable(Utilities.GetUrlParam("productVariantId", document.location));
            _this.reportFilter = ko.observable(StorageService.Get(_this.key("reportFilter")));
            _this.frequencyFilter = ko.observable(StorageService.Get(_this.key("frequencyFilter")));
            _this.products = ko.observableArray();
            return _this;
        }
        PlanIndex.prototype.key = function (key) {
            return "plan-v2-" + key;
        };
        PlanIndex.prototype.createModel = function () {
            var self = this;
            var canRun = true;
            if (!self.sort()) {
                self.sort("Name");
                self.sortDirection(Constants.SORT_ASC);
            }
            ko.computed(function () {
                var reportFilter = self.reportFilter();
                if (reportFilter)
                    StorageService.Store(self.key("reportFilter"), reportFilter);
                else
                    StorageService.Clear(self.key("reportFilter"));
            });
            ProductService.New()
                .With("canBeSubscription", true)
                .GetAll(function (result) {
                self.products.removeAll();
                for (var i = 0; i < result.data.length; i++)
                    self.products.push(result.data[i]);
            });
            if (Utilities.GetUrlParam("productId", document.location))
                self.productIdFilter(Utilities.GetUrlParam("productId", document.location));
            ko.computed(function () {
                var productIdFilter = self.productIdFilter();
                if (productIdFilter)
                    StorageService.Store(self.key("productIdFilter"), productIdFilter);
                else
                    StorageService.Clear(self.key("productIdFilter"));
            });
            self.processPlan = function (data, event) {
                var l = Ladda.create($(event.currentTarget).parent().parent().parent().children("a")[0]);
                l.start();
                $(event.currentTarget).parent().parent().parent().removeClass("open");
                var id = $(event.currentTarget).data("id");
                JobService.New()
                    .Create({
                    jobType: "process-plan",
                    message: id
                }, function () {
                    l.stop();
                });
                return true;
            };
            ko.computed(function () {
                var page = self.page();
                var pageSize = self.pageSize();
                var search = self.search();
                var dir = self.sortDirection();
                var sort = self.sort();
                var productIdFilter = self.productIdFilter();
                var productVariantIdFilter = self.productVariantIdFilter();
                var report = self.reportFilter();
                var frequency = self.frequencyFilter();
                if (canRun) {
                    canRun = false;
                    if (self.state() == Constants.STATE_READY)
                        self.state(Constants.STATE_BUSY);
                    var service = PlanService.New()
                        .With("status", "active")
                        .With("direction", dir)
                        .With("sort", sort)
                        .With("q", search);
                    if (productIdFilter)
                        service = service.With("productId", productIdFilter);
                    if (productVariantIdFilter)
                        service = service.With("productVariantId", productVariantIdFilter);
                    if (report) {
                        if (report == "active") {
                            service = service.With("isPaused", false);
                            service = service.With("isCancelled", false);
                        }
                        else if (report == "paused") {
                            service = service.With("isPaused", true);
                        }
                        else if (report == "cancelled") {
                            service = service.With("isCancelled", true);
                        }
                        else {
                            service = service.With("isRenewingThisMonth", true);
                        }
                    }
                    if (frequency) {
                        service = service.With("frequency", frequency);
                    }
                    service.Get((page - 1) * pageSize, pageSize, function (result) {
                        self.state(Constants.STATE_READY);
                        self.total(result.total);
                        self.data.removeAll();
                        for (var i = 0; i < result.data.length; i++) {
                            self.data.push(result.data[i]);
                        }
                        canRun = true;
                    });
                }
            });
            ko.computed(function () {
                if (self.productIdFilter()) {
                    ProductService.New()
                        .GetDetail(self.productIdFilter(), function (result) {
                        if (result) {
                            self.filteredTo("the product " + result.title);
                        }
                    });
                }
                if (self.productVariantIdFilter()) {
                    ProductVariantService.New()
                        .GetDetail(self.productVariantIdFilter(), function (result) {
                        if (result) {
                            self.filteredTo("the product variant " + result.title);
                        }
                    });
                }
                if (self.productIdFilter() == null && self.productVariantIdFilter() == null)
                    self.filteredTo(null);
            });
            $("#clearFilter").click(function () {
                if (canRun) {
                    self.productIdFilter(null);
                    self.productVariantIdFilter(null);
                    return false;
                }
            });
            return self;
        };
        return PlanIndex;
    }(BindableIndexModel));
    Admin.PlanIndex = PlanIndex;
})(Admin || (Admin = {}));
//# sourceMappingURL=Admin.PlanIndex.js.map;
var Admin;
(function (Admin) {
    var ProductAdd = /** @class */ (function () {
        function ProductAdd() {
            this.isLoading = ko.observable(false);
            this.name = ko.observable();
            this.description = ko.observable();
            this.barcode = ko.observable();
            this.grams = ko.observable();
            this.inventoryPolicy = ko.observable();
            this.price = ko.observable();
            this.shipsOnSpecificDay = ko.observable();
            this.shippingUnits = ko.observable(1);
            this.isSubscription = ko.observable();
            this.requiredDogInfo = ko.observable();
        }
        ProductAdd.prototype.createModel = function () {
            var self = this;
            $("#add-brand").click(function () {
                alertify
                    .confirm("Add a brand", function () {
                    if ($("#brandname").val()) {
                        BrandService.New()
                            .Create({
                            name: $("#brandname").val(),
                            location: $("#brandlocation").val()
                        }, function (result) {
                            if (result) {
                                console.log(result);
                                var s2 = $("#brandToAdd").data('select2');
                                s2.trigger('select', {
                                    data: {
                                        id: result.id,
                                        text: result.name
                                    }
                                });
                                alertify.success("Brand added");
                            }
                            else {
                                alertify.error("Unable to add brand");
                            }
                        });
                    }
                    else {
                        alertify.error("Brand name required");
                    }
                });
                var htmlText = '<div class="row" style="text-align: left;">';
                htmlText += '<div class="col-md-12"><div class="form-group"> <label for="street">Name*</label><input class="form-control" id="brandname" value="" placeholder="Bark Bag" /></div></div>';
                htmlText += '</div>';
                htmlText += '<div class="row" style="text-align: left;">';
                htmlText += '<div class="col-md-12"><div class="form-group"><label for="location">Location</label><input class="form-control" id="brandlocation" value="" placeholder="New Zealand" /></div></div>';
                htmlText += '</div>';
                $(htmlText).insertAfter(".alertify .msg");
                return false;
            });
            $("#brandToAdd").select2({
                ajax: {
                    url: "/api/v1/brands",
                    dataType: 'json',
                    delay: 250,
                    data: function (query) {
                        var search = "";
                        if (query.term)
                            search = "q=" + query.term;
                        if (query.page) {
                            if (search.length > 0)
                                search = search + "&";
                            search = search + "skip=" + (query.page - 1) * 5 + "&take=5";
                        }
                        return search;
                    },
                    processResults: function (data, params) {
                        var results = [{
                                id: "",
                                text: "Search for brand that this variant is to be added under"
                            }];
                        if (data && data.data) {
                            for (var i = 0; i < data.data.length; i++) {
                                results.push({
                                    id: data.data[i].id,
                                    text: data.data[i].name
                                });
                            }
                        }
                        return {
                            results: results
                        };
                    },
                    cache: true
                },
                minimumInputLength: 0
            });
            $("#attributesToAdd").select2({
                ajax: {
                    url: "/api/v1/attributes",
                    dataType: 'json',
                    delay: 250,
                    data: function (query) {
                        var search = "";
                        if (query.term)
                            search = "q=" + query.term;
                        if (query.page) {
                            if (search.length > 0)
                                search = search + "&";
                            search = search + "skip=" + (query.page - 1) * 5 + "&take=5";
                        }
                        return search;
                    },
                    processResults: function (data, params) {
                        var results = [{
                                id: "",
                                text: "Search for an attribute for this variant"
                            }];
                        if (data && data.data) {
                            for (var i = 0; i < data.data.length; i++) {
                                results.push({
                                    id: data.data[i].id,
                                    text: data.data[i].name
                                });
                            }
                        }
                        return {
                            results: results
                        };
                    },
                    cache: true
                },
                minimumInputLength: 0
            });
            $("#save-button").click(function () {
                $('#save-button').attr("disabled", "disabled");
                self.isLoading(true);
                $("[data-error]").hide();
                ProductService.New().Create({
                    brandId: $("#brandToAdd").val(),
                    title: self.name(),
                    description: self.description(),
                    attributes: $("#attributesToAdd").val(),
                    type: 'product'
                }, function (result, error) {
                    $('#save-button').removeAttr("disabled");
                    self.isLoading(false);
                    if (result) {
                        //Create product variant
                        ProductVariantService.New().Create({
                            productId: result.id,
                            title: self.name(),
                            barcode: self.barcode(),
                            grams: self.grams(),
                            inventoryPolicy: self.inventoryPolicy(),
                            position: 0,
                            price: self.price(),
                            description: self.description(),
                            shippingUnits: self.shippingUnits(),
                            shipsOnSpecificDay: self.shipsOnSpecificDay(),
                            isSubscription: self.isSubscription(),
                            isAvailable: true,
                            requiresDogInfo: self.requiredDogInfo(),
                            attributes: $("#attributesToAdd").val()
                        }, function (pvResult, error) {
                            window.location.pathname = "/admin/products/details/" + result.id;
                        });
                    }
                    else if (error && error.errors) {
                        for (var i = 0, len = error.errors.length; i < len; i++) {
                            $('[data-error="' + error.errors[i].key + '"]').text(error.errors[i].error);
                            $('[data-error="' + error.errors[i].key + '"]').show();
                        }
                    }
                    else {
                        $('[data-error="General"]').text("Woops something went wrong");
                        $('[data-error="General"]').show();
                    }
                });
                return false;
            });
            return self;
        };
        return ProductAdd;
    }());
    Admin.ProductAdd = ProductAdd;
})(Admin || (Admin = {}));
//# sourceMappingURL=Admin.ProductAdd.js.map;
var Admin;
(function (Admin) {
    var ProductDetails = /** @class */ (function () {
        function ProductDetails() {
            this.result = ko.observable();
            this.isLoading = ko.observable(false);
            this.bagTotal = ko.observable();
            this.userTotal = ko.observable();
            this.dogTotal = ko.observable();
            this.productVariantTotal = ko.observable();
        }
        ProductDetails.prototype.createModel = function () {
            var self = this;
            self.isLoading(true);
            ProductService.New().GetDetail($("#id").val(), function (result, error) {
                if (result) {
                    self.result(result);
                    self.isLoading(false);
                    setTimeout(function () {
                        $("#editable-title").editable({
                            pk: 1,
                            mode: "inline",
                            type: 'text',
                            success: function (response, newValue) {
                                ProductService.New().UpdateSingle($("#id").val(), "title", newValue);
                            }
                        }).on('shown', function (e, editable) {
                            editable.input.$input.val($(e.currentTarget).text().trim());
                        });
                    }, 10);
                    setTimeout(function () {
                        $("#editable-description").editable({
                            pk: 1,
                            mode: "inline",
                            type: 'text',
                            success: function (response, newValue) {
                                ProductService.New().UpdateSingle($("#id").val(), "description", newValue);
                            },
                            emptytext: 'No description'
                        }).on('shown', function (e, editable) {
                            editable.input.$input.val($(e.currentTarget).text().trim());
                        });
                        $("#delete-button").click(function () {
                            self.isLoading(true);
                            //TODO: CONFIRM DELETE
                            ProductService.New().Delete($("#id").val(), function (result) {
                                self.isLoading(false);
                                if (result) {
                                    window.location.pathname = "/admin/products";
                                }
                                else {
                                    $('[data-error="General"]').text("Woops something went wrong");
                                    $('[data-error="General"]').show();
                                }
                            });
                            return false;
                        });
                    }, 10);
                }
                else {
                    $('[data-error="General"]').text("Woops something went wrong");
                    $('[data-error="General"]').show();
                }
            });
            BagService.New()
                .With("productId", $("#id").val())
                .Get(0, 0, function (result) {
                if (result)
                    self.bagTotal(result.total);
            });
            UserService.New()
                .With("productId", $("#id").val())
                .Get(0, 0, function (result) {
                if (result)
                    self.userTotal(result.total);
            });
            DogService.New()
                .With("productId", $("#id").val())
                .Get(0, 0, function (result) {
                if (result)
                    self.dogTotal(result.total);
            });
            ProductVariantService.New()
                .With("productId", $("#id").val())
                .Get(0, 0, function (result) {
                if (result)
                    self.productVariantTotal(result.total);
            });
            return self;
        };
        return ProductDetails;
    }());
    Admin.ProductDetails = ProductDetails;
})(Admin || (Admin = {}));
//# sourceMappingURL=Admin.ProductDetails.js.map;
var Admin;
(function (Admin) {
    var ProductEdit = /** @class */ (function () {
        function ProductEdit() {
            this.isLoading = ko.observable(false);
            this.name = ko.observable();
            this.description = ko.observable();
        }
        ProductEdit.prototype.createModel = function () {
            var self = this;
            ProductService.New().GetDetail($("#id").val(), function (result) {
                self.name(result.title);
                self.description(result.description);
                if (result.attributes) {
                    for (var i = 0; i < result.attributes.length; i++) {
                        $("#attributesToAdd")
                            .append('<option selected value="' + result.attributes[i].id + '">' + result.attributes[i].name + '</option>')
                            .trigger("change");
                    }
                }
                $("#brandToAdd")
                    .append('<option selected value="' + result.brand.id + '">' + result.brand.name + '</option>')
                    .val(result.brand.id)
                    .trigger("change");
                $("#brandToAdd").select2({
                    ajax: {
                        url: "/api/v1/brands",
                        dataType: 'json',
                        delay: 250,
                        data: function (query) {
                            var search = "";
                            if (query.term)
                                search = "q=" + query.term;
                            if (query.page) {
                                if (search.length > 0)
                                    search = search + "&";
                                search = search + "skip=" + (query.page - 1) * 5 + "&take=5";
                            }
                            return search;
                        },
                        processResults: function (data, params) {
                            var results = [{
                                    id: "",
                                    text: "Search for brand that this variant is to be added under"
                                }];
                            if (data && data.data) {
                                for (var i = 0; i < data.data.length; i++) {
                                    results.push({
                                        id: data.data[i].id,
                                        text: data.data[i].name
                                    });
                                }
                            }
                            return {
                                results: results
                            };
                        },
                        cache: true
                    },
                    minimumInputLength: 0
                });
                $("#attributesToAdd").select2({
                    ajax: {
                        url: "/api/v1/attributes",
                        dataType: 'json',
                        delay: 250,
                        data: function (query) {
                            var search = "";
                            if (query.term)
                                search = "q=" + query.term;
                            if (query.page) {
                                if (search.length > 0)
                                    search = search + "&";
                                search = search + "skip=" + (query.page - 1) * 5 + "&take=5";
                            }
                            return search;
                        },
                        processResults: function (data, params) {
                            var results = [{
                                    id: "",
                                    text: "Search for an attribute for this variant"
                                }];
                            if (data && data.data) {
                                for (var i = 0; i < data.data.length; i++) {
                                    results.push({
                                        id: data.data[i].id,
                                        text: data.data[i].name
                                    });
                                }
                            }
                            return {
                                results: results
                            };
                        },
                        cache: true
                    },
                    minimumInputLength: 0
                });
            });
            $("#save-button").click(function () {
                $('#save-button').attr("disabled", "disabled");
                self.isLoading(true);
                $("[data-error]").hide();
                ProductService.New().Update($("#id").val(), {
                    brandId: $("#brandToAdd").val(),
                    title: self.name(),
                    description: self.description(),
                    attributes: $("#attributesToAdd").val(),
                    type: 'product'
                }, function (result, error) {
                    $('#save-button').removeAttr("disabled");
                    self.isLoading(false);
                    if (result) {
                        window.location.pathname = "/admin/products/details/" + $("#id").val();
                    }
                    else if (error && error.errors) {
                        for (var i = 0, len = error.errors.length; i < len; i++) {
                            $('[data-error="' + error.errors[i].key + '"]').text(error.errors[i].error);
                            $('[data-error="' + error.errors[i].key + '"]').show();
                        }
                    }
                    else {
                        $('[data-error="General"]').text("Woops something went wrong");
                        $('[data-error="General"]').show();
                    }
                });
                return false;
            });
            return self;
        };
        return ProductEdit;
    }());
    Admin.ProductEdit = ProductEdit;
})(Admin || (Admin = {}));
//# sourceMappingURL=Admin.ProductEdit.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var Admin;
(function (Admin) {
    var ProductIndex = /** @class */ (function (_super) {
        __extends(ProductIndex, _super);
        function ProductIndex() {
            var _this = _super !== null && _super.apply(this, arguments) || this;
            _this.supplierIdFilter = ko.observable(Utilities.GetUrlParam("supplierId", document.location));
            _this.brandIdFilter = ko.observable(Utilities.GetUrlParam("brandId", document.location));
            _this.productTypeFilter = ko.observable(StorageService.Get(_this.key("productTypeFilter")));
            return _this;
        }
        ProductIndex.prototype.key = function (key) {
            return "product-v2-" + key;
        };
        ProductIndex.prototype.createModel = function () {
            var self = this;
            var canRun = true;
            if (!self.sort()) {
                self.sort("Name");
                self.sortDirection(Constants.SORT_ASC);
            }
            ko.computed(function () {
                var productTypeFilter = self.productTypeFilter();
                if (productTypeFilter)
                    StorageService.Store(self.key("productTypeFilter"), productTypeFilter);
                else
                    StorageService.Clear(self.key("productTypeFilter"));
            });
            ko.computed(function () {
                var page = self.page();
                var pageSize = self.pageSize();
                var search = self.search();
                var dir = self.sortDirection();
                var sort = self.sort();
                var brandIdFilter = self.brandIdFilter();
                var supplierIdFilter = self.supplierIdFilter();
                var productTypeFilter = self.productTypeFilter();
                if (canRun) {
                    canRun = false;
                    if (self.state() == Constants.STATE_READY)
                        self.state(Constants.STATE_BUSY);
                    var service = ProductService.New()
                        .With("status", "active")
                        .With("direction", dir)
                        .With("sort", sort)
                        .With("q", search);
                    if (brandIdFilter)
                        service = service.With("brandId", brandIdFilter);
                    if (supplierIdFilter)
                        service = service.With("supplierId", supplierIdFilter);
                    if (productTypeFilter)
                        service = service.With("type", productTypeFilter);
                    service.Get((page - 1) * pageSize, pageSize, function (result) {
                        self.state(Constants.STATE_READY);
                        self.total(result.total);
                        self.data.removeAll();
                        for (var i = 0; i < result.data.length; i++) {
                            self.data.push(result.data[i]);
                        }
                        canRun = true;
                    });
                }
            });
            ko.computed(function () {
                if (self.supplierIdFilter()) {
                    SupplierService.New()
                        .GetDetail(self.supplierIdFilter(), function (result) {
                        if (result) {
                            self.filteredTo("the supplier " + result.name);
                        }
                    });
                }
                if (self.brandIdFilter()) {
                    BrandService.New()
                        .GetDetail(self.brandIdFilter(), function (result) {
                        if (result) {
                            self.filteredTo("the brand " + result.name);
                        }
                    });
                }
                if (self.supplierIdFilter() == null && self.brandIdFilter() == null)
                    self.filteredTo(null);
            });
            $("#clearFilter").click(function () {
                if (canRun) {
                    self.supplierIdFilter(null);
                    self.brandIdFilter(null);
                    return false;
                }
            });
            return self;
        };
        return ProductIndex;
    }(BindableIndexModel));
    Admin.ProductIndex = ProductIndex;
})(Admin || (Admin = {}));
//# sourceMappingURL=Admin.ProductIndex.js.map;
var Admin;
(function (Admin) {
    var ProductVariantAdd = /** @class */ (function () {
        function ProductVariantAdd() {
            this.isLoading = ko.observable(false);
            this.name = ko.observable();
            this.barcode = ko.observable();
            this.grams = ko.observable();
            this.inventoryPolicy = ko.observable();
            this.price = ko.observable();
            this.description = ko.observable();
            this.shipsOnSpecificDay = ko.observable();
            this.shippingUnits = ko.observable(1);
            this.isSubscription = ko.observable();
            this.requiredDogInfo = ko.observable();
        }
        ProductVariantAdd.prototype.createModel = function () {
            var self = this;
            if ($("#productId").val()) {
            }
            else {
                $("#productToAdd").select2({
                    ajax: {
                        url: "/api/v1/products",
                        dataType: 'json',
                        delay: 250,
                        data: function (query) {
                            var search = "";
                            if (query.term)
                                search = "q=" + query.term;
                            if (query.page) {
                                if (search.length > 0)
                                    search = search + "&";
                                search = search + "skip=" + (query.page - 1) * 5 + "&take=5";
                            }
                            return search;
                        },
                        processResults: function (data, params) {
                            var results = [{
                                    id: "",
                                    text: "Search for product that this variant is to be added under"
                                }];
                            if (data && data.data) {
                                for (var i = 0; i < data.data.length; i++) {
                                    results.push({
                                        id: data.data[i].id,
                                        text: data.data[i].title
                                    });
                                }
                            }
                            return {
                                results: results
                            };
                        },
                        cache: true
                    },
                    minimumInputLength: 0
                });
            }
            $("#attributesToAdd").select2({
                ajax: {
                    url: "/api/v1/attributes",
                    dataType: 'json',
                    delay: 250,
                    data: function (query) {
                        var search = "";
                        if (query.term)
                            search = "q=" + query.term;
                        if (query.page) {
                            if (search.length > 0)
                                search = search + "&";
                            search = search + "skip=" + (query.page - 1) * 5 + "&take=5";
                        }
                        return search;
                    },
                    processResults: function (data, params) {
                        var results = [{
                                id: "",
                                text: "Search for an attribute for this variant"
                            }];
                        if (data && data.data) {
                            for (var i = 0; i < data.data.length; i++) {
                                results.push({
                                    id: data.data[i].id,
                                    text: data.data[i].name
                                });
                            }
                        }
                        return {
                            results: results
                        };
                    },
                    cache: true
                },
                minimumInputLength: 0
            });
            $("#save-button").click(function () {
                $('#save-button').attr("disabled", "disabled");
                self.isLoading(true);
                $("[data-error]").hide();
                ProductVariantService.New().Create({
                    productId: $("#productId").val() ? $("#productId").val() : $("#productToAdd").val(),
                    title: self.name(),
                    barcode: self.barcode(),
                    grams: self.grams(),
                    inventoryPolicy: self.inventoryPolicy(),
                    position: 0,
                    price: self.price(),
                    description: self.description(),
                    shippingUnits: self.shippingUnits(),
                    shipsOnSpecificDay: self.shipsOnSpecificDay(),
                    isSubscription: self.isSubscription(),
                    isAvailable: true,
                    requiresDogInfo: self.requiredDogInfo(),
                    attributes: $("#attributesToAdd").val()
                }, function (result, error) {
                    $('#save-button').removeAttr("disabled");
                    self.isLoading(false);
                    if (result) {
                        window.location.pathname = "/admin/products/details/" + result.productId;
                    }
                    else if (error && error.errors) {
                        for (var i = 0, len = error.errors.length; i < len; i++) {
                            $('[data-error="' + error.errors[i].key + '"]').text(error.errors[i].error);
                            $('[data-error="' + error.errors[i].key + '"]').show();
                        }
                    }
                    else {
                        $('[data-error="General"]').text("Woops something went wrong");
                        $('[data-error="General"]').show();
                    }
                });
                return false;
            });
            return self;
        };
        return ProductVariantAdd;
    }());
    Admin.ProductVariantAdd = ProductVariantAdd;
})(Admin || (Admin = {}));
//# sourceMappingURL=Admin.ProductVariantAdd.js.map;
var Admin;
(function (Admin) {
    var ProductVariantDetails = /** @class */ (function () {
        function ProductVariantDetails() {
            this.result = ko.observable();
            this.isLoading = ko.observable(false);
            this.bagTotal = ko.observable();
            this.userTotal = ko.observable();
            this.dogTotal = ko.observable();
        }
        ProductVariantDetails.prototype.createModel = function () {
            var self = this;
            self.isLoading(true);
            ProductVariantService.New().GetDetail($("#id").val(), function (result, error) {
                if (result) {
                    self.result(result);
                    self.isLoading(false);
                    setTimeout(function () {
                        $("#delete-button").click(function () {
                            self.isLoading(true);
                            //TODO: CONFIRM
                            ProductVariantService.New().Delete($("#id").val(), function (result) {
                                self.isLoading(false);
                                if (result) {
                                    window.location.pathname = "/admin/products/" + self.result().id;
                                }
                                else {
                                    $('[data-error="General"]').text("Woops something went wrong");
                                    $('[data-error="General"]').show();
                                }
                            });
                            return false;
                        });
                    }, 10);
                }
                else {
                    $('[data-error="General"]').text("Woops something went wrong");
                    $('[data-error="General"]').show();
                }
            });
            BagService.New()
                .With("productVariantId", $("#id").val())
                .Get(0, 0, function (result) {
                if (result)
                    self.bagTotal(result.total);
            });
            UserService.New()
                .With("productVariantId", $("#id").val())
                .Get(0, 0, function (result) {
                if (result)
                    self.userTotal(result.total);
            });
            DogService.New()
                .With("productVariantId", $("#id").val())
                .Get(0, 0, function (result) {
                if (result)
                    self.dogTotal(result.total);
            });
            return self;
        };
        return ProductVariantDetails;
    }());
    Admin.ProductVariantDetails = ProductVariantDetails;
})(Admin || (Admin = {}));
//# sourceMappingURL=Admin.ProductVariantDetails.js.map;
var Admin;
(function (Admin) {
    var ProductVariantEdit = /** @class */ (function () {
        function ProductVariantEdit() {
            this.isLoading = ko.observable(false);
            this.name = ko.observable();
            this.barcode = ko.observable();
            this.grams = ko.observable();
            this.inventoryPolicy = ko.observable();
            this.price = ko.observable();
            this.description = ko.observable();
            this.shipsOnSpecificDay = ko.observable();
            this.shippingUnits = ko.observable(1);
            this.isSubscription = ko.observable();
            this.requiredDogInfo = ko.observable();
            this.productId = ko.observable();
        }
        ProductVariantEdit.prototype.createModel = function () {
            var self = this;
            ProductVariantService.New().GetDetail($("#id").val(), function (result) {
                self.name(result.title);
                self.barcode(result.barcode);
                self.grams(result.grams);
                self.inventoryPolicy(result.inventoryPolicy);
                self.price(result.price);
                self.description(result.description);
                self.shipsOnSpecificDay(result.shipsOnSpecificDay);
                self.shippingUnits(result.shippingUnits);
                self.isSubscription(result.isSubscription);
                self.requiredDogInfo(result.requiresDogInfo);
                self.productId(result.productId);
                if (result.attributes) {
                    for (var i = 0; i < result.attributes.length; i++) {
                        $("#attributesToAdd")
                            .append('<option selected value="' + result.attributes[i].id + '">' + result.attributes[i].name + '</option>')
                            .trigger("change");
                    }
                }
                $("#attributesToAdd").select2({
                    ajax: {
                        url: "/api/v1/attributes",
                        dataType: 'json',
                        delay: 250,
                        data: function (query) {
                            var search = "";
                            if (query.term)
                                search = "q=" + query.term;
                            if (query.page) {
                                if (search.length > 0)
                                    search = search + "&";
                                search = search + "skip=" + (query.page - 1) * 5 + "&take=5";
                            }
                            return search;
                        },
                        processResults: function (data, params) {
                            var results = [{
                                    id: "",
                                    text: "Search for an attribute for this variant"
                                }];
                            if (data && data.data) {
                                for (var i = 0; i < data.data.length; i++) {
                                    results.push({
                                        id: data.data[i].id,
                                        text: data.data[i].name
                                    });
                                }
                            }
                            return {
                                results: results
                            };
                        },
                        cache: true
                    },
                    minimumInputLength: 0
                });
            });
            $("#save-button").click(function () {
                $('#save-button').attr("disabled", "disabled");
                self.isLoading(true);
                $("[data-error]").hide();
                ProductVariantService.New().Update($("#id").val(), {
                    title: self.name(),
                    barcode: self.barcode(),
                    grams: self.grams(),
                    inventoryPolicy: self.inventoryPolicy(),
                    position: 0,
                    price: self.price(),
                    description: self.description(),
                    shippingUnits: self.shippingUnits(),
                    shipsOnSpecificDay: self.shipsOnSpecificDay(),
                    isSubscription: self.isSubscription(),
                    isAvailable: true,
                    requiresDogInfo: self.requiredDogInfo(),
                    attributes: $("#attributesToAdd").val()
                }, function (result, error) {
                    $('#save-button').removeAttr("disabled");
                    self.isLoading(false);
                    if (result) {
                        window.location.pathname = "/admin/products/details/" + self.productId();
                    }
                    else if (error && error.errors) {
                        for (var i = 0, len = error.errors.length; i < len; i++) {
                            $('[data-error="' + error.errors[i].key + '"]').text(error.errors[i].error);
                            $('[data-error="' + error.errors[i].key + '"]').show();
                        }
                    }
                    else {
                        $('[data-error="General"]').text("Woops something went wrong");
                        $('[data-error="General"]').show();
                    }
                });
                return false;
            });
            return self;
        };
        return ProductVariantEdit;
    }());
    Admin.ProductVariantEdit = ProductVariantEdit;
})(Admin || (Admin = {}));
//# sourceMappingURL=Admin.ProductVariantEdit.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var Admin;
(function (Admin) {
    var ProductVariantIndex = /** @class */ (function (_super) {
        __extends(ProductVariantIndex, _super);
        function ProductVariantIndex() {
            var _this = _super !== null && _super.apply(this, arguments) || this;
            _this.supplierIdFilter = ko.observable(Utilities.GetUrlParam("supplierId", document.location));
            _this.brandIdFilter = ko.observable(Utilities.GetUrlParam("brandId", document.location));
            _this.productIdFilter = ko.observable(Utilities.GetUrlParam("productId", document.location));
            _this.productTypeFilter = ko.observable(StorageService.Get(_this.key("productTypeFilter")));
            _this.hasStock = ko.observable(StorageService.Get(_this.key("hasStock")));
            _this.hasAvailable = ko.observable(StorageService.Get(_this.key("hasAvailable")));
            return _this;
        }
        ProductVariantIndex.prototype.key = function (key) {
            return "productvariant-v2-" + key;
        };
        ProductVariantIndex.prototype.createModel = function () {
            var self = this;
            var canRun = true;
            console.log($("#vId").val());
            if ($("#vId").val()) {
                self.productIdFilter($("#vId").val());
            }
            if (!self.sort()) {
                self.sort("Name");
                self.sortDirection(Constants.SORT_ASC);
            }
            ko.computed(function () {
                var productTypeFilter = self.productTypeFilter();
                if (productTypeFilter)
                    StorageService.Store(self.key("productTypeFilter"), productTypeFilter);
                else
                    StorageService.Clear(self.key("productTypeFilter"));
                var hasAvailable = self.hasAvailable();
                if (hasAvailable)
                    StorageService.Store(self.key("hasAvailable"), hasAvailable);
                else
                    StorageService.Clear(self.key("hasAvailable"));
                var hasStock = self.hasStock();
                if (hasStock)
                    StorageService.Store(self.key("hasStock"), hasStock);
                else
                    StorageService.Clear(self.key("hasStock"));
            });
            ko.computed(function () {
                var page = self.page();
                var pageSize = self.pageSize();
                var search = self.search();
                var dir = self.sortDirection();
                var sort = self.sort();
                var brandIdFilter = self.brandIdFilter();
                var supplierIdFilter = self.supplierIdFilter();
                var productIdFilter = self.productIdFilter();
                var hasAvailable = self.hasAvailable();
                var productTypeFilter = self.productTypeFilter();
                var hasStock = self.hasStock();
                if (canRun) {
                    canRun = false;
                    if (self.state() == Constants.STATE_READY)
                        self.state(Constants.STATE_BUSY);
                    var service = ProductVariantService.New()
                        .With("status", "active")
                        .With("direction", dir)
                        .With("sort", sort)
                        .With("q", search);
                    if (brandIdFilter)
                        service = service.With("brandId", brandIdFilter);
                    if (productIdFilter)
                        service = service.With("productId", productIdFilter);
                    if (hasAvailable)
                        service = service.With("hasAvailable", hasAvailable);
                    if (hasStock)
                        service = service.With("hasStock", hasStock);
                    if (productTypeFilter) {
                        if (productTypeFilter == "subscription")
                            service = service.With("isSubscription", true);
                        if (productTypeFilter == "barkbag")
                            service = service.With("isBarkBag", true);
                        if (productTypeFilter == "external")
                            service = service.With("isBarkBag", false);
                    }
                    service.Get((page - 1) * pageSize, pageSize, function (result) {
                        self.state(Constants.STATE_READY);
                        self.total(result.total);
                        self.data.removeAll();
                        for (var i = 0; i < result.data.length; i++) {
                            self.data.push(result.data[i]);
                        }
                        canRun = true;
                    });
                }
            });
            ko.computed(function () {
                if (self.supplierIdFilter()) {
                    SupplierService.New()
                        .GetDetail(self.supplierIdFilter(), function (result) {
                        if (result) {
                            self.filteredTo("the supplier " + result.name);
                        }
                    });
                }
                if (self.productIdFilter()) {
                    ProductService.New()
                        .GetDetail(self.productIdFilter(), function (result) {
                        if (result) {
                            self.filteredTo("the product " + result.title);
                        }
                    });
                }
                if (self.brandIdFilter()) {
                    BrandService.New()
                        .GetDetail(self.brandIdFilter(), function (result) {
                        if (result) {
                            self.filteredTo("the brand " + result.name);
                        }
                    });
                }
                if (self.supplierIdFilter() == null && self.brandIdFilter() == null && self.productIdFilter() == null)
                    self.filteredTo(null);
            });
            $("#clearFilter").click(function () {
                if (canRun) {
                    self.supplierIdFilter(null);
                    self.brandIdFilter(null);
                    self.productIdFilter(null);
                    return false;
                }
            });
            return self;
        };
        return ProductVariantIndex;
    }(BindableIndexModel));
    Admin.ProductVariantIndex = ProductVariantIndex;
})(Admin || (Admin = {}));
//# sourceMappingURL=Admin.ProductVariantIndex.js.map;
var Admin;
(function (Admin) {
    var PromoCodeAdd = /** @class */ (function () {
        function PromoCodeAdd() {
            this.code = ko.observable();
            this.description = ko.observable();
            this.type = ko.observable();
            this.value = ko.observable();
            this.startsAt = ko.observable();
            this.endsAt = ko.observable();
            this.minimumOrderAmount = ko.observable();
            this.maxValue = ko.observable();
            this.remaining = ko.observable();
            this.isSystemGenerated = ko.observable();
            this.perCustomerLimit = ko.observable();
            this.notes = ko.observable();
            this.isLoading = ko.observable(false);
        }
        PromoCodeAdd.prototype.createModel = function () {
            var self = this;
            $("#save-button").click(function () {
                $('#save-button').attr("disabled", "disabled");
                self.isLoading(true);
                $("[data-error]").hide();
                PromoCodeDefinitionService.New().Create({
                    code: self.code(),
                    description: self.description(),
                    appliedQuantity: 1,
                    value: self.value(),
                    startsAt: $("#startsAt").val().length > 0 ? moment($("#startsAt").val(), "DD/MM/YY").toISOString() : null,
                    endsAt: $("#endsAt").val().length > 0 ? moment($("#endsAt").val(), "DD/MM/YY").toISOString() : null,
                    minimumOrderAmount: self.minimumOrderAmount(),
                    remaining: self.remaining(),
                    type: self.type(),
                    maxValue: self.maxValue(),
                    isSystemGenerated: self.isSystemGenerated(),
                    notes: self.notes(),
                    perCustomerLimit: self.perCustomerLimit()
                }, function (result, error) {
                    $('#save-button').removeAttr("disabled");
                    self.isLoading(false);
                    if (result) {
                        window.location.pathname = "/admin/promo-codes/details/" + result.id;
                    }
                    else if (error && error.errors) {
                        for (var i = 0, len = error.errors.length; i < len; i++) {
                            $('[data-error="' + error.errors[i].key + '"]').text(error.errors[i].error);
                            $('[data-error="' + error.errors[i].key + '"]').show();
                        }
                    }
                    else {
                        $('[data-error="General"]').text("Woops something went wrong");
                        $('[data-error="General"]').show();
                    }
                });
                return false;
            });
            return self;
        };
        return PromoCodeAdd;
    }());
    Admin.PromoCodeAdd = PromoCodeAdd;
})(Admin || (Admin = {}));
//# sourceMappingURL=Admin.PromoCodeAdd.js.map;
var Admin;
(function (Admin) {
    var PromoCodeDetails = /** @class */ (function () {
        function PromoCodeDetails() {
            this.result = ko.observable();
            this.isLoading = ko.observable(false);
            this.userTotal = ko.observable();
            this.planTotal = ko.observable();
            this.orderTotal = ko.observable();
            this.cartTotal = ko.observable();
        }
        PromoCodeDetails.prototype.createModel = function () {
            var self = this;
            self.isLoading(true);
            PromoCodeDefinitionService.New().GetDetail($("#id").val(), function (result, error) {
                self.isLoading(false);
                if (result) {
                    self.result(result);
                    $("#delete-button").click(function () {
                        self.isLoading(true);
                        PromoCodeDefinitionService.New().Delete($("#id").val(), function (result) {
                            self.isLoading(false);
                            if (result) {
                                window.location.pathname = "/admin/promo-codes";
                            }
                            else {
                                $('[data-error="General"]').text("Woops something went wrong");
                                $('[data-error="General"]').show();
                            }
                        });
                        return false;
                    });
                }
                else {
                    $('[data-error="General"]').text("Woops something went wrong");
                    $('[data-error="General"]').show();
                }
            });
            UserService.New()
                .With("promoCodeDefinitionId", $("#id").val())
                .Get(0, 0, function (result) {
                if (result)
                    self.userTotal(result.total);
            });
            PlanService.New()
                .With("promoCodeDefinitionId", $("#id").val())
                .Get(0, 0, function (result) {
                if (result)
                    self.planTotal(result.total);
            });
            OrderService.New()
                .With("promoCodeDefinitionId", $("#id").val())
                .Get(0, 0, function (result) {
                if (result)
                    self.orderTotal(result.total);
            });
            CartService.New()
                .With("promoCodeDefinitionId", $("#id").val())
                .Get(0, 0, function (result) {
                if (result)
                    self.cartTotal(result.total);
            });
            return self;
        };
        return PromoCodeDetails;
    }());
    Admin.PromoCodeDetails = PromoCodeDetails;
})(Admin || (Admin = {}));
//# sourceMappingURL=Admin.PromoCodeDetails.js.map;
var Admin;
(function (Admin) {
    var PromoCodeEdit = /** @class */ (function () {
        function PromoCodeEdit() {
            this.code = ko.observable();
            this.description = ko.observable();
            this.type = ko.observable();
            this.value = ko.observable();
            this.startsAt = ko.observable();
            this.endsAt = ko.observable();
            this.minimumOrderAmount = ko.observable();
            this.maxValue = ko.observable();
            this.remaining = ko.observable();
            this.isSystemGenerated = ko.observable();
            this.perCustomerLimit = ko.observable();
            this.notes = ko.observable();
            this.isLoading = ko.observable(false);
        }
        PromoCodeEdit.prototype.createModel = function () {
            var self = this;
            self.isLoading(true);
            PromoCodeDefinitionService.New().GetDetail($("#id").val(), function (result, error) {
                self.isLoading(false);
                if (result) {
                    self.code(result.code);
                    self.description(result.description);
                    self.type(result.type);
                    self.minimumOrderAmount(result.minimumOrderAmount);
                    self.remaining(result.remaining);
                    self.value(result.value);
                    self.maxValue(result.maxValue);
                    self.isSystemGenerated(result.isSystemGenerated);
                    self.perCustomerLimit(result.perCustomerLimit);
                    self.notes(result.notes);
                    if (result.startsAt)
                        self.startsAt(moment.utc(result.startsAt).local().format("DD/MM/YY"));
                    if (result.endsAt)
                        self.endsAt(moment.utc(result.endsAt).local().format("DD/MM/YY"));
                }
                else {
                    $('[data-error="General"]').text("Woops something went wrong");
                    $('[data-error="General"]').show();
                }
            });
            $("#save-button").click(function () {
                $('#save-button').attr("disabled", "disabled");
                self.isLoading(true);
                $("[data-error]").hide();
                PromoCodeDefinitionService.New().Update($("#id").val(), {
                    code: self.code(),
                    description: self.description(),
                    appliedQuantity: 1,
                    value: self.value(),
                    startsAt: $("#startsAt").val().length > 0 ? moment($("#startsAt").val(), "DD/MM/YY").toISOString() : null,
                    endsAt: $("#endsAt").val().length > 0 ? moment($("#endsAt").val(), "DD/MM/YY").toISOString() : null,
                    minimumOrderAmount: self.minimumOrderAmount(),
                    remaining: self.remaining(),
                    type: self.type(),
                    maxValue: self.maxValue(),
                    isSystemGenerated: self.isSystemGenerated(),
                    notes: self.notes(),
                    perCustomerLimit: self.perCustomerLimit()
                }, function (result, error) {
                    $('#save-button').removeAttr("disabled");
                    self.isLoading(false);
                    if (result) {
                        window.location.pathname = "/admin/promo-codes/details/" + $("#id").val();
                    }
                    else if (error && error.errors) {
                        for (var i = 0, len = error.errors.length; i < len; i++) {
                            $('[data-error="' + error.errors[i].key + '"]').text(error.errors[i].error);
                            $('[data-error="' + error.errors[i].key + '"]').show();
                        }
                    }
                    else {
                        $('[data-error="General"]').text("Woops something went wrong");
                        $('[data-error="General"]').show();
                    }
                });
                return false;
            });
            return self;
        };
        return PromoCodeEdit;
    }());
    Admin.PromoCodeEdit = PromoCodeEdit;
})(Admin || (Admin = {}));
//# sourceMappingURL=Admin.PromoCodeEdit.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var Admin;
(function (Admin) {
    var PromoCodeIndex = /** @class */ (function (_super) {
        __extends(PromoCodeIndex, _super);
        function PromoCodeIndex() {
            var _this = _super !== null && _super.apply(this, arguments) || this;
            _this.expiryFilter = ko.observable(StorageService.Get(_this.key("expiryFilter")));
            _this.systemGenerated = ko.observable(StorageService.Get(_this.key("systemGenerated")));
            return _this;
        }
        PromoCodeIndex.prototype.key = function (key) {
            return "promoCodeDefinition-v2-" + key;
        };
        PromoCodeIndex.prototype.createModel = function () {
            var self = this;
            var canRun = true;
            ko.computed(function () {
                var expiryFilter = self.expiryFilter();
                if (expiryFilter) {
                    StorageService.Store(self.key("expiryFilter"), expiryFilter);
                }
                else {
                    StorageService.Clear(self.key("expiryFilter"));
                }
            });
            ko.computed(function () {
                var systemGenerated = self.systemGenerated();
                if (systemGenerated) {
                    StorageService.Store(self.key("systemGenerated"), systemGenerated);
                }
                else {
                    StorageService.Clear(self.key("systemGenerated"));
                }
            });
            if (!self.sort()) {
                self.sort("Name");
                self.sortDirection(Constants.SORT_ASC);
            }
            ko.computed(function () {
                var page = self.page();
                var pageSize = self.pageSize();
                var search = self.search();
                var dir = self.sortDirection();
                var sort = self.sort();
                var expiryFilter = self.expiryFilter();
                var systemGenerated = self.systemGenerated();
                if (canRun) {
                    canRun = false;
                    if (self.state() == Constants.STATE_READY)
                        self.state(Constants.STATE_BUSY);
                    var service = PromoCodeDefinitionService.New()
                        .With("status", "active")
                        .With("direction", dir)
                        .With("sort", sort)
                        .With("q", search);
                    if (expiryFilter) {
                        if (expiryFilter == "expired")
                            service = service.With("expired", true);
                        if (expiryFilter == "active")
                            service = service.With("expired", false).With("started", true).With("noneLeft", false);
                        if (expiryFilter == "upcoming")
                            service = service.With("started", false);
                    }
                    if (systemGenerated) {
                        service = service.With("systemGenerated", systemGenerated);
                    }
                    service.Get((page - 1) * pageSize, pageSize, function (result) {
                        self.state(Constants.STATE_READY);
                        self.total(result.total);
                        self.data.removeAll();
                        for (var i = 0; i < result.data.length; i++) {
                            self.data.push(result.data[i]);
                        }
                        canRun = true;
                    });
                }
            });
            return self;
        };
        return PromoCodeIndex;
    }(BindableIndexModel));
    Admin.PromoCodeIndex = PromoCodeIndex;
})(Admin || (Admin = {}));
//# sourceMappingURL=Admin.PromoCodeIndex.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var Admin;
(function (Admin) {
    var PromoCodeUsesIndex = /** @class */ (function (_super) {
        __extends(PromoCodeUsesIndex, _super);
        function PromoCodeUsesIndex() {
            return _super !== null && _super.apply(this, arguments) || this;
        }
        PromoCodeUsesIndex.prototype.key = function (key) {
            return "promocode-use-v2-" + key;
        };
        PromoCodeUsesIndex.prototype.createModel = function () {
            var self = this;
            var canRun = true;
            if (!self.sort()) {
                self.sort("Name");
                self.sortDirection(Constants.SORT_ASC);
            }
            ko.computed(function () {
                var page = self.page();
                var pageSize = self.pageSize();
                var search = self.search();
                var dir = self.sortDirection();
                var sort = self.sort();
                if (canRun) {
                    canRun = false;
                    if (self.state() == Constants.STATE_READY)
                        self.state(Constants.STATE_BUSY);
                    var service = PromoCodeService.New()
                        .With("status", "active")
                        .With("direction", dir)
                        .With("sort", sort)
                        .With("q", search)
                        .With("promocodeDefinitionId", $("#id").val());
                    service.Get((page - 1) * pageSize, pageSize, function (result) {
                        self.state(Constants.STATE_READY);
                        self.total(result.total);
                        self.data.removeAll();
                        for (var i = 0; i < result.data.length; i++) {
                            self.data.push(result.data[i]);
                        }
                        canRun = true;
                    });
                }
            });
            return self;
        };
        return PromoCodeUsesIndex;
    }(BindableIndexModel));
    Admin.PromoCodeUsesIndex = PromoCodeUsesIndex;
})(Admin || (Admin = {}));
//# sourceMappingURL=Admin.PromoCodeUsesIndex.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var Admin;
(function (Admin) {
    var ShipmentIndex = /** @class */ (function (_super) {
        __extends(ShipmentIndex, _super);
        function ShipmentIndex() {
            var _this = _super !== null && _super.apply(this, arguments) || this;
            _this.orderIdFilter = ko.observable(Utilities.GetUrlParam("orderId", document.location));
            _this.pickupFilter = ko.observable(StorageService.Get(_this.key("pickupFilter")));
            _this.shippingMethodFilter = ko.observable(StorageService.Get(_this.key("shippingMethodFilter")));
            _this.reportFilter = ko.observable(StorageService.Get(_this.key("reportFilter")));
            return _this;
        }
        ShipmentIndex.prototype.key = function (key) {
            return "shipment-v2-" + key;
        };
        ShipmentIndex.prototype.createModel = function () {
            var self = this;
            var canRun = true;
            if (!self.sort()) {
                self.sort("Name");
                self.sortDirection(Constants.SORT_ASC);
            }
            ko.computed(function () {
                var pickupFilter = self.pickupFilter();
                if (pickupFilter)
                    StorageService.Store(self.key("pickupFilter"), pickupFilter);
                else
                    StorageService.Clear(self.key("pickupFilter"));
                var shippingMethodFilter = self.shippingMethodFilter();
                if (shippingMethodFilter)
                    StorageService.Store(self.key("shippingMethodFilter"), shippingMethodFilter);
                else
                    StorageService.Clear(self.key("shippingMethodFilter"));
                var reportFilter = self.reportFilter();
                if (reportFilter)
                    StorageService.Store(self.key("reportFilter"), reportFilter);
                else
                    StorageService.Clear(self.key("reportFilter"));
            });
            ko.computed(function () {
                var page = self.page();
                var pageSize = self.pageSize();
                var search = self.search();
                var dir = self.sortDirection();
                var sort = self.sort();
                var pickupFilter = self.pickupFilter();
                var shippingMethodFilter = self.shippingMethodFilter();
                var reportFilter = self.reportFilter();
                var orderIdFilter = self.orderIdFilter();
                if (canRun) {
                    canRun = false;
                    if (self.state() == Constants.STATE_READY)
                        self.state(Constants.STATE_BUSY);
                    var service = ShipmentService.New()
                        .With("status", "active")
                        .With("direction", dir)
                        .With("sort", sort)
                        .With("q", search);
                    if (pickupFilter)
                        service = service.With("customerPickup", pickupFilter);
                    if (shippingMethodFilter)
                        service = service.With("shippingMethod", shippingMethodFilter);
                    if (reportFilter)
                        service = service.With("report", reportFilter);
                    if (orderIdFilter)
                        service = service.With("orderId", orderIdFilter);
                    service.Get((page - 1) * pageSize, pageSize, function (result) {
                        self.state(Constants.STATE_READY);
                        self.total(result.total);
                        self.data.removeAll();
                        for (var i = 0; i < result.data.length; i++) {
                            self.data.push(result.data[i]);
                        }
                        canRun = true;
                    });
                }
            });
            if (self.orderIdFilter()) {
                OrderService.New()
                    .GetDetail(self.orderIdFilter(), function (result) {
                    if (result) {
                        self.filteredTo("the order " + result.orderNumber);
                    }
                });
            }
            $("#clearFilter").click(function () {
                if (canRun) {
                    self.orderIdFilter(null);
                    return false;
                }
            });
            return self;
        };
        return ShipmentIndex;
    }(BindableIndexModel));
    Admin.ShipmentIndex = ShipmentIndex;
})(Admin || (Admin = {}));
//# sourceMappingURL=Admin.ShipmentIndex.js.map;
var Admin;
(function (Admin) {
    var StockAdd = /** @class */ (function () {
        function StockAdd() {
            this.isLoading = ko.observable(false);
            this.url = ko.observable();
        }
        StockAdd.prototype.createModel = function () {
            var self = this;
            $("#batchToAdd").select2({
                ajax: {
                    url: "/api/v1/batches",
                    dataType: 'json',
                    delay: 250,
                    data: function (query) {
                        var search = "?isAvailable=true";
                        if (query.term)
                            search = "&q=" + query.term;
                        if (query.page) {
                            if (search.length > 0)
                                search = search + "&";
                            search = search + "skip=" + (query.page - 1) * 5 + "&take=5";
                        }
                        return search;
                    },
                    processResults: function (data, params) {
                        var results = [{
                                id: "",
                                text: "Search for a batch"
                            }];
                        if (data && data.data) {
                            for (var i = 0; i < data.data.length; i++) {
                                results.push({
                                    id: data.data[i].id,
                                    text: data.data[i].name
                                });
                            }
                        }
                        return {
                            results: results
                        };
                    },
                    cache: true
                },
                minimumInputLength: 0,
                allowClear: true
            });
            $("#supplierToAdd").select2({
                ajax: {
                    url: "/api/v1/suppliers",
                    dataType: 'json',
                    delay: 250,
                    data: function (query) {
                        var search = "";
                        if (query.term)
                            search = "q=" + query.term;
                        if (query.page) {
                            if (search.length > 0)
                                search = search + "&";
                            search = search + "skip=" + (query.page - 1) * 5 + "&take=5";
                        }
                        return search;
                    },
                    processResults: function (data, params) {
                        var results = [{
                                id: "",
                                text: "Search for supplier to add"
                            }];
                        if (data && data.data) {
                            for (var i = 0; i < data.data.length; i++) {
                                results.push({
                                    id: data.data[i].id,
                                    text: data.data[i].name
                                });
                            }
                        }
                        return {
                            results: results
                        };
                    },
                    cache: true
                },
                minimumInputLength: 0
            });
            $("#productToAdd").select2({
                ajax: {
                    url: "/api/v1/productvariants",
                    dataType: 'json',
                    delay: 250,
                    data: function (query) {
                        var search = "";
                        if (query.term)
                            search = "q=" + query.term;
                        if (query.page) {
                            if (search.length > 0)
                                search = search + "&";
                            search = search + "skip=" + (query.page - 1) * 5 + "&take=5";
                        }
                        return search;
                    },
                    processResults: function (data, params) {
                        var results = [{
                                id: "",
                                text: "Search for supplier to add"
                            }];
                        if (data && data.data) {
                            for (var i = 0; i < data.data.length; i++) {
                                results.push({
                                    id: data.data[i].id,
                                    text: data.data[i].title
                                });
                            }
                        }
                        return {
                            results: results
                        };
                    },
                    cache: true
                },
                minimumInputLength: 0
            });
            $("#save-button").click(function () {
                $('#save-button').attr("disabled", "disabled");
                self.isLoading(true);
                $("[data-error]").hide();
                StockService.New().Create({
                    batchId: $("#batchToAdd").val(),
                    supplierId: $("#supplierToAdd").val(),
                    productVariantId: $("#productToAdd").val(),
                    quantity: parseInt($("#quantity").val()),
                    unitCost: parseFloat($("#unitCost").val()),
                    bestBefore: $("#bestBefore").val().length > 0 ? moment($("#bestBefore").val(), "DD/MM/YY").toISOString() : null
                }, function (result, error) {
                    $('#save-button').removeAttr("disabled");
                    self.isLoading(false);
                    if (result) {
                        window.location.pathname = "/admin/stock/details/" + result.id;
                    }
                    else if (error && error.errors) {
                        for (var i = 0, len = error.errors.length; i < len; i++) {
                            $('[data-error="' + error.errors[i].key + '"]').text(error.errors[i].error);
                            $('[data-error="' + error.errors[i].key + '"]').show();
                        }
                    }
                    else {
                        $('[data-error="General"]').text("Woops something went wrong");
                        $('[data-error="General"]').show();
                    }
                });
                return false;
            });
            return self;
        };
        return StockAdd;
    }());
    Admin.StockAdd = StockAdd;
})(Admin || (Admin = {}));
//# sourceMappingURL=Admin.StockAdd.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var Admin;
(function (Admin) {
    var StockBagIndex = /** @class */ (function (_super) {
        __extends(StockBagIndex, _super);
        function StockBagIndex() {
            return _super !== null && _super.apply(this, arguments) || this;
        }
        StockBagIndex.prototype.key = function (key) {
            return "stock-bag-v2-" + key;
        };
        StockBagIndex.prototype.createModel = function () {
            var self = this;
            var canRun = true;
            if (!self.sort()) {
                self.sort("Name");
                self.sortDirection(Constants.SORT_ASC);
            }
            ko.computed(function () {
                var page = self.page();
                var pageSize = self.pageSize();
                var search = self.search();
                var dir = self.sortDirection();
                var sort = self.sort();
                if (canRun) {
                    canRun = false;
                    if (self.state() == Constants.STATE_READY)
                        self.state(Constants.STATE_BUSY);
                    var service = BagService.New()
                        .With("status", "active")
                        .With("direction", dir)
                        .With("sort", sort)
                        .With("q", search)
                        .With("stockId", $("#id").val());
                    service.Get((page - 1) * pageSize, pageSize, function (result) {
                        self.state(Constants.STATE_READY);
                        self.total(result.total);
                        self.data.removeAll();
                        for (var i = 0; i < result.data.length; i++) {
                            self.data.push(result.data[i]);
                        }
                        canRun = true;
                    });
                }
            });
            return self;
        };
        return StockBagIndex;
    }(BindableIndexModel));
    Admin.StockBagIndex = StockBagIndex;
})(Admin || (Admin = {}));
//# sourceMappingURL=Admin.StockBagIndex.js.map;
var Admin;
(function (Admin) {
    var StockDetails = /** @class */ (function () {
        function StockDetails() {
            this.result = ko.observable();
            this.source = ko.observable();
            this.isLoading = ko.observable(false);
            this.bagTotal = ko.observable();
            this.userTotal = ko.observable();
            this.dogTotal = ko.observable();
        }
        StockDetails.prototype.createModel = function () {
            var self = this;
            self.isLoading(true);
            StockService.New().GetDetail($("#id").val(), function (result, error) {
                if (result) {
                    self.result(result);
                    $("#delete-button").click(function () {
                        self.isLoading(true);
                        StockService.New().Delete($("#id").val(), function (result) {
                            self.isLoading(false);
                            if (result) {
                                window.location.pathname = "/admin/stock";
                            }
                            else {
                                $('[data-error="General"]').text("Woops something went wrong");
                                $('[data-error="General"]').show();
                            }
                        });
                        return false;
                    });
                    SupplierProductService.New()
                        .With("supplierId", result.supplierId)
                        .With("productVariantId", result.productVariantId)
                        .GetAll(function (result) {
                        self.isLoading(false);
                        if (result && result.total > 0)
                            self.source(result.data[0]);
                    });
                }
                else {
                    $('[data-error="General"]').text("Woops something went wrong");
                    $('[data-error="General"]').show();
                }
            });
            BagService.New()
                .With("stockId", $("#id").val())
                .Get(0, 0, function (result) {
                if (result)
                    self.bagTotal(result.total);
            });
            UserService.New()
                .With("stockId", $("#id").val())
                .Get(0, 0, function (result) {
                if (result)
                    self.userTotal(result.total);
            });
            DogService.New()
                .With("stockId", $("#id").val())
                .Get(0, 0, function (result) {
                if (result)
                    self.dogTotal(result.total);
            });
            return self;
        };
        return StockDetails;
    }());
    Admin.StockDetails = StockDetails;
})(Admin || (Admin = {}));
//# sourceMappingURL=Admin.StockDetails.js.map;
var Admin;
(function (Admin) {
    var StockEdit = /** @class */ (function () {
        function StockEdit() {
            this.isLoading = ko.observable(false);
            this.url = ko.observable();
            this.difference = ko.observable(0);
        }
        StockEdit.prototype.createModel = function () {
            var self = this;
            $("#quantity").keyup(function () {
                if ($("#quantity").val()) {
                    $("#quantityAvailable").val($("#quantity").val() - self.difference());
                }
                else {
                    $("#quantityAvailable").val(0);
                }
            });
            StockService.New().GetDetail($("#id").val(), function (result) {
                self.difference(result.quantity - result.quantityAvailable);
                $("#quantity").val(result.quantity);
                if (result.bestBefore)
                    $("#bestBefore").val(moment.utc(result.bestBefore).local().format("DD/MM/YY"));
                $("#quantityAvailable").val(result.quantityAvailable);
                $("#unitCost").val(result.unitCost);
                $("#supplierToAdd")
                    .append('<option value="' + result.supplier.id + '">' + result.supplier.name + '</option>')
                    .val(result.supplier.id)
                    .trigger("change");
                $("#productToAdd")
                    .append('<option value="' + result.productVariant.id + '">' + result.productVariant.title + '</option>')
                    .val(result.productVariant.id)
                    .trigger("change");
                $("#supplierToAdd").select2({
                    ajax: {
                        url: "/api/v1/suppliers",
                        dataType: 'json',
                        delay: 250,
                        data: function (query) {
                            var search = "";
                            if (query.term)
                                search = "q=" + query.term;
                            if (query.page) {
                                if (search.length > 0)
                                    search = search + "&";
                                search = search + "skip=" + (query.page - 1) * 5 + "&take=5";
                            }
                            return search;
                        },
                        processResults: function (data, params) {
                            var results = [{
                                    id: "",
                                    text: "Search for supplier to add"
                                }];
                            if (data && data.data) {
                                for (var i = 0; i < data.data.length; i++) {
                                    results.push({
                                        id: data.data[i].id,
                                        text: data.data[i].name
                                    });
                                }
                            }
                            return {
                                results: results
                            };
                        },
                        cache: true
                    },
                    minimumInputLength: 0
                });
                $("#productToAdd").select2({
                    ajax: {
                        url: "/api/v1/productvariants",
                        dataType: 'json',
                        delay: 250,
                        data: function (query) {
                            var search = "";
                            if (query.term)
                                search = "q=" + query.term;
                            if (query.page) {
                                if (search.length > 0)
                                    search = search + "&";
                                search = search + "skip=" + (query.page - 1) * 5 + "&take=5";
                            }
                            return search;
                        },
                        processResults: function (data, params) {
                            var results = [{
                                    id: "",
                                    text: "Search for supplier to add"
                                }];
                            if (data && data.data) {
                                for (var i = 0; i < data.data.length; i++) {
                                    results.push({
                                        id: data.data[i].id,
                                        text: data.data[i].title
                                    });
                                }
                            }
                            return {
                                results: results
                            };
                        },
                        cache: true
                    },
                    minimumInputLength: 0
                });
            });
            $("#save-button").click(function () {
                $('#save-button').attr("disabled", "disabled");
                self.isLoading(true);
                $("[data-error]").hide();
                StockService.New().Update($("#id").val(), {
                    supplierId: $("#supplierToAdd").val(),
                    productVariantId: $("#productToAdd").val(),
                    quantity: parseInt($("#quantity").val()),
                    unitCost: parseFloat($("#unitCost").val()),
                    bestBefore: $("#bestBefore").val().length > 0 ? moment($("#bestBefore").val(), "DD/MM/YY").toISOString() : null
                }, function (result, error) {
                    $('#save-button').removeAttr("disabled");
                    self.isLoading(false);
                    if (result) {
                        window.location.pathname = "/admin/stock/details/" + $("#id").val();
                    }
                    else if (error && error.errors) {
                        for (var i = 0, len = error.errors.length; i < len; i++) {
                            $('[data-error="' + error.errors[i].key + '"]').text(error.errors[i].error);
                            $('[data-error="' + error.errors[i].key + '"]').show();
                        }
                    }
                    else {
                        $('[data-error="General"]').text("Woops something went wrong");
                        $('[data-error="General"]').show();
                    }
                });
                return false;
            });
            return self;
        };
        return StockEdit;
    }());
    Admin.StockEdit = StockEdit;
})(Admin || (Admin = {}));
//# sourceMappingURL=Admin.StockEdit.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var Admin;
(function (Admin) {
    var StockIndex = /** @class */ (function (_super) {
        __extends(StockIndex, _super);
        function StockIndex() {
            var _this = _super !== null && _super.apply(this, arguments) || this;
            _this.supplierIdFilter = ko.observable(Utilities.GetUrlParam("supplierId", document.location));
            _this.brandIdFilter = ko.observable(Utilities.GetUrlParam("brandId", document.location));
            _this.expiryFilter = ko.observable(StorageService.Get(_this.key("expiryFilter")));
            _this.hasAvailable = ko.observable(StorageService.Get(_this.key("hasAvailable")));
            return _this;
        }
        StockIndex.prototype.key = function (key) {
            return "stock-v2-" + key;
        };
        StockIndex.prototype.createModel = function () {
            var self = this;
            var canRun = true;
            if (!self.sort()) {
                self.sort("Name");
                self.sortDirection(Constants.SORT_ASC);
            }
            ko.computed(function () {
                var expiryFilter = self.expiryFilter();
                if (expiryFilter) {
                    StorageService.Store(self.key("expiryFilter"), expiryFilter);
                }
                else {
                    StorageService.Clear(self.key("expiryFilter"));
                }
            });
            ko.computed(function () {
                var hasAvailable = self.hasAvailable();
                if (hasAvailable) {
                    StorageService.Store(self.key("hasAvailable"), hasAvailable);
                }
                else {
                    StorageService.Clear(self.key("hasAvailable"));
                }
            });
            ko.computed(function () {
                var page = self.page();
                var pageSize = self.pageSize();
                var search = self.search();
                var dir = self.sortDirection();
                var sort = self.sort();
                var supplierIdFilter = self.supplierIdFilter();
                var brandIdFilter = self.brandIdFilter();
                var hasAvailable = self.hasAvailable();
                var expiryFilter = self.expiryFilter();
                if (canRun) {
                    canRun = false;
                    if (self.state() == Constants.STATE_READY)
                        self.state(Constants.STATE_BUSY);
                    var service = StockService.New()
                        .With("status", "active")
                        .With("direction", dir)
                        .With("sort", sort)
                        .With("q", search);
                    if (supplierIdFilter)
                        service = service.With("supplierId", supplierIdFilter);
                    if (brandIdFilter)
                        service = service.With("brandId", brandIdFilter);
                    if (hasAvailable)
                        service = service.With("hasAvailable", hasAvailable);
                    if (expiryFilter) {
                        if (expiryFilter == "near-expiry")
                            service = service.With("nearExpiry", true);
                        if (expiryFilter == "expired")
                            service = service.With("expired", true);
                        if (expiryFilter == "not-expired")
                            service = service.With("expired", false);
                    }
                    service.Get((page - 1) * pageSize, pageSize, function (result) {
                        self.state(Constants.STATE_READY);
                        self.total(result.total);
                        self.data.removeAll();
                        for (var i = 0; i < result.data.length; i++) {
                            self.data.push(result.data[i]);
                        }
                        canRun = true;
                    });
                }
            });
            ko.computed(function () {
                if (self.supplierIdFilter()) {
                    SupplierService.New()
                        .GetDetail(self.supplierIdFilter(), function (result) {
                        if (result) {
                            self.filteredTo("the supplier " + result.name);
                        }
                    });
                }
                if (self.brandIdFilter()) {
                    BrandService.New()
                        .GetDetail(self.brandIdFilter(), function (result) {
                        if (result) {
                            self.filteredTo("the brand " + result.name);
                        }
                    });
                }
                if (self.supplierIdFilter() == null && self.brandIdFilter() == null)
                    self.filteredTo(null);
            });
            $("#clearFilter").click(function () {
                if (canRun) {
                    self.supplierIdFilter(null);
                    self.brandIdFilter(null);
                    return false;
                }
            });
            return self;
        };
        return StockIndex;
    }(BindableIndexModel));
    Admin.StockIndex = StockIndex;
})(Admin || (Admin = {}));
//# sourceMappingURL=Admin.StockIndex.js.map;
var Admin;
(function (Admin) {
    var SupplierDetails = /** @class */ (function () {
        function SupplierDetails() {
            this.name = ko.observable();
            this.isLoading = ko.observable(false);
            this.productTotal = ko.observable();
            this.productVariantTotal = ko.observable();
            this.stockTotal = ko.observable();
        }
        SupplierDetails.prototype.createModel = function () {
            var self = this;
            self.isLoading(true);
            SupplierService.New().GetDetail($("#id").val(), function (result, error) {
                self.isLoading(false);
                if (result) {
                    self.name(result.name);
                }
                else {
                    $('[data-error="General"]').text("Woops something went wrong");
                    $('[data-error="General"]').show();
                }
            });
            ProductService.New()
                .With("supplierId", $("#id").val())
                .Get(0, 0, function (result) {
                if (result)
                    self.productTotal(result.total);
            });
            ProductVariantService.New()
                .With("supplierId", $("#id").val())
                .Get(0, 0, function (result) {
                if (result)
                    self.productVariantTotal(result.total);
            });
            StockService.New()
                .With("supplierId", $("#id").val())
                .With("hasAvailable", true)
                .Get(0, 0, function (result) {
                if (result)
                    self.stockTotal(result.total);
            });
            $("#delete-button").click(function () {
                self.isLoading(true);
                SupplierService.New().Delete($("#id").val(), function (result) {
                    self.isLoading(false);
                    if (result) {
                        window.location.pathname = "/admin/suppliers";
                    }
                    else {
                        $('[data-error="General"]').text("Woops something went wrong");
                        $('[data-error="General"]').show();
                    }
                });
                return false;
            });
            return self;
        };
        return SupplierDetails;
    }());
    Admin.SupplierDetails = SupplierDetails;
})(Admin || (Admin = {}));
//# sourceMappingURL=Admin.SupplierDetails.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var Admin;
(function (Admin) {
    var SupplierIndex = /** @class */ (function (_super) {
        __extends(SupplierIndex, _super);
        function SupplierIndex() {
            var _this = _super !== null && _super.apply(this, arguments) || this;
            _this.productIdFilter = ko.observable(Utilities.GetUrlParam("productId", document.location));
            _this.productVariantIdFilter = ko.observable(Utilities.GetUrlParam("productVariantId", document.location));
            _this.isAddMode = ko.observable(false);
            return _this;
        }
        SupplierIndex.prototype.key = function (key) {
            return "supplier-v2-" + key;
        };
        SupplierIndex.prototype.createModel = function () {
            var self = this;
            var canRun = true;
            $('#nameToAdd').on('keydown', function (e) {
                if (e.which == 13) {
                    e.preventDefault();
                    self.addEntity();
                }
            });
            self.addEntity = function () {
                if ($("#nameToAdd").val()) {
                    SupplierService.New().Create({
                        name: $("#nameToAdd").val()
                    }, function (result, error) {
                        if (result) {
                            alertify.success("Supplier added");
                            self.page.valueHasMutated();
                            $("#nameToAdd").val("");
                        }
                        else {
                            alertify.error("Cannot add supplier");
                        }
                    });
                }
                else {
                    alertify.error("Please enter a value");
                }
                return false;
            };
            if (!self.sort()) {
                self.sort("Name");
                self.sortDirection(Constants.SORT_ASC);
            }
            ko.computed(function () {
                var page = self.page();
                var pageSize = self.pageSize();
                var search = self.search();
                var dir = self.sortDirection();
                var sort = self.sort();
                var productIdFilter = self.productIdFilter();
                var productVariantIdFilter = self.productVariantIdFilter();
                if (canRun) {
                    canRun = false;
                    if (self.state() == Constants.STATE_READY)
                        self.state(Constants.STATE_BUSY);
                    var service = SupplierService.New()
                        .With("status", "active")
                        .With("direction", dir)
                        .With("sort", sort)
                        .With("q", search);
                    if (productIdFilter)
                        service = service.With("productId", productIdFilter);
                    if (productVariantIdFilter)
                        service = service.With("productVariantId", productVariantIdFilter);
                    service.Get((page - 1) * pageSize, pageSize, function (result) {
                        self.state(Constants.STATE_READY);
                        self.total(result.total);
                        self.data.removeAll();
                        for (var i = 0; i < result.data.length; i++) {
                            self.data.push(result.data[i]);
                        }
                        setTimeout(function () {
                            $(".editable-name").editable({
                                pk: 1,
                                mode: "inline",
                                type: 'text',
                                success: function (response, newValue) {
                                    SupplierService.New().UpdateSingle($(this).attr("id"), "name", newValue);
                                }
                            }).on('shown', function (e, editable) {
                                editable.input.$input.val($(e.currentTarget).text().trim());
                            });
                        }, 10);
                        canRun = true;
                    });
                }
            });
            ko.computed(function () {
                if (self.productIdFilter()) {
                    ProductService.New()
                        .GetDetail(self.productIdFilter(), function (result) {
                        if (result) {
                            self.filteredTo("the product " + result.title);
                        }
                    });
                }
                if (self.productVariantIdFilter()) {
                    ProductVariantService.New()
                        .GetDetail(self.productVariantIdFilter(), function (result) {
                        if (result) {
                            self.filteredTo("the product variant " + result.title);
                        }
                    });
                }
                if (self.productIdFilter() == null && self.productVariantIdFilter() == null)
                    self.filteredTo(null);
            });
            $("#clearFilter").click(function () {
                if (canRun) {
                    self.productIdFilter(null);
                    self.productVariantIdFilter(null);
                    return false;
                }
            });
            return self;
        };
        return SupplierIndex;
    }(BindableIndexModel));
    Admin.SupplierIndex = SupplierIndex;
})(Admin || (Admin = {}));
//# sourceMappingURL=Admin.SupplierIndex.js.map;
var Admin;
(function (Admin) {
    var SupplierProductEdit = /** @class */ (function () {
        function SupplierProductEdit() {
            this.isDiscontinued = ko.observable();
            this.isInStock = ko.observable();
            this.supplierId = ko.observable();
            this.isLoading = ko.observable(false);
        }
        SupplierProductEdit.prototype.createModel = function () {
            var self = this;
            self.isLoading(true);
            SupplierProductService.New().GetDetail($("#id").val(), function (result, error) {
                self.isLoading(false);
                if (result) {
                    self.isDiscontinued(result.discontinued != null);
                    self.isInStock(result.inStock);
                    self.supplierId(result.supplierId);
                }
                else {
                    $('[data-error="General"]').text("Woops something went wrong");
                    $('[data-error="General"]').show();
                }
            });
            $("#save-button").click(function () {
                $('#save-button').attr("disabled", "disabled");
                self.isLoading(true);
                $("[data-error]").hide();
                SupplierProductService.New().Update($("#id").val(), {
                    discontinued: self.isDiscontinued() ? moment.utc(new Date()).toISOString() : null,
                    inStock: self.isInStock()
                }, function (result, error) {
                    $('#save-button').removeAttr("disabled");
                    self.isLoading(false);
                    if (result) {
                        window.location.pathname = "/admin/suppliers/details/" + self.supplierId();
                    }
                    else if (error && error.errors) {
                        for (var i = 0, len = error.errors.length; i < len; i++) {
                            $('[data-error="' + error.errors[i].key + '"]').text(error.errors[i].error);
                            $('[data-error="' + error.errors[i].key + '"]').show();
                        }
                    }
                    else {
                        $('[data-error="General"]').text("Woops something went wrong");
                        $('[data-error="General"]').show();
                    }
                });
                return false;
            });
            return self;
        };
        return SupplierProductEdit;
    }());
    Admin.SupplierProductEdit = SupplierProductEdit;
})(Admin || (Admin = {}));
//# sourceMappingURL=Admin.SupplierProductEdit.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var Admin;
(function (Admin) {
    var SupplierProductIndex = /** @class */ (function (_super) {
        __extends(SupplierProductIndex, _super);
        function SupplierProductIndex() {
            var _this = _super !== null && _super.apply(this, arguments) || this;
            _this.supplierIdFilter = ko.observable($("#id").val());
            return _this;
        }
        SupplierProductIndex.prototype.key = function (key) {
            return "supplierproduct-v2-" + key;
        };
        SupplierProductIndex.prototype.createModel = function () {
            var self = this;
            var canRun = true;
            self.removeProduct = function (id) {
                SupplierProductService.New()
                    .Delete(id, function () {
                    self.page.valueHasMutated();
                });
                return false;
            };
            if (!self.sort()) {
                self.sort("Name");
                self.sortDirection(Constants.SORT_ASC);
            }
            $("#add-product").click(function () {
                var productId = $("#productToAdd").val();
                if (productId && productId.length > 0) {
                    var done = 0;
                    ProductVariantService.New()
                        .With("productId", $("#productToAdd").val())
                        .GetAll(function (data) {
                        _.forEach(data.data, function (item) {
                            SupplierProductService.New().Create({
                                productVariantId: item.id,
                                supplierId: self.supplierIdFilter()
                            }, function () {
                                done++;
                                if (done == data.total) {
                                    alertify.success("Product added to supplier");
                                    $("#productToAdd").val(null).trigger("change");
                                    self.page.valueHasMutated();
                                }
                            });
                        });
                    });
                }
                else {
                    alertify.error("Please select a product to add");
                }
                return false;
            });
            $("#productToAdd").select2({
                ajax: {
                    url: "/api/v1/products?excludeSupplierId=" + self.supplierIdFilter(),
                    dataType: 'json',
                    delay: 250,
                    data: function (query) {
                        var search = "";
                        if (query.term)
                            search = "q=" + query.term;
                        if (query.page) {
                            if (search.length > 0)
                                search = search + "&";
                            search = search + "skip=" + (query.page - 1) * 5 + "&take=5";
                        }
                        return search;
                    },
                    processResults: function (data, params) {
                        var results = [{
                                id: "",
                                text: "Search for product to add"
                            }];
                        if (data && data.data) {
                            for (var i = 0; i < data.data.length; i++) {
                                results.push({
                                    id: data.data[i].id,
                                    text: data.data[i].title
                                });
                            }
                        }
                        return {
                            results: results
                        };
                    },
                    cache: true
                },
                minimumInputLength: 0
            });
            ko.computed(function () {
                var page = self.page();
                var pageSize = self.pageSize();
                var search = self.search();
                var dir = self.sortDirection();
                var sort = self.sort();
                var supplierIdFilter = self.supplierIdFilter();
                if (canRun) {
                    canRun = false;
                    if (self.state() == Constants.STATE_READY)
                        self.state(Constants.STATE_BUSY);
                    var service = SupplierProductService.New()
                        .With("status", "active")
                        .With("direction", dir)
                        .With("sort", sort)
                        .With("q", search);
                    if (supplierIdFilter)
                        service = service.With("supplierId", supplierIdFilter);
                    service.Get((page - 1) * pageSize, pageSize, function (result) {
                        self.state(Constants.STATE_READY);
                        self.total(result.total);
                        self.data.removeAll();
                        for (var i = 0; i < result.data.length; i++) {
                            self.data.push(result.data[i]);
                        }
                        canRun = true;
                    });
                }
            });
            return self;
        };
        return SupplierProductIndex;
    }(BindableIndexModel));
    Admin.SupplierProductIndex = SupplierProductIndex;
})(Admin || (Admin = {}));
//# sourceMappingURL=Admin.SupplierProductIndex.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var Admin;
(function (Admin) {
    var UserIndex = /** @class */ (function (_super) {
        __extends(UserIndex, _super);
        function UserIndex() {
            var _this = _super !== null && _super.apply(this, arguments) || this;
            _this.userTypeFilter = ko.observable(StorageService.Get(_this.key("userTypeFilter")));
            return _this;
        }
        UserIndex.prototype.key = function (key) {
            return "user-v2-" + key;
        };
        UserIndex.prototype.createModel = function () {
            var self = this;
            var canRun = true;
            if (!self.sort()) {
                self.sort("Name");
                self.sortDirection(Constants.SORT_ASC);
            }
            ko.computed(function () {
                var userTypeFilter = self.userTypeFilter();
                if (userTypeFilter)
                    StorageService.Store(self.key("userTypeFilter"), userTypeFilter);
                else
                    StorageService.Clear(self.key("userTypeFilter"));
            });
            ko.computed(function () {
                var page = self.page();
                var pageSize = self.pageSize();
                var search = self.search();
                var dir = self.sortDirection();
                var sort = self.sort();
                var userTypeFilter = self.userTypeFilter();
                if (canRun) {
                    canRun = false;
                    if (self.state() == Constants.STATE_READY)
                        self.state(Constants.STATE_BUSY);
                    var service = UserService.New()
                        .With("status", "active")
                        .With("direction", dir)
                        .With("sort", sort)
                        .With("q", search);
                    if (userTypeFilter) {
                        if (userTypeFilter == "subscribed") {
                            service = service.With("isSubscribed", true);
                        }
                        if (userTypeFilter == "not-sale") {
                            service = service.With("hasSale", false);
                        }
                        if (userTypeFilter == "one-off") {
                            service = service.With("hasOneOff", false);
                        }
                        if (userTypeFilter == "subscription") {
                            service = service.With("hasPlan", true);
                        }
                        if (userTypeFilter == "subscription") {
                            service = service.With("hasPlan", true);
                        }
                        if (userTypeFilter == "subscription-paused") {
                            service = service.With("hasPlan", true);
                            service = service.With("planStatus", "paused");
                        }
                        if (userTypeFilter == "subscription-cancelled") {
                            service = service.With("hasPlan", true);
                            service = service.With("planStatus", "cancelled");
                        }
                    }
                    service.Get((page - 1) * pageSize, pageSize, function (result) {
                        self.state(Constants.STATE_READY);
                        self.total(result.total);
                        self.data.removeAll();
                        for (var i = 0; i < result.data.length; i++) {
                            self.data.push(result.data[i]);
                        }
                        canRun = true;
                    });
                }
            });
            $("#clearFilter").click(function () {
                if (canRun) {
                    return false;
                }
            });
            return self;
        };
        return UserIndex;
    }(BindableIndexModel));
    Admin.UserIndex = UserIndex;
})(Admin || (Admin = {}));
//# sourceMappingURL=Admin.UserIndex.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var BarkBag;
(function (BarkBag) {
    var CartNavItem = /** @class */ (function (_super) {
        __extends(CartNavItem, _super);
        function CartNavItem() {
            var _this = _super !== null && _super.apply(this, arguments) || this;
            _this.cart = ko.observable();
            _this.numberCartItems = ko.observable(Utilities.Default(parseInt(StorageService.Get("cart-items-count")), 0));
            _this.loadingState = ko.observable(Constants.STATE_INITIAL);
            _this.attempts = 2;
            _this.activePromoCode = ko.observable(StorageService.Get("active-promocode"));
            _this.promocodeInstructions = ko.observable(StorageService.Get("active-promocode-instructions"));
            return _this;
        }
        CartNavItem.prototype.createModel = function () {
            var self = this;
            $.notiny.addTheme('normal', {
                notification_class: 'notiny-theme-normal notiny-default-vars'
            });
            $.notiny.addTheme('error', {
                notification_class: 'notiny-theme-error notiny-default-vars'
            });
            $.notiny.addTheme('success', {
                notification_class: 'notiny-theme-success notiny-default-vars'
            });
            ko.computed(function () {
                Constants.GLOBAL_REFRESH();
                var pc = self.activePromoCode();
                if (self.attempts > 0) {
                    //TODO: FIX FOR IF CART ID NOT AVAILABLE
                    CartService.New()
                        .GetDetail(CartService.CartId(), function (result) {
                        self.loadingState(Constants.STATE_READY);
                        if (result) {
                            self.cart(result);
                            if (self.cart() && self.cart().cartItems) {
                                var filteredItems = _.filter(self.cart().cartItems, function (cartItem) {
                                    return cartItem.name.indexOf("Shipping") == -1 && cartItem.id != "00000000-0000-0000-0000-000000000000";
                                });
                                self.numberCartItems(filteredItems.length);
                                StorageService.Store("cart-items-count", filteredItems.length + "");
                            }
                            if (pc) {
                                //attempt to apply promocode
                                if (document.location.href.indexOf("check-out") != -1 && document.location.href.indexOf("confirm") != -1) {
                                    //Remove any other code applied
                                    var otherCodes = self.cart().promoCodes
                                        .filter(function (code, i) {
                                        return code.promoCodeDefinition.code != self.activePromoCode();
                                    });
                                    if (otherCodes.length > 0) {
                                        for (var i = 0; i < otherCodes.length; i++) {
                                            PromoCodeService.New()
                                                .Delete(otherCodes[i].id);
                                        }
                                    }
                                    //Add this code
                                    var sameCode = self.cart().promoCodes
                                        .filter(function (code, i) {
                                        return code.promoCodeDefinition.code == self.activePromoCode();
                                    });
                                    if (sameCode.length == 0) {
                                        console.log("Applyuing code");
                                        PromoCodeService.New()
                                            .Create({
                                            cartId: self.cart().id,
                                            code: self.activePromoCode()
                                        }, function (code, error) {
                                            if (error) {
                                                $.notiny({ text: "The promo code <b>'" + pc + "'</b> cannot be applied. <i>" + error.description + "</i>", position: 'fluid-bottom', autohide: false, clickhide: true, theme: 'error' });
                                            }
                                            else {
                                                self.activePromoCodeNotification = $.notiny({ text: "The promo code <b>'" + pc + "'</b> is applied.", position: 'fluid-bottom', autohide: false, clickhide: true, theme: 'success' });
                                                Constants.GLOBAL_REFRESH.valueHasMutated();
                                            }
                                        });
                                    }
                                    else {
                                        if (!self.activePromoCodeNotification)
                                            $.notiny({ text: "The promo code <b>'" + pc + "'</b> is applied.", position: 'fluid-bottom', autohide: false, clickhide: true, theme: 'success' });
                                    }
                                }
                            }
                        }
                        else {
                            //self.numberCartItems(0);
                            self.attempts = self.attempts - 1;
                            StorageService.Store("cart-items-count", "0");
                            CartService.New()
                                .Create({}, function (result) {
                                Constants.GLOBAL_REFRESH.valueHasMutated();
                            });
                        }
                    });
                }
            });
            var pc = Utilities.GetUrlParam("pc", document.location);
            if (pc) {
                PromoCodeDefinitionService.New()
                    .GetDetail(pc, function (result) {
                    if (!result) {
                        $.notiny({ text: "The promo code <b>'" + pc + "'</b> is no longer valid.", position: 'fluid-bottom', autohide: true, clickhide: true, theme: 'error' });
                        self.activePromoCode("");
                        StorageService.Clear("active-promocode");
                        setTimeout(function () {
                            if (typeof window.history.replaceState == 'function') {
                                history.replaceState({}, '', Utilities.RemoveURLParameters(window.location.href));
                            }
                            else {
                                window.location.href = Utilities.RemoveURLParameters(window.location.href);
                            }
                        }, 3000);
                    }
                    else {
                        self.activePromoCode(pc);
                        StorageService.Store("active-promocode", result.code);
                        self.promocodeInstructions(result.description);
                        StorageService.Store("active-promocode-instructions", result.description);
                        if (typeof window.history.replaceState == 'function') {
                            history.replaceState({}, '', Utilities.RemoveURLParameters(window.location.href));
                        }
                        else {
                            window.location.href = Utilities.RemoveURLParameters(window.location.href);
                        }
                    }
                });
            }
            //remove FS on signout
            var so = Utilities.GetUrlParam("so", document.location);
            if (so) {
                if (typeof FS == "function") {
                    FS.identify(false);
                }
                setTimeout(function () {
                    if (typeof window.history.replaceState == 'function') {
                        history.replaceState({}, '', Utilities.RemoveURLParameters(window.location.href));
                    }
                    else {
                        window.location.href = Utilities.RemoveURLParameters(window.location.href);
                    }
                }, 100);
            }
            ko.computed(function () {
                var pc = self.activePromoCode();
                if (self.activePromoCodeNotification)
                    $.notiny.close(self.activePromoCodeNotification);
                if (pc) {
                    if (document.location.href.indexOf("check-out") == -1 || document.location.href.indexOf("confirm") == -1) {
                        var instructions = self.promocodeInstructions();
                        if (instructions) {
                            self.activePromoCodeNotification = $.notiny({ text: "The promo code <b>'" + pc + "'</b> will apply on final checkout screen. <i>" + instructions + "</i>", position: 'fluid-bottom', autohide: false, clickhide: true, theme: "normal" });
                        }
                        else {
                            self.activePromoCodeNotification = $.notiny({ text: "The promo code <b>'" + pc + "'</b> will apply on final checkout screen. ", position: 'fluid-bottom', autohide: false, clickhide: true, theme: "normal" });
                        }
                    }
                }
            });
            self.pageReady(true);
            return self;
        };
        return CartNavItem;
    }(BindablePageModel));
    BarkBag.CartNavItem = CartNavItem;
})(BarkBag || (BarkBag = {}));
//# sourceMappingURL=BarkBag.CartNavItem.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var BarkBag;
(function (BarkBag) {
    var CartViewModel = /** @class */ (function (_super) {
        __extends(CartViewModel, _super);
        function CartViewModel() {
            var _this = _super !== null && _super.apply(this, arguments) || this;
            _this.cart = ko.observable();
            _this.updateCart = ko.observable();
            _this.shippingDate = ko.observable();
            return _this;
        }
        CartViewModel.prototype.createModel = function () {
            var self = this;
            $(document).on("change", '.quantity-update', function () {
                for (var i = 0; i < self.cart().cartItems.length; i++) {
                    self.cart().cartItems[i].quantity = $("#" + self.cart().cartItems[i].id).val();
                    self.cart().cartItems[i].total(self.cart().cartItems[i].price * self.cart().cartItems[i].quantity);
                }
                self.cart.valueHasMutated();
            });
            self.shippingDateDaysAway = ko.computed(function () {
                return moment.utc(self.shippingDate()).diff(moment(), 'days');
            });
            self.canAddOneOff = ko.computed(function () {
                var cart = self.cart();
                if (cart) {
                    var barkBag = _.find(cart.cartItems, function (item) { return item.isSubscription; });
                    if (barkBag) {
                        self.shippingDate(barkBag.shippingDate);
                        var introBarkBag = _.find(cart.cartItems, function (item) { return item.productVariantId == Constants.EXTRA_ONE_OFF_PRODUCT_VARIANT_ID; });
                        if (moment.utc(barkBag.shippingDate) > moment().add("days", 8) && introBarkBag == null) {
                            return true;
                        }
                    }
                    return false;
                }
            });
            ko.computed(function () {
                self.updateCart();
                self.loading(true);
                CartService.New().GetDetail(CartService.CartId(), function (result, error) {
                    if (result) {
                        for (var i = 0; i < result.cartItems.length; i++) {
                            result.cartItems[i].total = ko.observable(result.cartItems[i].price * result.cartItems[i].quantity);
                        }
                        self.cart(result);
                        if (typeof ga == "function") {
                            ga('send', 'event', 'cart', 'view', self.cart().id, self.cartTotal());
                        }
                    }
                    self.pageReady(true);
                    self.loading(false);
                });
            });
            self.addIntroBarkBag = function (data, event) {
                if (self.canAddOneOff()) {
                    var l = Ladda.create(event.currentTarget);
                    l.start();
                    self.loading(true);
                    CartItemService.New()
                        .Create({
                        cartId: self.cart().id,
                        productVariantId: Constants.EXTRA_ONE_OFF_PRODUCT_VARIANT_ID
                    }, function () {
                        l.stop();
                        self.updateCart.valueHasMutated();
                        self.loading(false);
                    });
                }
            };
            self.removeCartItem = function (id) {
                self.loading(true);
                CartItemService.New()
                    .Delete(id, function () {
                    self.updateCart.valueHasMutated();
                    self.loading(false);
                });
            };
            self.cartTotal = ko.computed(function () {
                var total = 0;
                if (self.cart() && self.cart().cartItems) {
                    _.each(self.cart().cartItems, function (item) {
                        total = total + item.price * item.quantity;
                    });
                }
                return total;
            });
            self.submitForm = function (data, event) {
                var l = Ladda.create(event.currentTarget);
                l.start();
                if (self.cart() && self.cart().cartItems) {
                    var promises = new Array();
                    for (var i = 0; i < self.cart().cartItems.length; i++) {
                        var item = self.cart().cartItems[i];
                        var item_promise = $.Deferred();
                        promises.push(item_promise);
                        if ($("#" + item.id).val() > 0) {
                            (function (promise) {
                                CartItemService.New()
                                    .UpdateSingle(item.id, "quantity", $("#" + item.id).val(), function (result) {
                                    promise.resolve();
                                });
                            })(item_promise);
                        }
                        else {
                            item_promise.resolve();
                        }
                    }
                    $.when.apply($, promises).then(function () {
                        document.location.pathname = "/check-out";
                    });
                }
                else {
                    document.location.pathname = "/shop";
                }
                return false;
            };
            return self;
        };
        return CartViewModel;
    }(BindablePageModel));
    BarkBag.CartViewModel = CartViewModel;
})(BarkBag || (BarkBag = {}));
//# sourceMappingURL=BarkBag.CartViewModel.js.map;
var BarkBag;
(function (BarkBag) {
    var CheckoutConfirmModel = /** @class */ (function () {
        function CheckoutConfirmModel() {
            this.loadingState = ko.observable(Constants.STATE_INITIAL);
            this.cart = ko.observable();
            this.updateCart = ko.observable();
            this.recurringText = ko.observable();
            this.shippingDate = ko.observable();
            this.shippingDateSubscription = ko.observable();
            this.deviceData = ko.observable();
            this.isSubmitting = ko.observable(false);
            this.giftName = ko.observable();
            this.giftMessage = ko.observable();
            this.address = ko.observable();
            this.user = ko.observable();
            this.dogs = ko.observableArray();
            this.selectedCreditCard = ko.observable();
            this.creditCards = ko.observableArray();
            this.creditCardLoaded = ko.observable(false);
            this.showAddPromoCode = ko.observable(false);
            this.enteredPromoCode = ko.observable();
        }
        CheckoutConfirmModel.prototype.createModel = function () {
            var self = this;
            ko.computed(function () {
                Constants.GLOBAL_REFRESH();
                self.updateCart.valueHasMutated();
            });
            var md = new MobileDetect(window.navigator.userAgent);
            braintree.setup($("#ClientSideToken").val(), 'custom', {
                id: 'payment-container',
                dataCollector: {
                    kount: { environment: 'sandbox' }
                },
                hostedFields: {
                    styles: {
                        'input': {
                            'font-size': '1em',
                            'height': '40px'
                        }
                    },
                    number: {
                        selector: "#card-number"
                    },
                    cvv: {
                        selector: "#card-cvv"
                    },
                    expirationDate: {
                        selector: "#card-exp",
                        placeholder: md.phone() ? 'MMYY' : 'MM/YY'
                    }
                },
                onError: function (error) {
                    $("#btn-confirm-pay").prop('disabled', false);
                    LoaderService.StopOverlay();
                    $(".field-validation-error").addClass("hidden");
                    $("#card-alert").addClass("hidden");
                    if (error.type == "VALIDATION") {
                        $("#card-alert").removeClass("hidden");
                        $("#card-alert").text("We couldn't process your card, please check the details below are correct.");
                        if (error.details && error.details.invalidFieldKeys) {
                            for (var i = 0; i < error.details.invalidFieldKeys.length; i++) {
                                var field = error.details.invalidFieldKeys[i];
                                $("#group-" + field).find(".field-validation-error").removeClass("hidden");
                            }
                        }
                        Ladda.stopAll();
                    }
                },
                onReady: function (braintreeInstance) {
                    self.deviceData(braintreeInstance.deviceData);
                },
                onPaymentMethodReceived: function (response) {
                    if (!self.isSubmitting()) {
                        self.isSubmitting(true);
                        $(".field-validation-error").addClass("hidden");
                        $("#card-alert").addClass("hidden");
                        $("#btn-confirm-pay").prop('disabled', true);
                        LoaderService.StartOverlay("Fetching your order, woof!");
                        LoggingService.Log(response);
                        CreditCardService.New()
                            .Create({
                            nonce: response.nonce,
                            deviceData: self.deviceData()
                        }, function (result, error) {
                            if (error) {
                                LoggingService.Log({
                                    Result: "CC Error",
                                    Data: error
                                });
                                $("#card-alert").removeClass("hidden");
                                $("#card-alert").text(error.description);
                                self.isSubmitting(false);
                                LoaderService.StopOverlay();
                                $("#btn-confirm-pay").prop('disabled', false);
                            }
                            else if (result) {
                                CartService.New()
                                    .UpdateSingle(self.cart().id, "creditCardId", result.id);
                                LoggingService.Log({
                                    Result: "Success",
                                    Data: result
                                });
                                self.completeOrder();
                            }
                        });
                    }
                }
            });
            ko.computed(function () {
                self.updateCart();
                CartService.New().GetDetail(CartService.CartId(), function (result, error) {
                    if (result) {
                        self.cart(result);
                        self.giftMessage(result.giftMessage);
                        self.giftName(result.giftName);
                        if (result.cartItems && _.any(result.cartItems, function (item) { return item.isSubscription; })) {
                            self.recurringText("Your cart contains a subscription, these renew automatically but may be cancelled at any time.");
                        }
                        if (result.cartItems && result.cartItems.length > 0) {
                            var normalItems = _.filter(result.cartItems, function (cartItem) {
                                return !cartItem.isSubscription && cartItem.name.indexOf("Shipping") == -1 && cartItem.id != "00000000-0000-0000-0000-000000000000";
                            });
                            if (normalItems.length > 0) {
                                var min = _.sortBy(normalItems, 'shippingDate')[0];
                                self.shippingDate(min.shippingDate);
                            }
                            var subscriptionItems = _.filter(result.cartItems, function (cartItem) {
                                return cartItem.isSubscription && cartItem.name.indexOf("Shipping") == -1;
                            });
                            if (subscriptionItems.length > 0) {
                                var min = _.sortBy(subscriptionItems, 'shippingDate')[0];
                                self.shippingDateSubscription(min.shippingDate);
                            }
                        }
                        AddressService.New()
                            .GetDetail(result.addressId, function (address) {
                            self.address(address);
                        });
                        self.selectedCreditCard(result.creditCardId);
                    }
                });
            });
            ko.computed(function () {
                DogService.New()
                    .With("cartId", CartService.CartId())
                    .GetAll(function (result) {
                    if (result) {
                        self.dogs.removeAll();
                        _.each(result.data, function (dog) {
                            self.dogs.push(dog);
                        });
                    }
                });
                UserService.New()
                    .GetDetail("current", function (result) {
                    self.user(result);
                });
                CreditCardService.New()
                    .GetAll(function (result) {
                    self.creditCards.removeAll();
                    _.each(result.data, function (creditCard) {
                        self.creditCards.push(creditCard);
                    });
                    self.creditCardLoaded(true);
                    if (self.cart()) {
                        self.selectedCreditCard(self.cart().creditCardId);
                    }
                });
            });
            self.cartTotal = ko.computed(function () {
                var total = 0;
                if (self.cart() && self.cart().cartItems) {
                    _.each(self.cart().cartItems, function (item) {
                        total = total + item.price * item.quantity;
                    });
                }
                return total;
            });
            self.appliedPromoCode = ko.computed(function () {
                var cart = self.cart();
                if (cart) {
                    if (cart.promoCodes && cart.promoCodes.length > 0)
                        return cart.promoCodes[0];
                }
                return null;
            });
            self.removePromoCode = function (data, event) {
                StorageService.Clear("active-promocode");
                var l = Ladda.create(event.currentTarget);
                l.start();
                Utilities.ClearFormErrors();
                if (self.appliedPromoCode()) {
                    PromoCodeService.New()
                        .Delete(self.appliedPromoCode().id, function () {
                        l.stop();
                        self.updateCart.valueHasMutated();
                    });
                }
            };
            self.addPromoCode = function (data, event) {
                var l = Ladda.create(event.currentTarget);
                l.start();
                Utilities.ClearFormErrors();
                PromoCodeService.New()
                    .Create({
                    cartId: self.cart().id,
                    code: self.enteredPromoCode()
                }, function (result, error) {
                    if (error) {
                        notie.alert(3, error.description, 1.5);
                    }
                    else {
                        if (StorageService.Get("active-promocode")) {
                            StorageService.Store("active-promocode", result.promoCodeDefinition.code);
                        }
                    }
                    l.stop();
                    self.updateCart.valueHasMutated();
                });
            };
            self.submitForm = function (data, event) {
                var l = Ladda.create(event.currentTarget);
                l.start();
                Utilities.ClearFormErrors();
                var error = false;
                if (self.cartTotal() > 0) {
                    if (!self.selectedCreditCard()) {
                        $("#send-cc").click();
                    }
                    else {
                        LoaderService.StartOverlay("Fetching your order, woof!");
                        CartService.New()
                            .UpdateSingle(self.cart().id, "creditCardId", self.selectedCreditCard());
                        self.completeOrder();
                    }
                }
                else {
                    LoaderService.StartOverlay("Fetching your order, woof!");
                    self.completeOrder();
                }
                if (typeof ga == "function") {
                    ga('send', 'event', 'cart', 'confirm');
                }
                return false;
            };
            self.completeOrder = function () {
                StorageService.Clear("active-promocode");
                CartService.New()
                    .UpdateSingle(self.cart().id, "completed", "True", function (result) {
                    if (result) {
                        window.location.pathname = "/check-out/success/" + self.cart().id;
                        if (typeof ga == "function") {
                            ga('send', 'event', 'cart', 'submit-order', self.cart().id, self.cartTotal());
                        }
                    }
                    else {
                        LoaderService.StopOverlay();
                        Ladda.stopAll();
                        notie.alert(3, "Woops something went wrong, please try again!", 1.5);
                        if (typeof ga == "function") {
                            ga('send', 'event', 'cart', 'submit-order-fail', self.cart().id, self.cartTotal());
                        }
                    }
                });
            };
            return self;
        };
        return CheckoutConfirmModel;
    }());
    BarkBag.CheckoutConfirmModel = CheckoutConfirmModel;
})(BarkBag || (BarkBag = {}));
//# sourceMappingURL=BarkBag.CheckoutConfirmModel.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var BarkBag;
(function (BarkBag) {
    var CheckoutModel = /** @class */ (function (_super) {
        __extends(CheckoutModel, _super);
        function CheckoutModel() {
            var _this = _super !== null && _super.apply(this, arguments) || this;
            _this.currentPlan = ko.observable();
            _this.cart = ko.observable();
            _this.updateCart = ko.observable();
            _this.shippingDate = ko.observable();
            //Dog form fields
            _this.selectedDog = ko.observable();
            _this.selectedDogOther = ko.observable();
            _this.hasOtherDog = ko.observable(false);
            _this.dogName = ko.observable();
            _this.dogNameOther = ko.observable();
            _this.dogSize = ko.observable();
            _this.dogSizeOther = ko.observable();
            _this.dogBreed = ko.observable();
            _this.dogBreedOther = ko.observable();
            _this.dogPreferences = ko.observable();
            _this.dogPreferencesOther = ko.observable();
            _this.giftName = ko.observable();
            _this.giftMessage = ko.observable();
            _this.contactName = ko.observable();
            _this.contactNumber = ko.observable();
            _this.addresses = ko.observableArray();
            _this.selectedAddress = ko.observable();
            _this.addressStreet = ko.observable();
            _this.addressSuburb = ko.observable();
            _this.addressCity = ko.observable();
            _this.addressIsRural = ko.observable();
            _this.addressInstructions = ko.observable();
            _this.dogs = ko.observableArray();
            _this.productVariants = ko.observableArray();
            return _this;
        }
        CheckoutModel.prototype.createModel = function () {
            var self = this;
            ko.computed(function () {
                if (self.selectedDog() && self.selectedDogOther()) {
                    if (self.selectedDog() == self.selectedDogOther()) {
                        self.selectedDogOther("");
                        notie.alert(3, "That pup was already chosen so has been removed from the second slot.", 5);
                    }
                }
                //set dog info
                if (self.selectedDog()) {
                    var dog = _.find(self.dogs(), function (dog) {
                        if (dog.id == self.selectedDog())
                            return true;
                        return false;
                    });
                    if (dog) {
                        self.dogName(dog.name);
                        self.dogBreed(dog.breed);
                        if (dog.birthday) {
                            $("#dogBirthdayDay").val(moment.utc(dog.birthday).format('DD'));
                            $("#dogBirthdayMonth").val(moment.utc(dog.birthday).format('MM'));
                            $("#dogBirthdayYear").val(moment.utc(dog.birthday).format('YY'));
                        }
                        self.dogPreferences(dog.specialRequirements);
                        self.dogSize(dog.size);
                    }
                }
                if (self.selectedDogOther()) {
                    var dog = _.find(self.dogs(), function (dog) {
                        if (dog.id == self.selectedDogOther())
                            return true;
                        return false;
                    });
                    if (dog) {
                        self.dogNameOther(dog.name);
                        self.dogBreedOther(dog.breed);
                        if (dog.birthday) {
                            $("#dogBirthdayOtherDay").val(moment.utc(dog.birthday).format('DD'));
                            $("#dogBirthdayOtherMonth").val(moment.utc(dog.birthday).format('MM'));
                            $("#dogBirthdayOtherYear").val(moment.utc(dog.birthday).format('YY'));
                        }
                        self.dogPreferencesOther(dog.specialRequirements);
                        self.dogSizeOther(dog.size);
                    }
                }
            });
            ko.computed(function () {
                //set address info
                if (self.selectedAddress()) {
                    var address = _.find(self.addresses(), function (address) {
                        if (address.id == self.selectedAddress())
                            return true;
                        return false;
                    });
                    if (address) {
                        self.addressInstructions(address.instructions);
                        self.addressIsRural(address.isRuralDelivery);
                        self.addressStreet(address.street);
                        self.addressSuburb(address.suburb);
                        self.addressCity(address.city);
                    }
                }
            });
            self.shippingDateDaysAway = ko.computed(function () {
                return moment.utc(self.shippingDate()).diff(moment(), 'days');
            });
            ko.computed(function () {
                var cart = self.cart();
                if (self.productVariants().length == 0) {
                    self.productVariants.removeAll();
                    if (cart) {
                        var barkBag = _.find(cart.cartItems, function (item) { return item.isSubscription; });
                        if (barkBag) {
                            ProductVariantService.New()
                                .With("isSubscription", true)
                                .With("productId", barkBag.productVariant.productId)
                                .Get(0, 3, function (result) {
                                if (result) {
                                    for (var i = 0; i < result.data.length; i++)
                                        self.productVariants.push(result.data[i]);
                                }
                            });
                        }
                    }
                }
            });
            ko.computed(function () {
                self.updateCart();
                self.loading(true);
                var promises = new Array();
                var promise_01_cart = $.Deferred();
                promises.push(promise_01_cart);
                CartService.New().GetDetail(CartService.CartId(), function (result, error) {
                    if (result) {
                        self.cart(result);
                        self.giftMessage(result.giftMessage);
                        self.giftName(result.giftName);
                        if (result.cartItems && _.any(result.cartItems, function (item) { return item.isSubscription; })) {
                            var barkBag = _.find(result.cartItems, function (item) { return item.isSubscription; });
                            self.currentPlan(barkBag.productVariantId);
                            self.shippingDate(barkBag.shippingDate);
                        }
                        if (result.cartDogs) {
                            if (result.cartDogs.length > 0) {
                                self.selectedDog(result.cartDogs[0].id);
                            }
                            if (result.cartDogs.length > 1) {
                                self.hasOtherDog(true);
                                self.selectedDogOther(result.cartDogs[1].id);
                            }
                        }
                        if (result.addressId)
                            self.selectedAddress(result.addressId);
                    }
                    promise_01_cart.resolve();
                });
                if ($("#can-add-dog").val() == "True") {
                    var promise_02_dog = $.Deferred();
                    promises.push(promise_02_dog);
                    DogService.New()
                        .With("ownDogs", $("#isFriendsDog").val() == "False")
                        .GetAll(function (result) {
                        self.dogs.removeAll();
                        _.each(result.data, function (dog) {
                            self.dogs.push(dog);
                        });
                        if (self.cart()) {
                            if (self.cart().cartDogs) {
                                if (self.cart().cartDogs.length > 0) {
                                    self.selectedDog(self.cart().cartDogs[0].id);
                                }
                                if (self.cart().cartDogs.length > 1) {
                                    self.hasOtherDog(true);
                                    self.selectedDogOther(self.cart().cartDogs[1].id);
                                }
                            }
                        }
                        promise_02_dog.resolve();
                    });
                }
                var promise_03_user = $.Deferred();
                promises.push(promise_03_user);
                UserService.New()
                    .GetDetail("current", function (result) {
                    self.contactName(result.name);
                    self.contactNumber(result.mobile);
                    promise_03_user.resolve();
                });
                var promise_04_address = $.Deferred();
                promises.push(promise_04_address);
                AddressService.New()
                    .With("ownAddress", $("#isFriendsDog").val() == "False")
                    .GetAll(function (result) {
                    self.addresses.removeAll();
                    _.each(result.data, function (dog) {
                        self.addresses.push(dog);
                    });
                    if (self.cart()) {
                        if (self.cart().addressId) {
                            self.selectedAddress(self.cart().addressId);
                        }
                    }
                    promise_04_address.resolve();
                });
                $.when.apply($, promises).then(function () {
                    self.loading(false);
                    self.pageReady(true);
                });
            });
            self.canAddOneOff = ko.computed(function () {
                var cart = self.cart();
                if (cart) {
                    var barkBag = _.find(cart.cartItems, function (item) { return item.isSubscription; });
                    if (barkBag) {
                        var introBarkBag = _.find(cart.cartItems, function (item) { return item.productVariantId == Constants.EXTRA_ONE_OFF_PRODUCT_VARIANT_ID; });
                        if (moment.utc(barkBag.shippingDate) > moment().add("days", 8) && introBarkBag == null) {
                            return true;
                        }
                    }
                    return false;
                }
            });
            ko.computed(function () {
                var currentPlan = self.currentPlan();
                if (currentPlan) {
                    if (self.cart() && self.cart().cartItems && _.any(self.cart().cartItems, function (item) { return item.isSubscription; })) {
                        var cartItem = _.find(self.cart().cartItems, function (item) { return item.isSubscription; });
                        if (cartItem.productVariantId != currentPlan) {
                            self.loading(true);
                            CartItemService.New()
                                .UpdateSingle(cartItem.id, "productVariantId", currentPlan, function () {
                                self.loading(false);
                                self.updateCart.valueHasMutated();
                            });
                        }
                    }
                }
            });
            self.addIntroBarkBag = function (data, event) {
                var cart = self.cart();
                if (cart) {
                    if (self.canAddOneOff()) {
                        var l = Ladda.create(event.currentTarget);
                        l.start();
                        self.loading(true);
                        CartItemService.New()
                            .Create({
                            cartId: self.cart().id,
                            productVariantId: Constants.EXTRA_ONE_OFF_PRODUCT_VARIANT_ID
                        }, function () {
                            self.loading(false);
                            l.stop();
                            self.updateCart.valueHasMutated();
                        });
                    }
                }
            };
            self.removeCartItem = function (id) {
                CartItemService.New()
                    .Delete(id, function () {
                    self.updateCart.valueHasMutated();
                });
            };
            self.cartTotal = ko.computed(function () {
                var total = 0;
                if (self.cart() && self.cart().cartItems) {
                    _.each(self.cart().cartItems, function (item) {
                        total = total + item.price * item.quantity;
                    });
                }
                return total;
            });
            self.submitForm = function (data, event) {
                var l = Ladda.create(event.currentTarget);
                l.start();
                if ($("#dogBirthdayYear").val() && $("#dogBirthdayYear").val().length == 4)
                    $("#dogBirthdayYear").val($("#dogBirthdayYear").val().slice(2));
                if ($("#dogBirthdayOtherYear").val() && $("#dogBirthdayOtherYear").val().length == 4)
                    $("#dogBirthdayOtherYear").val($("#dogBirthdayOtherYear").val().slice(2));
                Utilities.ClearFormErrors();
                var error = false;
                var description = "your ";
                if ($("#can-add-dog").val() == "True") {
                    if (self.dogName() == null || self.dogName().length == 0) {
                        Utilities.ApplyFormError("dogName", "Please let us know who we're packing the bag for");
                        error = true;
                        description += "dog's name, ";
                    }
                    if (self.hasOtherDog() && (self.dogNameOther() == null || self.dogNameOther().length == 0)) {
                        Utilities.ApplyFormError("dogName2", "Please let us know who we're packing the bag for");
                        error = true;
                        description += "second dog's name, ";
                    }
                }
                if (self.addressStreet() == null || self.addressStreet().length == 0) {
                    Utilities.ApplyFormError("street", "Where are we delivering the package to");
                    error = true;
                    description += "street address, ";
                }
                if (self.addressCity() == null || self.addressCity().length == 0) {
                    Utilities.ApplyFormError("city", "Which city or town are we delivering to");
                    error = true;
                    description += "city, ";
                }
                description = description.substring(0, description.length - 2);
                var cart = self.cart();
                var promises = new Array();
                if (error) {
                    l.stop();
                    notie.alert(3, "Woops! Please enter " + description + ".", 1.5);
                }
                else if (cart) {
                    var promise_01_dog = $.Deferred();
                    promises.push(promise_01_dog);
                    var promise_02_dog = $.Deferred();
                    promises.push(promise_02_dog);
                    console.log("Adding dogs");
                    //remove all existing cart dogs
                    CartDogService.New()
                        .Delete(cart.id, function () {
                        var dogBirthday = null;
                        if ($("#dogBirthdayDay").val() && $("#dogBirthdayMonth").val() && $("#dogBirthdayYear").val())
                            dogBirthday = moment($("#dogBirthdayDay").val() + "/" + $("#dogBirthdayMonth").val() + "/" + $("#dogBirthdayYear").val(), "DD/MM/YY").format("YYYY/MM/DD");
                        if (dogBirthday == 'Invalid date')
                            dogBirthday = null;
                        console.log("Dog callback");
                        if ($("#can-add-dog").val() == "True") {
                            console.log("Dog can add");
                            if (!self.selectedDog() || self.selectedDog().length == 0) {
                                DogService.New()
                                    .Create({
                                    name: self.dogName(),
                                    breed: self.dogBreed(),
                                    size: self.dogSize(),
                                    specialRequirements: self.dogPreferences(),
                                    birthday: dogBirthday,
                                    isFriendsDog: $("#isFriendsDog").val() == "True"
                                }, function (result) {
                                    CartDogService.New()
                                        .Create({
                                        dogId: result.id,
                                        cartId: cart.id
                                    }, function (result) {
                                        promise_01_dog.resolve();
                                    });
                                });
                            }
                            else {
                                DogService.New()
                                    .Update(self.selectedDog(), {
                                    name: self.dogName(),
                                    breed: self.dogBreed(),
                                    size: self.dogSize(),
                                    specialRequirements: self.dogPreferences(),
                                    birthday: dogBirthday
                                }, function (result) {
                                    CartDogService.New()
                                        .Create({
                                        dogId: self.selectedDog(),
                                        cartId: cart.id
                                    }, function (result) {
                                        promise_01_dog.resolve();
                                    });
                                });
                            }
                            ;
                            if (self.hasOtherDog()) {
                                var dogBirthday2 = null;
                                if ($("#dogBirthdayOtherDay").val() && $("#dogBirthdayOtherMonth").val() && $("#dogBirthdayOtherYear").val())
                                    dogBirthday2 = moment($("#dogBirthdayOtherDay").val() + "/" + $("#dogBirthdayOtherMonth").val() + "/" + $("#dogBirthdayOtherYear").val(), "DD/MM/YY").format("YYYY/MM/DD");
                                if (dogBirthday2 == 'Invalid date')
                                    dogBirthday2 = null;
                                if (!self.selectedDogOther() || self.selectedDogOther().length == 0) {
                                    DogService.New()
                                        .Create({
                                        name: self.dogNameOther(),
                                        breed: self.dogBreedOther(),
                                        size: self.dogSizeOther(),
                                        specialRequirements: self.dogPreferencesOther(),
                                        birthday: dogBirthday2,
                                        isFriendsDog: $("#isFriendsDog").val() == "True"
                                    }, function (result) {
                                        CartDogService.New()
                                            .Create({
                                            dogId: result.id,
                                            cartId: cart.id
                                        }, function (result) {
                                            promise_02_dog.resolve();
                                        });
                                    });
                                }
                                else {
                                    DogService.New()
                                        .Update(self.selectedDogOther(), {
                                        name: self.dogNameOther(),
                                        breed: self.dogBreedOther(),
                                        size: self.dogSizeOther(),
                                        specialRequirements: self.dogPreferencesOther(),
                                        birthday: dogBirthday2
                                    }, function (result) {
                                        CartDogService.New()
                                            .Create({
                                            dogId: self.selectedDogOther(),
                                            cartId: cart.id
                                        }, function (result) {
                                            promise_02_dog.resolve();
                                        });
                                    });
                                }
                            }
                            else {
                                promise_02_dog.resolve();
                            }
                        }
                        else {
                            promise_01_dog.resolve();
                            promise_02_dog.resolve();
                            console.log("Resolving dogs");
                        }
                    });
                    //update user
                    var promise_03_user = $.Deferred();
                    promises.push(promise_03_user);
                    UserService.New()
                        .Update("current", {
                        "name": self.contactName(),
                        "mobile": self.contactNumber()
                    }, function (result) {
                        promise_03_user.resolve();
                    });
                    if ($("#isFriendsDog").val() == "True") {
                        var promise_04_friend = $.Deferred();
                        promises.push(promise_04_friend);
                        CartService.New().Update(cart.id, {
                            giftMessage: self.giftMessage(),
                            giftName: self.giftName()
                        }, function (result) {
                            promise_04_friend.resolve();
                        });
                    }
                    var promise_05_address = $.Deferred();
                    promises.push(promise_05_address);
                    if (!self.selectedAddress() || self.selectedAddress().length == 0) {
                        AddressService.New()
                            .Create({
                            street: self.addressStreet(),
                            suburb: self.addressSuburb(),
                            city: self.addressCity(),
                            isRuralDelivery: self.addressIsRural(),
                            instructions: self.addressInstructions()
                        }, function (result) {
                            CartService.New()
                                .Update(cart.id, {
                                addressId: result.id
                            }, function (result) {
                                promise_05_address.resolve();
                            });
                        });
                    }
                    else {
                        AddressService.New()
                            .Update(self.selectedAddress(), {
                            street: self.addressStreet(),
                            suburb: self.addressSuburb(),
                            city: self.addressCity(),
                            isRuralDelivery: self.addressIsRural(),
                            instructions: self.addressInstructions()
                        }, function (result) {
                            CartService.New()
                                .Update(cart.id, {
                                addressId: self.selectedAddress()
                            }, function (result) {
                                promise_05_address.resolve();
                            });
                        });
                    }
                    $.when.apply($, promises).then(function () {
                        console.log("resolved");
                        if (typeof ga == "function") {
                            ga('send', 'event', 'cart', 'confirm-details', self.cart().id, self.cartTotal());
                        }
                        window.location.pathname = "/check-out/confirm";
                    });
                    if (typeof ga == "function") {
                        ga('send', 'event', 'cart', 'details');
                    }
                }
                else {
                    l.stop();
                    self.updateCart.valueHasMutated();
                    notie.alert(3, "Woops! Something went wrong. Please try again.", 1.5);
                }
                return false;
            };
            return self;
        };
        return CheckoutModel;
    }(BindablePageModel));
    BarkBag.CheckoutModel = CheckoutModel;
})(BarkBag || (BarkBag = {}));
//# sourceMappingURL=BarkBag.CheckoutModel.js.map;
var BarkBag;
(function (BarkBag) {
    var ChooseFavsModel = /** @class */ (function () {
        function ChooseFavsModel() {
            this.loadingState = ko.observable(Constants.STATE_INITIAL);
            this.update = ko.observable(0);
        }
        ChooseFavsModel.prototype.createModel = function () {
            var self = this;
            $("input").change(function () {
                self.update.valueHasMutated();
            });
            self.favs = ko.computed(function () {
                self.update();
                var flags = 0;
                for (var i = 0; i < $("input:checked").length; i++)
                    flags = flags | $($("input:checked")[i]).val();
                return flags;
            });
            return self;
        };
        return ChooseFavsModel;
    }());
    BarkBag.ChooseFavsModel = ChooseFavsModel;
})(BarkBag || (BarkBag = {}));
//# sourceMappingURL=BarkBag.ChooseFavsModel.js.map;
var BarkBag;
(function (BarkBag) {
    var ContactUsModel = /** @class */ (function () {
        function ContactUsModel() {
            this.loadingState = ko.observable(Constants.STATE_INITIAL);
            this.email = ko.observable();
            this.message = ko.observable();
        }
        ContactUsModel.prototype.createModel = function () {
            var self = this;
            self.submitForm = function (data, event) {
                var l = Ladda.create(event.currentTarget);
                l.start();
                ContactService.New().Create({
                    email: self.email(),
                    message: self.message()
                }, function (result, error) {
                    l.stop();
                    if (error) {
                        Utilities.ApplyFormErrors(error);
                        notie.alert(3, "Woops! Something went wrong. Please check everything is correct.", 1.5);
                    }
                    else {
                        self.email("");
                        self.message("");
                        notie.alert(1, "Thanks, we'll be in touch soon!", 1.5);
                    }
                    if (typeof ga == "function") {
                        ga('send', 'event', 'contact-us', 'message');
                    }
                });
            };
            return self;
        };
        return ContactUsModel;
    }());
    BarkBag.ContactUsModel = ContactUsModel;
})(BarkBag || (BarkBag = {}));
//# sourceMappingURL=BarkBag.ContactUsModel.js.map;
var BarkBag;
(function (BarkBag) {
    var FBSignInModel = /** @class */ (function () {
        function FBSignInModel() {
            this.isError = ko.observable(false);
            this.error = ko.observable();
        }
        FBSignInModel.prototype.createModel = function () {
            var self = this;
            var code = Utilities.GetUrlParam("code", window.location);
            var returnUrl = $("#returnUrl").val();
            var state = Utilities.GetUrlParam("state", window.location);
            self.error(Utilities.GetUrlParam("error", window.location));
            if (self.error()) {
                self.isError(true);
            }
            else {
                self.isError(false);
            }
            if (!self.isError()) {
                AuthenticationService.GetNewTokenWithFBCode(code, state, function (result) {
                    if (result) {
                        if (typeof ga == "function") {
                            ga('send', 'event', 'register', 'signin', 'facebook');
                        }
                        window.location.href = returnUrl;
                    }
                    else {
                        $("#sign-in-error-fb").text();
                        $("#sign-in-error-fb").show();
                        if (typeof ga == "function") {
                            ga('send', 'event', 'register', 'signin-error', 'facebook');
                        }
                        window.location.href = "/external/facebook?error=" + encodeURI("We could not sign you in using Facebook, please use the email option.");
                    }
                });
            }
            return self;
        };
        return FBSignInModel;
    }());
    BarkBag.FBSignInModel = FBSignInModel;
})(BarkBag || (BarkBag = {}));
//# sourceMappingURL=BarkBag.FBSignInModel.js.map;
var BarkBag;
(function (BarkBag) {
    var ForgotPasswordModel = /** @class */ (function () {
        function ForgotPasswordModel() {
            this.loadingState = ko.observable(Constants.STATE_INITIAL);
            this.email = ko.observable();
        }
        ForgotPasswordModel.prototype.createModel = function () {
            var self = this;
            self.submitForm = function (data, event) {
                $("#reset-error").hide();
                var l = Ladda.create(event.currentTarget);
                l.start();
                PasswordResetTokenService.New().Create({ email: self.email() }, function (result) {
                    l.stop();
                    if (result) {
                        window.location.pathname = "/password/forgotten/successful";
                        if (typeof ga == "function") {
                            ga('send', 'event', 'password-reset', 'start');
                        }
                    }
                    else {
                        notie.alert(3, "Woops! Something went wrong. Please check everything is correct.", 1.5);
                        $("#reset-error").text("That email does not exist.");
                        $("#reset-error").show();
                        if (typeof ga == "function") {
                            ga('send', 'event', 'password-reset', 'start-fail');
                        }
                    }
                });
            };
            return self;
        };
        return ForgotPasswordModel;
    }());
    BarkBag.ForgotPasswordModel = ForgotPasswordModel;
})(BarkBag || (BarkBag = {}));
//# sourceMappingURL=BarkBag.ForgotPasswordModel.js.map;
var BarkBag;
(function (BarkBag) {
    var LandingPageModel = /** @class */ (function () {
        function LandingPageModel() {
            this.loadingState = ko.observable(Constants.STATE_INITIAL);
            this.cart = ko.observable();
        }
        LandingPageModel.prototype.createModel = function () {
            var self = this;
            ko.computed(function () {
                Constants.GLOBAL_REFRESH();
                CartService.New()
                    .GetDetail(CartService.CartId(), function (result) {
                    self.loadingState(Constants.STATE_READY);
                    if (result) {
                        self.cart(result);
                        if (self.cart() && self.cart().cartItems) {
                            var currentItem = _.find(self.cart().cartItems, function (cartItem) {
                                return cartItem.productId == $("#product-id").val();
                            });
                        }
                    }
                });
            });
            self.addToCart = function (data, event) {
                var l = Ladda.create(event.currentTarget);
                l.start();
                var pvid = $(event.currentTarget).data("productvariantid");
                CartService.New()
                    .UpdateSingle(self.cart().id, "isGift", $(event.currentTarget).data("isgift"), function () {
                    CartItemService.New()
                        .Create({
                        cartId: self.cart().id,
                        productVariantId: pvid,
                        quantity: 1,
                        clear: true
                    }, function (result) {
                        Constants.GLOBAL_REFRESH.valueHasMutated();
                        document.location.pathname = "/view/cart";
                        Ladda.stopAll();
                    });
                });
                if (typeof ga == "function") {
                    ga('send', 'event', 'cart', 'add', pvid, $(event.currentTarget).data("price"));
                }
                return false;
            };
            return self;
        };
        return LandingPageModel;
    }());
    BarkBag.LandingPageModel = LandingPageModel;
})(BarkBag || (BarkBag = {}));
//# sourceMappingURL=BarkBag.LandingPage.js.map;
var BarkBag;
(function (BarkBag) {
    var NewsletterModel = /** @class */ (function () {
        function NewsletterModel() {
            this.loadingState = ko.observable(Constants.STATE_INITIAL);
            this.email = ko.observable();
        }
        NewsletterModel.prototype.createModel = function () {
            var self = this;
            self.submitForm = function (data, event) {
                var l = Ladda.create(event.currentTarget);
                l.start();
                Utilities.ClearFormErrors();
                NewsletterService.New().Create({
                    email: self.email()
                }, function (result, error) {
                    l.stop();
                    self.email("");
                    notie.alert(1, "Thanks and welcome to the pack!", 1.5);
                    if (typeof ga == "function") {
                        ga('send', 'event', 'register', 'newsletter-signup', 'email');
                    }
                });
            };
            return self;
        };
        return NewsletterModel;
    }());
    BarkBag.NewsletterModel = NewsletterModel;
})(BarkBag || (BarkBag = {}));
//# sourceMappingURL=BarkBag.NewsletterModel.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var BarkBag;
(function (BarkBag) {
    var OrderSuccessModel = /** @class */ (function (_super) {
        __extends(OrderSuccessModel, _super);
        function OrderSuccessModel() {
            var _this = _super !== null && _super.apply(this, arguments) || this;
            _this.cart = ko.observable();
            _this.order = ko.observable();
            _this.numberOfSuccessfulCarts = ko.observable();
            return _this;
        }
        OrderSuccessModel.prototype.createModel = function () {
            var self = this;
            if (typeof ga == "function") {
                ga('require', 'ecommerce');
            }
            //DOUBLE PROMISE
            var promises = new Array();
            var promise_01_orderdetail = $.Deferred();
            promises.push(promise_01_orderdetail);
            var promise_02_cartdetail = $.Deferred();
            promises.push(promise_02_cartdetail);
            $.when.apply($, promises).then(function () {
                self.pageReady(true);
                self.loading(false);
            });
            ko.computed(function () {
                CartService.New().GetDetail($("#cart-id-success").val(), function (result, error) {
                    if (result) {
                        self.cart(result);
                        OrderService.New()
                            .GetDetail("cart/" + self.cart().id, function (result, error) {
                            self.order(result);
                            if (typeof ga == "function") {
                                ga('send', 'event', 'order', 'success', self.order().id, self.cartTotal());
                                ga('ecommerce:addTransaction', {
                                    'id': self.order().id,
                                    'affiliation': 'Bark Bag',
                                    'revenue': self.cartTotal(),
                                    'shipping': self.cartTotal() > 30 ? 0 : 5,
                                    'tax': (self.cartTotal() - (self.cartTotal() / 1.15))
                                });
                                _.each(self.cart().cartItems, function (item) {
                                    ga('ecommerce:addItem', {
                                        'id': self.order().id,
                                        'name': item.name,
                                        'price': item.price,
                                        'quantity': item.quantity
                                    });
                                });
                                ga('ecommerce:send');
                                if (typeof gtag == "function") {
                                    gtag('event', 'conversion', {
                                        'send_to': 'AW-852122229/W0uZCO_f8nEQ9bSplgM',
                                        'value': self.cartTotal(),
                                        'currency': 'NZD'
                                    });
                                }
                            }
                            if (typeof fbq == "function") {
                                fbq('track', 'Purchase', { 'value': self.cartTotal(), 'currency': 'NZD' });
                            }
                            promise_01_orderdetail.resolve();
                        });
                    }
                    else {
                        promise_01_orderdetail.resolve();
                    }
                });
                CartService.New()
                    .With("isCompleted", true)
                    .Get(0, 0, function (result) {
                    self.numberOfSuccessfulCarts(result.total);
                    promise_02_cartdetail.resolve();
                });
            });
            self.cartTotal = ko.computed(function () {
                var total = 0;
                if (self.cart() && self.cart().cartItems) {
                    _.each(self.cart().cartItems, function (item) {
                        total = total + item.price * item.quantity;
                    });
                }
                return total;
            });
            return self;
        };
        return OrderSuccessModel;
    }(BindablePageModel));
    BarkBag.OrderSuccessModel = OrderSuccessModel;
})(BarkBag || (BarkBag = {}));
//# sourceMappingURL=BarkBag.OrderSuccessModel.js.map;
var BarkBag;
(function (BarkBag) {
    var ProductDetailsModel = /** @class */ (function () {
        function ProductDetailsModel() {
            this.loadingState = ko.observable(Constants.STATE_INITIAL);
            this.productVariants = ko.observableArray();
            this.selectedProductVariantId = ko.observable();
            this.cart = ko.observable();
        }
        ProductDetailsModel.prototype.createModel = function () {
            var self = this;
            ko.computed(function () {
                ProductVariantService.New()
                    .With("productId", $("#product-id").val())
                    .GetAll(function (result) {
                    if (result) {
                        for (var i = 0; i < result.data.length; i++)
                            self.productVariants.push(result.data[i]);
                    }
                });
            });
            self.selectedProductVariant = ko.computed(function () {
                var id = self.selectedProductVariantId();
                if (id) {
                    return _.find(self.productVariants(), function (item) {
                        return item.id == id;
                    });
                }
            });
            ko.computed(function () {
                Constants.GLOBAL_REFRESH();
                CartService.New()
                    .GetDetail(CartService.CartId(), function (result) {
                    self.loadingState(Constants.STATE_READY);
                    if (result) {
                        self.cart(result);
                        if (self.cart() && self.cart().cartItems) {
                            var currentItem = _.find(self.cart().cartItems, function (cartItem) {
                                return cartItem.productId == $("#product-id").val();
                            });
                        }
                    }
                });
            });
            self.addToCart = function (data, event) {
                var l = Ladda.create(event.currentTarget);
                l.start();
                CartItemService.New()
                    .Create({
                    cartId: self.cart().id,
                    productId: self.selectedProductVariant().productId,
                    productVariantId: self.selectedProductVariant().id,
                    quantity: self.selectedProductVariant().isSubscription ? 1 : $("#quantity").val(),
                    frequency: self.selectedProductVariant().isSubscription ? $("#frequency").val() : null
                }, function (result) {
                    if (result) {
                        notie.alert(1, "Puptasitc!! We've added that to your cart.", 1.5);
                    }
                    else {
                        notie.alert(3, "Woops - something went wront. Please try again.", 1.5);
                    }
                    Constants.GLOBAL_REFRESH.valueHasMutated();
                    Ladda.stopAll();
                });
                if (typeof ga == "function") {
                    ga('send', 'event', 'cart', 'add', self.selectedProductVariantId(), self.selectedProductVariant().price);
                }
                return false;
            };
            return self;
        };
        return ProductDetailsModel;
    }());
    BarkBag.ProductDetailsModel = ProductDetailsModel;
})(BarkBag || (BarkBag = {}));
//# sourceMappingURL=BarkBag.ProductDetailsModel.js.map;
var BarkBag;
(function (BarkBag) {
    var ProductSingleVariantModel = /** @class */ (function () {
        function ProductSingleVariantModel() {
            this.loadingState = ko.observable(Constants.STATE_INITIAL);
            this.frequency = ko.observable("monthly");
            this.monthMultiplier = ko.observable(1);
            this.cart = ko.observable();
        }
        ProductSingleVariantModel.prototype.createModel = function () {
            var self = this;
            ko.computed(function () {
                var freq = self.frequency();
                self.monthMultiplier(freq == "monthly" ? 1 : 2);
            });
            ko.computed(function () {
                Constants.GLOBAL_REFRESH();
                CartService.New()
                    .GetDetail(CartService.CartId(), function (result) {
                    self.loadingState(Constants.STATE_READY);
                    if (result) {
                        self.cart(result);
                    }
                });
            });
            self.subscribe = function (data, event) {
                var l = Ladda.create(event.currentTarget);
                l.start();
                CartItemService.New()
                    .Create({
                    cartId: self.cart().id,
                    productVariantId: $("#product-variant-id").val(),
                    quantity: 1,
                    frequency: self.frequency(),
                    clear: true
                }, function (result) {
                    Constants.GLOBAL_REFRESH.valueHasMutated();
                    l.stop();
                    document.location.pathname = "/fetch/favourites";
                });
                return false;
            };
            self.buy = function (data, event) {
                var message = $(event.currentTarget).data("warning");
                if (message) {
                    alertify.confirm(message, function () { self.confirmBuy(data, event); });
                }
                else {
                    return self.confirmBuy(data, event);
                }
                return false;
            };
            self.confirmBuy = function (data, event) {
                var l = Ladda.create(event.currentTarget);
                l.start();
                var isGift = "False";
                if ($(event.currentTarget).data("gift"))
                    isGift = $(event.currentTarget).data("gift");
                CartService.New()
                    .UpdateSingle(self.cart().id, "isGift", isGift, function () {
                    CartItemService.New()
                        .Create({
                        cartId: self.cart().id,
                        productVariantId: $("#product-variant-id").val(),
                        quantity: $("#quantity").val(),
                        frequency: "once-off",
                        clear: ($(event.currentTarget).data("clear") == "true") ? true : false
                    }, function (result) {
                        Constants.GLOBAL_REFRESH.valueHasMutated();
                        l.stop();
                        document.location.pathname = "/fetch/favourites";
                    });
                });
                return false;
            };
            return self;
        };
        return ProductSingleVariantModel;
    }());
    BarkBag.ProductSingleVariantModel = ProductSingleVariantModel;
})(BarkBag || (BarkBag = {}));
//# sourceMappingURL=BarkBag.ProductSingleVariantModel.js.map;
var BarkBag;
(function (BarkBag) {
    var RateBag = /** @class */ (function () {
        function RateBag() {
        }
        RateBag.prototype.createModel = function () {
            var self = this;
            self.updateRating = function (t, e) {
                BagItemService.New()
                    .Update($(e.target).attr('name'), {
                    rating: $(e.target).val()
                });
                $("#" + $(e.target).attr('name')).removeClass('hidden');
                if (typeof ga == "function") {
                    ga('send', 'event', 'rate', 'bagitem');
                }
                return true;
            };
            self.updateFeedback = function (t, e) {
                BagItemService.New()
                    .Update($(e.target).parents('tr').attr('id'), {
                    feedback: $(e.target).val()
                });
                if (typeof ga == "function") {
                    ga('send', 'event', 'rate', 'feedback');
                }
                return true;
            };
            return self;
        };
        return RateBag;
    }());
    BarkBag.RateBag = RateBag;
})(BarkBag || (BarkBag = {}));
//# sourceMappingURL=BarkBag.RateBag.js.map;
var BarkBag;
(function (BarkBag) {
    var RegisterOrSignInModel = /** @class */ (function () {
        function RegisterOrSignInModel() {
            this.loadingState = ko.observable("register");
            this.email = ko.observable();
            this.password = ko.observable();
        }
        RegisterOrSignInModel.prototype.createModel = function () {
            var self = this;
            self.submitForm = function (data, event) {
                $("#sign-in-error").hide();
                var l = Ladda.create(event.currentTarget);
                l.start();
                if (self.loadingState() == 'sign-in') {
                    AuthenticationService.GetNewTokenWithCredentials(self.email(), self.password(), function (result) {
                        if (result) {
                            if (typeof ga == "function") {
                                ga('send', 'event', 'register', 'cart-signin', 'email');
                            }
                            window.location.reload(false);
                        }
                        else {
                            l.stop();
                            notie.alert(3, "Woops! Something went wrong. Please check everything is correct.", 1.5);
                            $("#sign-in-error").text("The email or password entered may be incorrect.");
                            $("#sign-in-error").show();
                            if (typeof ga == "function") {
                                ga('send', 'event', 'register', 'cart-signin-error', 'email');
                            }
                        }
                    });
                }
                else {
                    UserService.New().Create({
                        email: self.email(),
                        subscribed: $("#email-subscribed").is(':checked'),
                        authenticate: true,
                        source: "register"
                    }, function (result, error) {
                        if (result) {
                            if (typeof ga == "function") {
                                ga('send', 'event', 'register', 'cart-signup', 'email');
                            }
                            window.location.reload(false);
                        }
                        else {
                            l.stop();
                            Utilities.ApplyFormErrors(error);
                            notie.alert(3, "Woops! Something went wrong. Please check your email is correct.", 1.5);
                            if (typeof ga == "function") {
                                ga('send', 'event', 'register', 'cart-signup-error', 'email');
                            }
                        }
                    });
                }
            };
            return self;
        };
        return RegisterOrSignInModel;
    }());
    BarkBag.RegisterOrSignInModel = RegisterOrSignInModel;
})(BarkBag || (BarkBag = {}));
//# sourceMappingURL=BarkBag.RegisterOrSignInModel.js.map;
var BarkBag;
(function (BarkBag) {
    var ResetPasswordModel = /** @class */ (function () {
        function ResetPasswordModel() {
            this.loadingState = ko.observable(Constants.STATE_INITIAL);
            this.password = ko.observable();
            this.token = ko.observable($("#token").val());
        }
        ResetPasswordModel.prototype.createModel = function () {
            var self = this;
            self.submitForm = function (data, event) {
                $("#reset-error").hide();
                var l = Ladda.create(event.currentTarget);
                l.start();
                PasswordUpdateService.New().Create({ password: self.password(), token: self.token() }, function (result) {
                    l.stop();
                    if (result) {
                        window.location.pathname = "/password/choose/successful";
                        if (typeof ga == "function") {
                            ga('send', 'event', 'password-reset', 'success');
                        }
                    }
                    else {
                        notie.alert(3, "Woops! Something went wrong. Please check everything is correct.", 1.5);
                        $("#reset-error").text("Please enter a password");
                        $("#reset-error").show();
                        if (typeof ga == "function") {
                            ga('send', 'event', 'password-reset', 'fail');
                        }
                    }
                });
            };
            return self;
        };
        return ResetPasswordModel;
    }());
    BarkBag.ResetPasswordModel = ResetPasswordModel;
})(BarkBag || (BarkBag = {}));
//# sourceMappingURL=BarkBag.ResetPasswordModel.js.map;
var BarkBag;
(function (BarkBag) {
    var SignInModel = /** @class */ (function () {
        function SignInModel() {
            this.loadingState = ko.observable(Constants.STATE_INITIAL);
            this.email = ko.observable();
            this.password = ko.observable();
        }
        SignInModel.prototype.createModel = function () {
            var self = this;
            self.submitForm = function (data, event) {
                $("#sign-in-error").hide();
                var l = Ladda.create(event.currentTarget);
                l.start();
                AuthenticationService.GetNewTokenWithCredentials(self.email(), self.password(), function (result) {
                    l.stop();
                    if (result) {
                        if (typeof ga == "function") {
                            ga('send', 'event', 'register', 'signin', 'email');
                        }
                        window.location.pathname = $("#returnUrl").val();
                    }
                    else {
                        notie.alert(3, "Woops! Something went wrong. Please check everything is correct.", 1.5);
                        $("#sign-in-error").text("The email or password entered may be incorrect.");
                        $("#sign-in-error").show();
                        if (typeof ga == "function") {
                            ga('send', 'event', 'register', 'signin-error', 'email');
                        }
                    }
                });
            };
            return self;
        };
        return SignInModel;
    }());
    BarkBag.SignInModel = SignInModel;
})(BarkBag || (BarkBag = {}));
//# sourceMappingURL=BarkBag.SignInModel.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var Customer;
(function (Customer) {
    var Dashboard = /** @class */ (function (_super) {
        __extends(Dashboard, _super);
        function Dashboard() {
            var _this = _super !== null && _super.apply(this, arguments) || this;
            _this.failedTransaction = ko.observable();
            _this.user = ko.observable();
            _this.currentUserId = ko.observable(Utilities.Default(StorageService.Get("currentUserId"), "current")).extend({ deferred: true });
            _this.pendingOrders = ko.observableArray();
            _this.shipments = ko.observableArray()
                .extend({ deferred: true });
            _this.bags = ko.observableArray()
                .extend({ deferred: true });
            _this.upcomingShipments = ko.observableArray()
                .extend({ deferred: true });
            _this.plans = ko.observableArray()
                .extend({ deferred: true });
            _this.refreshShipments = ko.observable();
            return _this;
        }
        ;
        Dashboard.prototype.createModel = function () {
            var self = this;
            var promises = new Array();
            var promise_01_transactions = $.Deferred();
            promises.push(promise_01_transactions);
            var promise_02_userdetails = $.Deferred();
            promises.push(promise_02_userdetails);
            var promise_03_orders = $.Deferred();
            promises.push(promise_03_orders);
            var promise_04_plans = $.Deferred();
            promises.push(promise_04_plans);
            var promise_05_shipments = $.Deferred();
            promises.push(promise_05_shipments);
            var promise_06_bags = $.Deferred();
            promises.push(promise_06_bags);
            var promise_07_planshipments = $.Deferred();
            promises.push(promise_07_planshipments);
            $.when.apply($, promises).then(function () {
                self.loading(false);
                self.pageReady(true);
            });
            self.isPrepaid = function (shipment) {
                _.each(self.plans, function (plan) {
                    if (plan.id == shipment.planId) {
                        console.log("Plen");
                    }
                });
                return false;
            };
            self.skip = function (data, e) {
                var l = Ladda.create(e.currentTarget);
                l.start();
                PlanShipmentService.New()
                    .UpdateSingle(data.id, "skip", "true", function () {
                    self.refreshShipments.valueHasMutated();
                    l.stop();
                });
            };
            self.unskip = function (data, e) {
                var l = Ladda.create(e.currentTarget);
                l.start();
                PlanShipmentService.New()
                    .UpdateSingle(data.id, "skip", "false", function () {
                    self.refreshShipments.valueHasMutated();
                    l.stop();
                });
            };
            StorageService.Clear("active-promocode");
            self.resume = function (id) {
                var l = Ladda.create($("#" + id)[0]);
                l.start();
                PlanService.New()
                    .UpdateSingle(id, "resume", (new Date()).toISOString(), function () {
                    l.stop();
                    self.currentUserId.valueHasMutated();
                });
            };
            ko.computed(function () {
                var userId = self.currentUserId();
                StorageService.Store("currentUserId", userId);
                TransactionService.New()
                    .With("userId", userId)
                    .Sorted("created", "desc")
                    .Get(0, 1, function (result) {
                    if (result && result.data.length == 1)
                        self.failedTransaction(result.data[0]);
                    promise_01_transactions.resolve();
                });
                UserService.New().GetDetail(userId, function (result) {
                    if (result) {
                        self.user(result);
                        if (result.id != StorageService.Get("currentUserId"))
                            StorageService.Clear("currentUserId");
                    }
                    else {
                        StorageService.Clear("currentUserId");
                    }
                    promise_02_userdetails.resolve();
                });
                self.pendingOrders.removeAll();
                OrderService.New()
                    .With("userId", userId)
                    .With("isFulfilled", false)
                    .Get(0, 10, function (result) {
                    if (result) {
                        _.each(result.data, function (item) {
                            self.pendingOrders.push(item);
                        });
                    }
                    promise_03_orders.resolve();
                });
            });
            ko.computed(function () {
                var userId = self.currentUserId();
                var refresh = self.refreshShipments();
                PlanService.New()
                    .With("userId", userId)
                    .Get(0, 10, function (result) {
                    if (result) {
                        self.plans.removeAll();
                        _.each(result.data, function (item) {
                            self.plans.push(item);
                        });
                    }
                    promise_04_plans.resolve();
                });
            });
            ko.computed(function () {
                var userId = self.currentUserId();
                ShipmentService.New()
                    .With("userId", userId)
                    .With("report", "recent")
                    .GetAll(function (result) {
                    if (result) {
                        self.shipments.removeAll();
                        _.each(result.data, function (item) {
                            self.shipments.push(item);
                        });
                    }
                    promise_05_shipments.resolve();
                });
            });
            ko.computed(function () {
                var userId = self.currentUserId();
                BagService.New()
                    .With("userId", userId)
                    .With("isRated", "false")
                    .With("isShipped", "true")
                    .GetAll(function (result) {
                    if (result) {
                        self.bags.removeAll();
                        _.each(result.data, function (item) {
                            self.bags.push(item);
                        });
                    }
                    promise_06_bags.resolve();
                });
            });
            ko.computed(function () {
                var userId = self.currentUserId();
                var refresh = self.refreshShipments();
                PlanShipmentService.New()
                    .With("userId", userId)
                    .With("hasShipment", false)
                    .Get(0, 6, function (result) {
                    if (result) {
                        self.upcomingShipments.removeAll();
                        _.each(result.data, function (item) {
                            self.upcomingShipments.push(item);
                        });
                    }
                    promise_07_planshipments.resolve();
                });
            });
            ko.computed(function () {
                if (self.pageReady() && self.users == null) {
                    UserService.New().GetAll(function (result) {
                        if (result) {
                            self.users = _.map(result.data, function (item) {
                                return {
                                    id: item.id,
                                    text: item.name ? item.name + " (" + item.email + ")" : item.email
                                };
                            });
                            $(".js-select-user").select2({
                                data: self.users
                            });
                            $(".js-select-user").on("change", function () {
                                if (self.currentUserId() != $(".js-select-user").val())
                                    self.currentUserId($(".js-select-user").val());
                            });
                            $(".js-select-user option[value='" + self.currentUserId() + "']").attr("selected", "selected");
                            $(".js-select-user").trigger("change");
                        }
                    });
                }
            });
            return self;
        };
        return Dashboard;
    }(BindablePageModel));
    Customer.Dashboard = Dashboard;
})(Customer || (Customer = {}));
//# sourceMappingURL=Customer.Dashboard.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var Customer;
(function (Customer) {
    var OrderDetailsModel = /** @class */ (function (_super) {
        __extends(OrderDetailsModel, _super);
        function OrderDetailsModel() {
            var _this = _super !== null && _super.apply(this, arguments) || this;
            _this.orderId = ko.observable($("#id").val());
            _this.order = ko.observable();
            return _this;
        }
        OrderDetailsModel.prototype.createModel = function () {
            var self = this;
            self.loading(true);
            OrderService.New()
                .GetDetail(self.orderId(), function (result, error) {
                self.order(result);
                self.loading(false);
                self.pageReady(true);
            });
            self.total = ko.computed(function () {
                var total = 0;
                if (self.order() && self.order().orderLineItems) {
                    for (var i = 0; i < self.order().orderLineItems.length; i++)
                        total = total + self.order().orderLineItems[i].total;
                }
                return total;
            });
            return self;
        };
        return OrderDetailsModel;
    }(BindablePageModel));
    Customer.OrderDetailsModel = OrderDetailsModel;
})(Customer || (Customer = {}));
//# sourceMappingURL=Customer.OrderDetailsModel.js.map;
var Customer;
(function (Customer) {
    var PlanDetailsModel = /** @class */ (function () {
        function PlanDetailsModel() {
            this.loadingState = ko.observable(Constants.STATE_INITIAL);
            this.planId = ko.observable($("#id").val());
            this.plan = ko.observable();
            this.dogs = ko.observableArray()
                .extend({ deferred: true });
            this.currentUserId = ko.observable(Utilities.Default(StorageService.Get("currentUserId"), "current")).extend({ deferred: true });
            this.bags = ko.observableArray()
                .extend({ deferred: true });
            this.bagPage = ko.observable(0);
            this.bagTotal = ko.observable(0);
            this.refresh = ko.observable();
        }
        ;
        PlanDetailsModel.prototype.createModel = function () {
            var self = this;
            ko.computed(function () {
                self.refresh();
                PlanService.New()
                    .GetDetail(self.planId(), function (result, error) {
                    self.plan(result);
                    self.loadingState(Constants.STATE_READY);
                });
            });
            ko.computed(function () {
                self.refresh();
                var planId = self.planId();
                BagService.New()
                    .With("planId", planId)
                    .Sorted("ExpectedShipmentDate", "desc")
                    .Get(self.bagPage() * 5, 5, function (result) {
                    if (result) {
                        self.bags.removeAll();
                        _.each(result.data, function (item) {
                            self.bags.push(item);
                        });
                        self.bagTotal(result.total);
                    }
                });
            });
            ko.computed(function () {
                self.refresh();
                DogService.New()
                    .With("planId", self.planId())
                    .With("userId", self.currentUserId())
                    .GetAll(function (result) {
                    if (result) {
                        self.dogs.removeAll();
                        self.loadingState(Constants.STATE_READY);
                        _.each(result.data, function (item) {
                            self.dogs.push(item);
                        });
                    }
                });
            });
            self.addDog = function (e, t) {
                alertify.confirm("Which dog to add?", function () {
                    if (!$("#dogAdd").val()) {
                        document.location.pathname = "/customer/settings/dogs/add";
                    }
                    else {
                        PlanDogService.New().Create({
                            dogId: $("#dogAdd").val(),
                            planId: self.planId()
                        }, function () {
                            self.refresh.valueHasMutated();
                        });
                    }
                });
                DogService.New()
                    .With("excludePlanId", self.planId())
                    .With("userId", self.currentUserId())
                    .GetAll(function (result) {
                    if (result) {
                        var htmlText = '<select id="dogAdd" class="form-control"><option value="">Add new dog</option>';
                        for (var i = 0; i < result.data.length; i++) {
                            htmlText += '<option value="' + result.data[i].id + '">' + result.data[i].name + '</option>';
                        }
                        htmlText += '</select>';
                        $(htmlText).insertAfter(".alertify .msg");
                    }
                });
            };
            self.resume = function (e, t) {
                var l = Ladda.create(t.currentTarget);
                l.start();
                PlanService.New()
                    .UpdateSingle(self.planId(), "resume", (new Date()).toISOString(), function (result) {
                    l.stop();
                    self.refresh.valueHasMutated();
                    if (result)
                        notie.alert(1, "Woof! Plan resumed!", 1.5);
                });
            };
            self.pause = function (e, t) {
                alertify.confirm("How long do you want to pause this plan for?", function () {
                    var l = Ladda.create(t.currentTarget);
                    l.start();
                    if ($("#pauseLength").val() == "forever") {
                        l.stop();
                        alertify.confirm("To help us improve, could you please tell us why you're cancelling?", function () {
                            var reason = $("#cancelReason").val();
                            l.start();
                            PlanService.New()
                                .Update(self.planId(), {
                                paused: (new Date()).toISOString(),
                                resume: null,
                                cancelReason: reason
                            }, function () {
                                l.stop();
                                if (reason != "back-again" && reason != "dog-died" && reason != "cant-afford-it") {
                                    alertify.confirm("Can you please give us some feedback to help us improve 😊", function () {
                                        if ($("#cancelFeedback").val()) {
                                            PlanService.New()
                                                .Update(self.planId(), {
                                                cancelFeedback: $("#cancelFeedback").val()
                                            }, function () {
                                                l.stop();
                                                self.refresh.valueHasMutated();
                                            });
                                        }
                                    });
                                    $('<textarea id="cancelFeedback" class="form-control" rows="5"></textarea>').insertAfter(".alertify .msg");
                                }
                                self.refresh.valueHasMutated();
                            });
                        });
                        $('<select id="cancelReason" class="form-control">' +
                            '<option value="">Please select a reason</option>' +
                            '<option value="dog-died">🌈 My dog has crossed the rainbow bridge</option>' +
                            '<option value="back-again">😍 I love it, I\'ll be back for more later</option>' +
                            '<option value="too-many-treats">🍪 My dog has too many treats!</option>' +
                            '<option value="didnt-like-treats">🙊 My dog didn\'t like the treats</option>' +
                            '<option value="cant-afford-it">😊 I can\'t afford it right now</option>' +
                            '<option value="not-enough-value">😒 I don\'t think it was good value</option>' +
                            '<option value="other">😉 A different reason ("other")</option>' +
                            '</select>').insertAfter(".alertify .msg");
                    }
                    else {
                        var until = moment(new Date());
                        until.add($("#pauseLength").val(), 'months');
                        PlanService.New()
                            .Update(self.planId(), {
                            paused: (new Date()).toISOString(),
                            resume: until.toISOString()
                        }, function () {
                            l.stop();
                            self.refresh.valueHasMutated();
                        });
                    }
                });
                $('<select id="pauseLength" class="form-control">' +
                    '<option value="1">1 Month</option>' +
                    '<option value="2">2 Months</option>' +
                    '<option value="3">3 Months</option>' +
                    '<option value="4">4 Months</option>' +
                    '<option value="5">5 Months</option>' +
                    '<option value="6">6 Months</option>' +
                    '<option value="forever">Forever (cancel plan)</option>' +
                    '</select>').insertAfter(".alertify .msg");
            };
            self.changeFrequency = function (e, t) {
                alertify.confirm("How often would you like a Bark Bag?", function () {
                    PlanService.New()
                        .Update(self.planId(), {
                        frequency: $("#frequency").val()
                    }, function (result) {
                        self.refresh.valueHasMutated();
                        if (result)
                            notie.alert(1, "Woof! The frequenct of your plan has been updated!", 1.5);
                    });
                });
                $('<select id="frequency" class="form-control">' +
                    '<option ' + (self.plan().frequency == "monthly" ? "selected=selected" : "") + ' value="monthly">Monthly</option>' +
                    '<option ' + (self.plan().frequency == "bimonthly" ? "selected=selected" : "") + ' value="bimonthly">Bimonthly</option>' +
                    '</select>').insertAfter(".alertify .msg");
            };
            self.changePlanSize = function (e, t) {
                alertify.confirm("How many bags would you like to buy on renewal?", function () {
                    PlanService.New()
                        .Update(self.planId(), {
                        productVariantId: $("#productVariantId").val()
                    }, function (result) {
                        self.refresh.valueHasMutated();
                        if (result)
                            notie.alert(1, "Woof! The size of your plan has been updated!", 1.5);
                    });
                });
                ko.computed(function () {
                    ProductVariantService.New()
                        .With("isSubscription", true)
                        .With("productId", self.plan().productVariant.productId)
                        .Get(0, 3, function (result) {
                        var html = '<select id="productVariantId" class="form-control">';
                        if (result) {
                            for (var i = 0; i < result.data.length; i++)
                                html += '<option ' + (self.plan().productVariant.id == result.data[i].id ? "selected=selected" : "") + ' value="' + result.data[i].id + '">' + result.data[i].shippingUnits + ' at a time - $' + result.data[i].price + ' ($' + (result.data[i].price / result.data[i].shippingUnits) + ' /bag)</option>';
                        }
                        html += "</select>";
                        $(html).insertAfter(".alertify .msg");
                    });
                });
                $('' +
                    '' +
                    '<option value="bimonthly">Bimonthly</option>' +
                    '');
            };
            self.remove = function (id, e) {
                PlanDogService.New()
                    .Delete(self.planId() + "?dogId=" + id, function (result) {
                    self.refresh.valueHasMutated();
                });
            };
            return self;
        };
        return PlanDetailsModel;
    }());
    Customer.PlanDetailsModel = PlanDetailsModel;
})(Customer || (Customer = {}));
//# sourceMappingURL=Customer.PlanDetailsModel.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var Customer;
(function (Customer) {
    var SettingAddress = /** @class */ (function (_super) {
        __extends(SettingAddress, _super);
        function SettingAddress() {
            var _this = _super !== null && _super.apply(this, arguments) || this;
            _this.addresses = ko.observableArray();
            _this.currentUserId = ko.observable(Utilities.Default(StorageService.Get("currentUserId"), "current")).extend({ deferred: true });
            _this.refresh = ko.observable();
            return _this;
        }
        SettingAddress.prototype.createModel = function () {
            var self = this;
            ko.computed(function () {
                self.refresh();
                self.loading(true);
                self.addresses.removeAll();
                var userId = self.currentUserId();
                StorageService.Store("currentUserId", userId);
                AddressService.New()
                    .With("userId", userId)
                    .GetAll(function (result) {
                    if (result) {
                        _.each(result.data, function (item) {
                            self.addresses.push(item);
                        });
                    }
                    else {
                        StorageService.Clear("currentUserId");
                    }
                    self.loading(false);
                    self.pageReady(true);
                });
            });
            self.remove = function (id, e) {
                alertify.confirm("Are you sure you want to delete this address?", function () {
                    var l = Ladda.create(e.currentTarget).start();
                    self.loading(true);
                    AddressService.New()
                        .Delete(id, function () {
                        self.refresh.valueHasMutated();
                        l.stop();
                        self.loading(false);
                    });
                });
                return false;
            };
            return self;
        };
        return SettingAddress;
    }(BindablePageModel));
    Customer.SettingAddress = SettingAddress;
})(Customer || (Customer = {}));
//# sourceMappingURL=Customer.SettingAddress.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var Customer;
(function (Customer) {
    var SettingAddressEdit = /** @class */ (function (_super) {
        __extends(SettingAddressEdit, _super);
        function SettingAddressEdit() {
            var _this = _super !== null && _super.apply(this, arguments) || this;
            _this.street = ko.observable();
            _this.suburb = ko.observable();
            _this.city = ko.observable();
            _this.postCode = ko.observable();
            _this.isRural = ko.observable();
            _this.deliveryInstructions = ko.observable();
            _this.currentUserId = ko.observable(Utilities.Default(StorageService.Get("currentUserId"), "current")).extend({ deferred: true });
            _this.refresh = ko.observable();
            return _this;
        }
        SettingAddressEdit.prototype.createModel = function () {
            var self = this;
            ko.computed(function () {
                self.loading(true);
                AddressService.New()
                    .GetDetail($("#id").val(), function (model) {
                    self.street(model.street);
                    self.suburb(model.suburb);
                    self.city(model.city);
                    self.isRural(model.isRuralDelivery);
                    self.deliveryInstructions(model.instructions);
                    self.postCode(model.postCode);
                    self.loading(false);
                    self.pageReady(true);
                });
            });
            self.submitForm = function (data, event) {
                var l = Ladda.create(event.currentTarget);
                l.start();
                Utilities.ClearFormErrors();
                var error = false;
                var description = "your ";
                if (self.street() == null || self.street().length == 0) {
                    Utilities.ApplyFormError("street", "Where are we delivering the package to");
                    error = true;
                    description += "street address, ";
                }
                if (self.city() == null || self.city().length == 0) {
                    Utilities.ApplyFormError("city", "Which city or town are we delivering to");
                    error = true;
                    description += "city, ";
                }
                description = description.substring(0, description.length - 2);
                if (error) {
                    l.stop();
                    notie.alert(3, "Woops! Please enter " + description + ".", 1.5);
                }
                else {
                    AddressService.New()
                        .Update($("#id").val(), {
                        street: self.street(),
                        suburb: self.suburb(),
                        city: self.city(),
                        isRuralDelivery: self.isRural(),
                        postCode: self.postCode(),
                        instructions: self.deliveryInstructions()
                    }, function (result) {
                        window.location.pathname = "/customer/settings/shipping-address";
                    });
                }
            };
            return self;
        };
        return SettingAddressEdit;
    }(BindablePageModel));
    Customer.SettingAddressEdit = SettingAddressEdit;
})(Customer || (Customer = {}));
//# sourceMappingURL=Customer.SettingAddressEdit.js.map;
var Customer;
(function (Customer) {
    var SettingAddressNew = /** @class */ (function () {
        function SettingAddressNew() {
            this.loadingState = ko.observable(Constants.STATE_INITIAL);
            this.street = ko.observable();
            this.suburb = ko.observable();
            this.city = ko.observable();
            this.isRural = ko.observable();
            this.deliveryInstructions = ko.observable();
            this.currentUserId = ko.observable(Utilities.Default(StorageService.Get("currentUserId"), "current")).extend({ deferred: true });
            this.refresh = ko.observable();
        }
        SettingAddressNew.prototype.createModel = function () {
            var self = this;
            self.submitForm = function (data, event) {
                var l = Ladda.create(event.currentTarget);
                l.start();
                Utilities.ClearFormErrors();
                var error = false;
                var description = "your ";
                if (self.street() == null || self.street().length == 0) {
                    Utilities.ApplyFormError("street", "Where are we delivering the package to");
                    error = true;
                    description += "street address, ";
                }
                if (self.city() == null || self.city().length == 0) {
                    Utilities.ApplyFormError("city", "Which city or town are we delivering to");
                    error = true;
                    description += "city, ";
                }
                description = description.substring(0, description.length - 2);
                if (error) {
                    l.stop();
                    notie.alert(3, "Woops! Please enter " + description + ".", 1.5);
                }
                else {
                    AddressService.New()
                        .Create({
                        street: self.street(),
                        suburb: self.suburb(),
                        city: self.city(),
                        isRuralDelivery: self.isRural(),
                        instructions: self.deliveryInstructions(),
                        userId: self.currentUserId()
                    }, function (result) {
                        window.location.pathname = "/customer/settings/shipping-address";
                    });
                }
            };
            return self;
        };
        return SettingAddressNew;
    }());
    Customer.SettingAddressNew = SettingAddressNew;
})(Customer || (Customer = {}));
//# sourceMappingURL=Customer.SettingAddressNew.js.map;
var Customer;
(function (Customer) {
    var SettingCreditCardAdd = /** @class */ (function () {
        function SettingCreditCardAdd() {
            this.deviceData = ko.observable();
            this.isSubmitting = ko.observable(false);
            this.currentUserId = ko.observable(Utilities.Default(StorageService.Get("currentUserId"), "current")).extend({ deferred: true });
        }
        ;
        SettingCreditCardAdd.prototype.createModel = function () {
            var self = this;
            var md = new MobileDetect(window.navigator.userAgent);
            braintree.setup($("#ClientSideToken").val(), 'custom', {
                id: 'payment-container',
                dataCollector: {
                    kount: { environment: 'sandbox' }
                },
                hostedFields: {
                    styles: {
                        'input': {
                            'font-size': '1em',
                            'height': '40px'
                        }
                    },
                    number: {
                        selector: "#card-number"
                    },
                    cvv: {
                        selector: "#card-cvv"
                    },
                    expirationDate: {
                        selector: "#card-exp",
                        placeholder: md.phone() ? 'MMYY' : 'MM/YY'
                    }
                },
                onError: function (error) {
                    $("#btn-confirm-pay").prop('disabled', false);
                    LoaderService.StopOverlay();
                    $(".field-validation-error").addClass("hidden");
                    $("#card-alert").addClass("hidden");
                    if (error.type == "VALIDATION") {
                        $("#card-alert").removeClass("hidden");
                        $("#card-alert").text("We couldn't process your card, please check the details below are correct.");
                        if (error.details && error.details.invalidFieldKeys) {
                            for (var i = 0; i < error.details.invalidFieldKeys.length; i++) {
                                var field = error.details.invalidFieldKeys[i];
                                $("#group-" + field).find(".field-validation-error").removeClass("hidden");
                            }
                        }
                        Ladda.stopAll();
                    }
                },
                onReady: function (braintreeInstance) {
                    self.deviceData(braintreeInstance.deviceData);
                },
                onPaymentMethodReceived: function (response) {
                    if (!self.isSubmitting()) {
                        self.isSubmitting(true);
                        $(".field-validation-error").addClass("hidden");
                        $("#card-alert").addClass("hidden");
                        $("#btn-confirm-pay").prop('disabled', true);
                        LoaderService.StartOverlay("Adding card, woof!");
                        LoggingService.Log(response);
                        CreditCardService.New()
                            .Create({
                            nonce: response.nonce,
                            deviceData: self.deviceData(),
                            userId: self.currentUserId()
                        }, function (result, error) {
                            if (error) {
                                LoggingService.Log({
                                    Result: "CC Error",
                                    Data: error
                                });
                                $("#card-alert").removeClass("hidden");
                                $("#card-alert").text(error.description);
                                self.isSubmitting(false);
                                LoaderService.StopOverlay();
                                $("#btn-confirm-pay").prop('disabled', false);
                            }
                            else if (result) {
                                window.location.pathname = "/customer/settings/credit-card";
                            }
                        });
                    }
                }
            });
            self.submitForm = function (data, event) {
                var l = Ladda.create(event.currentTarget);
                l.start();
                Utilities.ClearFormErrors();
                var error = false;
                $("#send-cc").click();
                return false;
            };
            return self;
        };
        return SettingCreditCardAdd;
    }());
    Customer.SettingCreditCardAdd = SettingCreditCardAdd;
})(Customer || (Customer = {}));
//# sourceMappingURL=Customer.SettingCreditCardAdd.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var Customer;
(function (Customer) {
    var SettingCreditCardDetails = /** @class */ (function (_super) {
        __extends(SettingCreditCardDetails, _super);
        function SettingCreditCardDetails() {
            var _this = _super !== null && _super.apply(this, arguments) || this;
            _this.creditCards = ko.observableArray();
            _this.currentUserId = ko.observable(Utilities.Default(StorageService.Get("currentUserId"), "current")).extend({ deferred: true });
            _this.refresh = ko.observable();
            return _this;
        }
        SettingCreditCardDetails.prototype.createModel = function () {
            var self = this;
            ko.computed(function () {
                self.refresh();
                self.loading(true);
                self.creditCards.removeAll();
                var userId = self.currentUserId();
                StorageService.Store("currentUserId", userId);
                CreditCardService.New()
                    .With("userId", userId)
                    .GetAll(function (result) {
                    if (result) {
                        _.each(result.data, function (item) {
                            self.creditCards.push(item);
                        });
                    }
                    else {
                        StorageService.Clear("currentUserId");
                    }
                    self.loading(false);
                    self.pageReady(true);
                });
            });
            self.remove = function (id, e) {
                alertify.confirm("Are you sure you want to delete this credit card?", function () {
                    self.loading(true);
                    var l = Ladda.create(e.currentTarget).start();
                    CreditCardService.New()
                        .Delete(id, function () {
                        self.refresh.valueHasMutated();
                        l.stop();
                        self.loading(false);
                    });
                });
                return false;
            };
            self.makePrimary = function (id, e) {
                var l = Ladda.create(e.currentTarget).start();
                self.loading(true);
                CreditCardService.New()
                    .UpdateSingle(id, "isDefault", "True", function () {
                    self.refresh.valueHasMutated();
                    l.stop();
                    self.loading(false);
                });
                return false;
            };
            return self;
        };
        return SettingCreditCardDetails;
    }(BindablePageModel));
    Customer.SettingCreditCardDetails = SettingCreditCardDetails;
})(Customer || (Customer = {}));
//# sourceMappingURL=Customer.SettingCreditCardDetails.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var Customer;
(function (Customer) {
    var SettingOrders = /** @class */ (function (_super) {
        __extends(SettingOrders, _super);
        function SettingOrders() {
            var _this = _super !== null && _super.apply(this, arguments) || this;
            _this.orders = ko.observableArray();
            _this.currentUserId = ko.observable(Utilities.Default(StorageService.Get("currentUserId"), "current")).extend({ deferred: true });
            _this.refresh = ko.observable();
            return _this;
        }
        SettingOrders.prototype.createModel = function () {
            var self = this;
            ko.computed(function () {
                self.refresh();
                self.loading(true);
                self.orders.removeAll();
                var userId = self.currentUserId();
                StorageService.Store("currentUserId", userId);
                OrderService.New()
                    .With("userId", userId)
                    .With("includeCancelled", "true")
                    .GetAll(function (result) {
                    if (result) {
                        _.each(result.data, function (item) {
                            self.orders.push(item);
                        });
                    }
                    else {
                        StorageService.Clear("currentUserId");
                    }
                    self.loading(false);
                    self.pageReady(true);
                });
            });
            return self;
        };
        return SettingOrders;
    }(BindablePageModel));
    Customer.SettingOrders = SettingOrders;
})(Customer || (Customer = {}));
//# sourceMappingURL=Customer.SettingOrders.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var Customer;
(function (Customer) {
    var SettingProfileDetails = /** @class */ (function (_super) {
        __extends(SettingProfileDetails, _super);
        function SettingProfileDetails() {
            var _this = _super !== null && _super.apply(this, arguments) || this;
            _this.user = ko.observable();
            _this.currentUserId = ko.observable(Utilities.Default(StorageService.Get("currentUserId"), "current")).extend({ deferred: true });
            return _this;
        }
        ;
        SettingProfileDetails.prototype.createModel = function () {
            var self = this;
            ko.computed(function () {
                self.loading(true);
                var userId = self.currentUserId();
                StorageService.Store("currentUserId", userId);
                UserService.New().GetDetail(userId, function (result) {
                    if (result) {
                        self.user(result);
                        if (result.id != StorageService.Get("currentUserId"))
                            StorageService.Clear("currentUserId");
                    }
                    else {
                        StorageService.Clear("currentUserId");
                    }
                    self.loading(false);
                    self.pageReady(true);
                });
            });
            return self;
        };
        return SettingProfileDetails;
    }(BindablePageModel));
    Customer.SettingProfileDetails = SettingProfileDetails;
})(Customer || (Customer = {}));
//# sourceMappingURL=Customer.SettingProfileDetails.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var Customer;
(function (Customer) {
    var SettingProfileEdit = /** @class */ (function (_super) {
        __extends(SettingProfileEdit, _super);
        function SettingProfileEdit() {
            var _this = _super !== null && _super.apply(this, arguments) || this;
            _this.currentUserId = ko.observable($("#id").val()).extend({ deferred: true });
            _this.name = ko.observable();
            _this.email = ko.observable();
            _this.twitter = ko.observable();
            _this.instagram = ko.observable();
            _this.mobile = ko.observable();
            return _this;
        }
        SettingProfileEdit.prototype.createModel = function () {
            var self = this;
            ko.computed(function () {
                var userId = self.currentUserId();
                self.loading(true);
                UserService.New().GetDetail(userId, function (result) {
                    if (result) {
                        self.name(result.name);
                        self.email(result.email);
                        self.twitter(result.twitter);
                        self.instagram(result.instagram);
                        self.mobile(result.mobile);
                    }
                    self.loading(false);
                    self.pageReady(true);
                });
            });
            self.submitForm = function () {
                Utilities.ClearFormErrors();
                Ladda.create($("#save-changes")[0]).start();
                UserService.New()
                    .Update(self.currentUserId(), {
                    name: self.name(),
                    mobile: self.mobile(),
                    email: self.email(),
                    twitter: self.twitter(),
                    instagram: self.instagram()
                }, function (result, error) {
                    if (result) {
                        document.location.pathname = "/customer/settings";
                    }
                    else {
                        Utilities.ApplyFormErrors(error);
                        Ladda.stopAll();
                    }
                });
                return false;
            };
            return self;
        };
        return SettingProfileEdit;
    }(BindablePageModel));
    Customer.SettingProfileEdit = SettingProfileEdit;
})(Customer || (Customer = {}));
//# sourceMappingURL=Customer.SettingProfileEdit.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var Customer;
(function (Customer) {
    var SettingPups = /** @class */ (function (_super) {
        __extends(SettingPups, _super);
        function SettingPups() {
            var _this = _super !== null && _super.apply(this, arguments) || this;
            _this.dogs = ko.observableArray();
            _this.currentUserId = ko.observable(Utilities.Default(StorageService.Get("currentUserId"), "current")).extend({ deferred: true });
            _this.refresh = ko.observable();
            return _this;
        }
        SettingPups.prototype.createModel = function () {
            var self = this;
            ko.computed(function () {
                self.refresh();
                self.loading(true);
                self.dogs.removeAll();
                var userId = self.currentUserId();
                StorageService.Store("currentUserId", userId);
                DogService.New()
                    .With("userId", userId)
                    .GetAll(function (result) {
                    if (result) {
                        _.each(result.data, function (item) {
                            self.dogs.push(item);
                        });
                    }
                    else {
                        StorageService.Clear("currentUserId");
                    }
                    self.loading(false);
                    self.pageReady(true);
                });
            });
            self.remove = function (id, e) {
                alertify.confirm("Are you sure you want to delete this dog?", function () {
                    var l = Ladda.create(e.currentTarget).start();
                    self.loading(true);
                    DogService.New()
                        .Delete(id, function () {
                        self.refresh.valueHasMutated();
                        l.stop();
                        self.loading(false);
                    });
                });
                return false;
            };
            return self;
        };
        return SettingPups;
    }(BindablePageModel));
    Customer.SettingPups = SettingPups;
})(Customer || (Customer = {}));
//# sourceMappingURL=Customer.SettingPups.js.map;
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var Customer;
(function (Customer) {
    var SettingPupsEdit = /** @class */ (function (_super) {
        __extends(SettingPupsEdit, _super);
        function SettingPupsEdit() {
            var _this = _super !== null && _super.apply(this, arguments) || this;
            _this.name = ko.observable();
            _this.size = ko.observable();
            _this.preferences = ko.observable();
            _this.breed = ko.observable();
            _this.imageUploading = ko.observable(false);
            _this.currentUserId = ko.observable(Utilities.Default(StorageService.Get("currentUserId"), "current")).extend({ deferred: true });
            _this.refresh = ko.observable();
            return _this;
        }
        SettingPupsEdit.prototype.createModel = function () {
            var self = this;
            ko.computed(function () {
                var userId = self.currentUserId();
                self.loading(true);
                DogService.New().GetDetail($("#id").val(), function (result) {
                    if (result) {
                        self.name(result.name);
                        self.size(result.size);
                        self.preferences(result.specialRequirements);
                        self.breed(result.breed);
                        if (result.birthday)
                            $("#dogBirthday").val(moment.utc(result.birthday).format('DD/MM/YY'));
                    }
                    self.loading(false);
                    self.pageReady(true);
                });
            });
            $("#photo-upload").change(function (e) {
                self.imageUploading(true);
                var blobFile = $("#photo-upload")[0].files[0];
                var formData = new FormData();
                formData.append("profile", blobFile);
                $.ajax({
                    url: "/images/dog/" + $("#id").val(),
                    type: "POST",
                    data: formData,
                    processData: false,
                    contentType: false,
                    success: function (response) {
                        self.imageUploading(false);
                        $("#dog-img").attr('src', '/images/dog/' + $("#id").val() + '?size=200&t=' + new Date());
                    },
                    error: function (jqXHR, textStatus, errorMessage) {
                        console.log(errorMessage);
                        notie.alert(3, "Woops! That didn't work. Please try again later.", 1.5);
                        self.imageUploading(false);
                    }
                });
            });
            self.submitForm = function (data, event) {
                var l = Ladda.create(event.currentTarget);
                l.start();
                Utilities.ClearFormErrors();
                var error = false;
                var description = "your ";
                if (self.name() == null) {
                    Utilities.ApplyFormError("name", "what should we call the dog");
                    description += "dog's name";
                    error = true;
                }
                description = description.substring(0, description.length - 2);
                if (error) {
                    l.stop();
                    notie.alert(3, "Please enter " + description + ".", 1.5);
                }
                else {
                    var birthday = null;
                    if ($("#dogBirthday").val())
                        birthday = moment($("#dogBirthday").val(), "DD/MM/YY").format("YYYY/MM/DD");
                    DogService.New()
                        .Update($("#id").val(), {
                        name: self.name(),
                        breed: self.breed(),
                        size: self.size(),
                        specialRequirements: self.preferences(),
                        birthday: birthday
                    }, function (result) {
                        Utilities.Back("/customer/settings/dogs");
                    });
                }
            };
            return self;
        };
        return SettingPupsEdit;
    }(BindablePageModel));
    Customer.SettingPupsEdit = SettingPupsEdit;
})(Customer || (Customer = {}));
//# sourceMappingURL=Customer.SettingPupsEdit.js.map;
var Customer;
(function (Customer) {
    var SettingPupsNew = /** @class */ (function () {
        function SettingPupsNew() {
            this.loadingState = ko.observable(Constants.STATE_INITIAL);
            this.name = ko.observable();
            this.size = ko.observable();
            this.birthday = ko.observable();
            this.preferences = ko.observable();
            this.breed = ko.observable();
            this.currentUserId = ko.observable(Utilities.Default(StorageService.Get("currentUserId"), "current")).extend({ deferred: true });
            this.refresh = ko.observable();
        }
        SettingPupsNew.prototype.createModel = function () {
            var self = this;
            self.submitForm = function (data, event) {
                var l = Ladda.create(event.currentTarget);
                l.start();
                Utilities.ClearFormErrors();
                var error = false;
                var description = "your ";
                if (self.name() == null) {
                    Utilities.ApplyFormError("name", "what should we call the dog");
                    description += "dog's name";
                    error = true;
                }
                description = description.substring(0, description.length - 2);
                if (error) {
                    l.stop();
                    notie.alert(3, "Please enter " + description + ".", 1.5);
                }
                else {
                    DogService.New()
                        .Create({
                        name: self.name(),
                        breed: self.breed(),
                        size: self.size(),
                        specialRequirements: self.preferences(),
                        birthday: moment($("#dogBirthday").val(), "DD/MM/YY").format("YYYY/MM/DD"),
                        userId: self.currentUserId()
                    }, function (result) {
                        Utilities.Back("/customer/settings/dogs");
                    });
                }
            };
            return self;
        };
        return SettingPupsNew;
    }());
    Customer.SettingPupsNew = SettingPupsNew;
})(Customer || (Customer = {}));
//# sourceMappingURL=Customer.SettingPupsNew.js.map;
