You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cmda.apache.org by xi...@apache.org on 2015/10/29 23:56:25 UTC

[2/9] incubator-cmda git commit: Update ApacheCMDA-Frontend with KnowledgeGraph

http://git-wip-us.apache.org/repos/asf/incubator-cmda/blob/ca952ad9/ApacheCMDA-Frontend/public/javascripts/vis.js
----------------------------------------------------------------------
diff --git a/ApacheCMDA-Frontend/public/javascripts/vis.js b/ApacheCMDA-Frontend/public/javascripts/vis.js
new file mode 100644
index 0000000..3388fc4
--- /dev/null
+++ b/ApacheCMDA-Frontend/public/javascripts/vis.js
@@ -0,0 +1,43387 @@
+/**
+ * vis.js
+ * https://github.com/almende/vis
+ *
+ * A dynamic, browser-based visualization library.
+ *
+ * @version 4.9.0
+ * @date    2015-10-01
+ *
+ * @license
+ * Copyright (C) 2011-2015 Almende B.V, http://almende.com
+ *
+ * Vis.js is dual licensed under both
+ *
+ * * The Apache 2.0 License
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * and
+ *
+ * * The MIT License
+ *   http://opensource.org/licenses/MIT
+ *
+ * Vis.js may be distributed under either license.
+ */
+
+"use strict";
+
+(function webpackUniversalModuleDefinition(root, factory) {
+	if(typeof exports === 'object' && typeof module === 'object')
+		module.exports = factory();
+	else if(typeof define === 'function' && define.amd)
+		define([], factory);
+	else if(typeof exports === 'object')
+		exports["vis"] = factory();
+	else
+		root["vis"] = factory();
+})(this, function() {
+return /******/ (function(modules) { // webpackBootstrap
+/******/ 	// The module cache
+/******/ 	var installedModules = {};
+
+/******/ 	// The require function
+/******/ 	function __webpack_require__(moduleId) {
+
+/******/ 		// Check if module is in cache
+/******/ 		if(installedModules[moduleId])
+/******/ 			return installedModules[moduleId].exports;
+
+/******/ 		// Create a new module (and put it into the cache)
+/******/ 		var module = installedModules[moduleId] = {
+/******/ 			exports: {},
+/******/ 			id: moduleId,
+/******/ 			loaded: false
+/******/ 		};
+
+/******/ 		// Execute the module function
+/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
+
+/******/ 		// Flag the module as loaded
+/******/ 		module.loaded = true;
+
+/******/ 		// Return the exports of the module
+/******/ 		return module.exports;
+/******/ 	}
+
+
+/******/ 	// expose the modules object (__webpack_modules__)
+/******/ 	__webpack_require__.m = modules;
+
+/******/ 	// expose the module cache
+/******/ 	__webpack_require__.c = installedModules;
+
+/******/ 	// __webpack_public_path__
+/******/ 	__webpack_require__.p = "";
+
+/******/ 	// Load entry module and return exports
+/******/ 	return __webpack_require__(0);
+/******/ })
+/************************************************************************/
+/******/ ([
+/* 0 */
+/***/ function(module, exports, __webpack_require__) {
+
+  // utils
+  'use strict';
+
+  exports.util = __webpack_require__(1);
+  exports.DOMutil = __webpack_require__(7);
+
+  // data
+  exports.DataSet = __webpack_require__(8);
+  exports.DataView = __webpack_require__(10);
+  exports.Queue = __webpack_require__(9);
+
+  // Graph3d
+  exports.Graph3d = __webpack_require__(11);
+  exports.graph3d = {
+    Camera: __webpack_require__(15),
+    Filter: __webpack_require__(16),
+    Point2d: __webpack_require__(14),
+    Point3d: __webpack_require__(13),
+    Slider: __webpack_require__(17),
+    StepNumber: __webpack_require__(18)
+  };
+
+  // Timeline
+  exports.Timeline = __webpack_require__(19);
+  exports.Graph2d = __webpack_require__(49);
+  exports.timeline = {
+    DateUtil: __webpack_require__(27),
+    DataStep: __webpack_require__(52),
+    Range: __webpack_require__(24),
+    stack: __webpack_require__(32),
+    TimeStep: __webpack_require__(30),
+
+    components: {
+      items: {
+        Item: __webpack_require__(34),
+        BackgroundItem: __webpack_require__(38),
+        BoxItem: __webpack_require__(36),
+        PointItem: __webpack_require__(37),
+        RangeItem: __webpack_require__(33)
+      },
+
+      Component: __webpack_require__(26),
+      CurrentTime: __webpack_require__(44),
+      CustomTime: __webpack_require__(42),
+      DataAxis: __webpack_require__(51),
+      GraphGroup: __webpack_require__(53),
+      Group: __webpack_require__(31),
+      BackgroundGroup: __webpack_require__(35),
+      ItemSet: __webpack_require__(29),
+      Legend: __webpack_require__(57),
+      LineGraph: __webpack_require__(50),
+      TimeAxis: __webpack_require__(39)
+    }
+  };
+
+  // Network
+  exports.Network = __webpack_require__(59);
+  exports.network = {
+    Images: __webpack_require__(117),
+    dotparser: __webpack_require__(115),
+    gephiParser: __webpack_require__(116),
+    allOptions: __webpack_require__(111)
+  };
+  exports.network.convertDot = function (input) {
+    return exports.network.dotparser.DOTToGraph(input);
+  };
+  exports.network.convertGephi = function (input, options) {
+    return exports.network.gephiParser.parseGephi(input, options);
+  };
+
+  // bundled external libraries
+  exports.moment = __webpack_require__(2);
+  exports.Hammer = __webpack_require__(20);
+  exports.keycharm = __webpack_require__(41);
+
+/***/ },
+/* 1 */
+/***/ function(module, exports, __webpack_require__) {
+
+  // utility functions
+
+  // first check if moment.js is already loaded in the browser window, if so,
+  // use this instance. Else, load via commonjs.
+
+  'use strict';
+
+  var moment = __webpack_require__(2);
+  var uuid = __webpack_require__(6);
+
+  /**
+   * Test whether given object is a number
+   * @param {*} object
+   * @return {Boolean} isNumber
+   */
+  exports.isNumber = function (object) {
+    return object instanceof Number || typeof object == 'number';
+  };
+
+  /**
+   * Remove everything in the DOM object
+   * @param DOMobject
+   */
+  exports.recursiveDOMDelete = function (DOMobject) {
+    if (DOMobject) {
+      while (DOMobject.hasChildNodes() === true) {
+        exports.recursiveDOMDelete(DOMobject.firstChild);
+        DOMobject.removeChild(DOMobject.firstChild);
+      }
+    }
+  };
+
+  /**
+   * this function gives you a range between 0 and 1 based on the min and max values in the set, the total sum of all values and the current value.
+   *
+   * @param min
+   * @param max
+   * @param total
+   * @param value
+   * @returns {number}
+   */
+  exports.giveRange = function (min, max, total, value) {
+    if (max == min) {
+      return 0.5;
+    } else {
+      var scale = 1 / (max - min);
+      return Math.max(0, (value - min) * scale);
+    }
+  };
+
+  /**
+   * Test whether given object is a string
+   * @param {*} object
+   * @return {Boolean} isString
+   */
+  exports.isString = function (object) {
+    return object instanceof String || typeof object == 'string';
+  };
+
+  /**
+   * Test whether given object is a Date, or a String containing a Date
+   * @param {Date | String} object
+   * @return {Boolean} isDate
+   */
+  exports.isDate = function (object) {
+    if (object instanceof Date) {
+      return true;
+    } else if (exports.isString(object)) {
+      // test whether this string contains a date
+      var match = ASPDateRegex.exec(object);
+      if (match) {
+        return true;
+      } else if (!isNaN(Date.parse(object))) {
+        return true;
+      }
+    }
+
+    return false;
+  };
+
+  /**
+   * Create a semi UUID
+   * source: http://stackoverflow.com/a/105074/1262753
+   * @return {String} uuid
+   */
+  exports.randomUUID = function () {
+    return uuid.v4();
+  };
+
+  /**
+   * assign all keys of an object that are not nested objects to a certain value (used for color objects).
+   * @param obj
+   * @param value
+   */
+  exports.assignAllKeys = function (obj, value) {
+    for (var prop in obj) {
+      if (obj.hasOwnProperty(prop)) {
+        if (typeof obj[prop] !== 'object') {
+          obj[prop] = value;
+        }
+      }
+    }
+  };
+
+  /**
+   * Fill an object with a possibly partially defined other object. Only copies values if the a object has an object requiring values.
+   * That means an object is not created on a property if only the b object has it.
+   * @param obj
+   * @param value
+   */
+  exports.fillIfDefined = function (a, b) {
+    var allowDeletion = arguments.length <= 2 || arguments[2] === undefined ? false : arguments[2];
+
+    for (var prop in a) {
+      if (b[prop] !== undefined) {
+        if (typeof b[prop] !== 'object') {
+          if ((b[prop] === undefined || b[prop] === null) && a[prop] !== undefined && allowDeletion === true) {
+            delete a[prop];
+          } else {
+            a[prop] = b[prop];
+          }
+        } else {
+          if (typeof a[prop] === 'object') {
+            exports.fillIfDefined(a[prop], b[prop], allowDeletion);
+          }
+        }
+      }
+    }
+  };
+
+  /**
+   * Extend object a with the properties of object b or a series of objects
+   * Only properties with defined values are copied
+   * @param {Object} a
+   * @param {... Object} b
+   * @return {Object} a
+   */
+  exports.protoExtend = function (a, b) {
+    for (var i = 1; i < arguments.length; i++) {
+      var other = arguments[i];
+      for (var prop in other) {
+        a[prop] = other[prop];
+      }
+    }
+    return a;
+  };
+
+  /**
+   * Extend object a with the properties of object b or a series of objects
+   * Only properties with defined values are copied
+   * @param {Object} a
+   * @param {... Object} b
+   * @return {Object} a
+   */
+  exports.extend = function (a, b) {
+    for (var i = 1; i < arguments.length; i++) {
+      var other = arguments[i];
+      for (var prop in other) {
+        if (other.hasOwnProperty(prop)) {
+          a[prop] = other[prop];
+        }
+      }
+    }
+    return a;
+  };
+
+  /**
+   * Extend object a with selected properties of object b or a series of objects
+   * Only properties with defined values are copied
+   * @param {Array.<String>} props
+   * @param {Object} a
+   * @param {Object} b
+   * @return {Object} a
+   */
+  exports.selectiveExtend = function (props, a, b) {
+    if (!Array.isArray(props)) {
+      throw new Error('Array with property names expected as first argument');
+    }
+
+    for (var i = 2; i < arguments.length; i++) {
+      var other = arguments[i];
+
+      for (var p = 0; p < props.length; p++) {
+        var prop = props[p];
+        if (other.hasOwnProperty(prop)) {
+          a[prop] = other[prop];
+        }
+      }
+    }
+    return a;
+  };
+
+  /**
+   * Extend object a with selected properties of object b or a series of objects
+   * Only properties with defined values are copied
+   * @param {Array.<String>} props
+   * @param {Object} a
+   * @param {Object} b
+   * @return {Object} a
+   */
+  exports.selectiveDeepExtend = function (props, a, b) {
+    var allowDeletion = arguments.length <= 3 || arguments[3] === undefined ? false : arguments[3];
+
+    // TODO: add support for Arrays to deepExtend
+    if (Array.isArray(b)) {
+      throw new TypeError('Arrays are not supported by deepExtend');
+    }
+    for (var i = 2; i < arguments.length; i++) {
+      var other = arguments[i];
+      for (var p = 0; p < props.length; p++) {
+        var prop = props[p];
+        if (other.hasOwnProperty(prop)) {
+          if (b[prop] && b[prop].constructor === Object) {
+            if (a[prop] === undefined) {
+              a[prop] = {};
+            }
+            if (a[prop].constructor === Object) {
+              exports.deepExtend(a[prop], b[prop], false, allowDeletion);
+            } else {
+              if (b[prop] === null && a[prop] !== undefined && allowDeletion === true) {
+                delete a[prop];
+              } else {
+                a[prop] = b[prop];
+              }
+            }
+          } else if (Array.isArray(b[prop])) {
+            throw new TypeError('Arrays are not supported by deepExtend');
+          } else {
+            if (b[prop] === null && a[prop] !== undefined && allowDeletion === true) {
+              delete a[prop];
+            } else {
+              a[prop] = b[prop];
+            }
+          }
+        }
+      }
+    }
+    return a;
+  };
+
+  /**
+   * Extend object a with selected properties of object b or a series of objects
+   * Only properties with defined values are copied
+   * @param {Array.<String>} props
+   * @param {Object} a
+   * @param {Object} b
+   * @return {Object} a
+   */
+  exports.selectiveNotDeepExtend = function (props, a, b) {
+    var allowDeletion = arguments.length <= 3 || arguments[3] === undefined ? false : arguments[3];
+
+    // TODO: add support for Arrays to deepExtend
+    if (Array.isArray(b)) {
+      throw new TypeError('Arrays are not supported by deepExtend');
+    }
+    for (var prop in b) {
+      if (b.hasOwnProperty(prop)) {
+        if (props.indexOf(prop) == -1) {
+          if (b[prop] && b[prop].constructor === Object) {
+            if (a[prop] === undefined) {
+              a[prop] = {};
+            }
+            if (a[prop].constructor === Object) {
+              exports.deepExtend(a[prop], b[prop]);
+            } else {
+              if (b[prop] === null && a[prop] !== undefined && allowDeletion === true) {
+                delete a[prop];
+              } else {
+                a[prop] = b[prop];
+              }
+            }
+          } else if (Array.isArray(b[prop])) {
+            a[prop] = [];
+            for (var i = 0; i < b[prop].length; i++) {
+              a[prop].push(b[prop][i]);
+            }
+          } else {
+            if (b[prop] === null && a[prop] !== undefined && allowDeletion === true) {
+              delete a[prop];
+            } else {
+              a[prop] = b[prop];
+            }
+          }
+        }
+      }
+    }
+    return a;
+  };
+
+  /**
+   * Deep extend an object a with the properties of object b
+   * @param {Object} a
+   * @param {Object} b
+   * @param [Boolean] protoExtend --> optional parameter. If true, the prototype values will also be extended.
+   *                                  (ie. the options objects that inherit from others will also get the inherited options)
+   * @param [Boolean] global      --> optional parameter. If true, the values of fields that are null will not deleted
+   * @returns {Object}
+   */
+  exports.deepExtend = function (a, b, protoExtend, allowDeletion) {
+    for (var prop in b) {
+      if (b.hasOwnProperty(prop) || protoExtend === true) {
+        if (b[prop] && b[prop].constructor === Object) {
+          if (a[prop] === undefined) {
+            a[prop] = {};
+          }
+          if (a[prop].constructor === Object) {
+            exports.deepExtend(a[prop], b[prop], protoExtend);
+          } else {
+            if (b[prop] === null && a[prop] !== undefined && allowDeletion === true) {
+              delete a[prop];
+            } else {
+              a[prop] = b[prop];
+            }
+          }
+        } else if (Array.isArray(b[prop])) {
+          a[prop] = [];
+          for (var i = 0; i < b[prop].length; i++) {
+            a[prop].push(b[prop][i]);
+          }
+        } else {
+          if (b[prop] === null && a[prop] !== undefined && allowDeletion === true) {
+            delete a[prop];
+          } else {
+            a[prop] = b[prop];
+          }
+        }
+      }
+    }
+    return a;
+  };
+
+  /**
+   * Test whether all elements in two arrays are equal.
+   * @param {Array} a
+   * @param {Array} b
+   * @return {boolean} Returns true if both arrays have the same length and same
+   *                   elements.
+   */
+  exports.equalArray = function (a, b) {
+    if (a.length != b.length) return false;
+
+    for (var i = 0, len = a.length; i < len; i++) {
+      if (a[i] != b[i]) return false;
+    }
+
+    return true;
+  };
+
+  /**
+   * Convert an object to another type
+   * @param {Boolean | Number | String | Date | Moment | Null | undefined} object
+   * @param {String | undefined} type   Name of the type. Available types:
+   *                                    'Boolean', 'Number', 'String',
+   *                                    'Date', 'Moment', ISODate', 'ASPDate'.
+   * @return {*} object
+   * @throws Error
+   */
+  exports.convert = function (object, type) {
+    var match;
+
+    if (object === undefined) {
+      return undefined;
+    }
+    if (object === null) {
+      return null;
+    }
+
+    if (!type) {
+      return object;
+    }
+    if (!(typeof type === 'string') && !(type instanceof String)) {
+      throw new Error('Type must be a string');
+    }
+
+    //noinspection FallthroughInSwitchStatementJS
+    switch (type) {
+      case 'boolean':
+      case 'Boolean':
+        return Boolean(object);
+
+      case 'number':
+      case 'Number':
+        return Number(object.valueOf());
+
+      case 'string':
+      case 'String':
+        return String(object);
+
+      case 'Date':
+        if (exports.isNumber(object)) {
+          return new Date(object);
+        }
+        if (object instanceof Date) {
+          return new Date(object.valueOf());
+        } else if (moment.isMoment(object)) {
+          return new Date(object.valueOf());
+        }
+        if (exports.isString(object)) {
+          match = ASPDateRegex.exec(object);
+          if (match) {
+            // object is an ASP date
+            return new Date(Number(match[1])); // parse number
+          } else {
+            return moment(object).toDate(); // parse string
+          }
+        } else {
+          throw new Error('Cannot convert object of type ' + exports.getType(object) + ' to type Date');
+        }
+
+      case 'Moment':
+        if (exports.isNumber(object)) {
+          return moment(object);
+        }
+        if (object instanceof Date) {
+          return moment(object.valueOf());
+        } else if (moment.isMoment(object)) {
+          return moment(object);
+        }
+        if (exports.isString(object)) {
+          match = ASPDateRegex.exec(object);
+          if (match) {
+            // object is an ASP date
+            return moment(Number(match[1])); // parse number
+          } else {
+            return moment(object); // parse string
+          }
+        } else {
+          throw new Error('Cannot convert object of type ' + exports.getType(object) + ' to type Date');
+        }
+
+      case 'ISODate':
+        if (exports.isNumber(object)) {
+          return new Date(object);
+        } else if (object instanceof Date) {
+          return object.toISOString();
+        } else if (moment.isMoment(object)) {
+          return object.toDate().toISOString();
+        } else if (exports.isString(object)) {
+          match = ASPDateRegex.exec(object);
+          if (match) {
+            // object is an ASP date
+            return new Date(Number(match[1])).toISOString(); // parse number
+          } else {
+            return new Date(object).toISOString(); // parse string
+          }
+        } else {
+          throw new Error('Cannot convert object of type ' + exports.getType(object) + ' to type ISODate');
+        }
+
+      case 'ASPDate':
+        if (exports.isNumber(object)) {
+          return '/Date(' + object + ')/';
+        } else if (object instanceof Date) {
+          return '/Date(' + object.valueOf() + ')/';
+        } else if (exports.isString(object)) {
+          match = ASPDateRegex.exec(object);
+          var value;
+          if (match) {
+            // object is an ASP date
+            value = new Date(Number(match[1])).valueOf(); // parse number
+          } else {
+            value = new Date(object).valueOf(); // parse string
+          }
+          return '/Date(' + value + ')/';
+        } else {
+          throw new Error('Cannot convert object of type ' + exports.getType(object) + ' to type ASPDate');
+        }
+
+      default:
+        throw new Error('Unknown type "' + type + '"');
+    }
+  };
+
+  // parse ASP.Net Date pattern,
+  // for example '/Date(1198908717056)/' or '/Date(1198908717056-0700)/'
+  // code from http://momentjs.com/
+  var ASPDateRegex = /^\/?Date\((\-?\d+)/i;
+
+  /**
+   * Get the type of an object, for example exports.getType([]) returns 'Array'
+   * @param {*} object
+   * @return {String} type
+   */
+  exports.getType = function (object) {
+    var type = typeof object;
+
+    if (type == 'object') {
+      if (object === null) {
+        return 'null';
+      }
+      if (object instanceof Boolean) {
+        return 'Boolean';
+      }
+      if (object instanceof Number) {
+        return 'Number';
+      }
+      if (object instanceof String) {
+        return 'String';
+      }
+      if (Array.isArray(object)) {
+        return 'Array';
+      }
+      if (object instanceof Date) {
+        return 'Date';
+      }
+      return 'Object';
+    } else if (type == 'number') {
+      return 'Number';
+    } else if (type == 'boolean') {
+      return 'Boolean';
+    } else if (type == 'string') {
+      return 'String';
+    } else if (type === undefined) {
+      return 'undefined';
+    }
+
+    return type;
+  };
+
+  /**
+   * Used to extend an array and copy it. This is used to propagate paths recursively.
+   *
+   * @param arr
+   * @param newValue
+   * @returns {Array}
+   */
+  exports.copyAndExtendArray = function (arr, newValue) {
+    var newArr = [];
+    for (var i = 0; i < arr.length; i++) {
+      newArr.push(arr[i]);
+    }
+    newArr.push(newValue);
+    return newArr;
+  };
+
+  /**
+   * Used to extend an array and copy it. This is used to propagate paths recursively.
+   *
+   * @param arr
+   * @param newValue
+   * @returns {Array}
+   */
+  exports.copyArray = function (arr) {
+    var newArr = [];
+    for (var i = 0; i < arr.length; i++) {
+      newArr.push(arr[i]);
+    }
+    return newArr;
+  };
+
+  /**
+   * Retrieve the absolute left value of a DOM element
+   * @param {Element} elem        A dom element, for example a div
+   * @return {number} left        The absolute left position of this element
+   *                              in the browser page.
+   */
+  exports.getAbsoluteLeft = function (elem) {
+    return elem.getBoundingClientRect().left;
+  };
+
+  /**
+   * Retrieve the absolute top value of a DOM element
+   * @param {Element} elem        A dom element, for example a div
+   * @return {number} top        The absolute top position of this element
+   *                              in the browser page.
+   */
+  exports.getAbsoluteTop = function (elem) {
+    return elem.getBoundingClientRect().top;
+  };
+
+  /**
+   * add a className to the given elements style
+   * @param {Element} elem
+   * @param {String} className
+   */
+  exports.addClassName = function (elem, className) {
+    var classes = elem.className.split(' ');
+    if (classes.indexOf(className) == -1) {
+      classes.push(className); // add the class to the array
+      elem.className = classes.join(' ');
+    }
+  };
+
+  /**
+   * add a className to the given elements style
+   * @param {Element} elem
+   * @param {String} className
+   */
+  exports.removeClassName = function (elem, className) {
+    var classes = elem.className.split(' ');
+    var index = classes.indexOf(className);
+    if (index != -1) {
+      classes.splice(index, 1); // remove the class from the array
+      elem.className = classes.join(' ');
+    }
+  };
+
+  /**
+   * For each method for both arrays and objects.
+   * In case of an array, the built-in Array.forEach() is applied.
+   * In case of an Object, the method loops over all properties of the object.
+   * @param {Object | Array} object   An Object or Array
+   * @param {function} callback       Callback method, called for each item in
+   *                                  the object or array with three parameters:
+   *                                  callback(value, index, object)
+   */
+  exports.forEach = function (object, callback) {
+    var i, len;
+    if (Array.isArray(object)) {
+      // array
+      for (i = 0, len = object.length; i < len; i++) {
+        callback(object[i], i, object);
+      }
+    } else {
+      // object
+      for (i in object) {
+        if (object.hasOwnProperty(i)) {
+          callback(object[i], i, object);
+        }
+      }
+    }
+  };
+
+  /**
+   * Convert an object into an array: all objects properties are put into the
+   * array. The resulting array is unordered.
+   * @param {Object} object
+   * @param {Array} array
+   */
+  exports.toArray = function (object) {
+    var array = [];
+
+    for (var prop in object) {
+      if (object.hasOwnProperty(prop)) array.push(object[prop]);
+    }
+
+    return array;
+  };
+
+  /**
+   * Update a property in an object
+   * @param {Object} object
+   * @param {String} key
+   * @param {*} value
+   * @return {Boolean} changed
+   */
+  exports.updateProperty = function (object, key, value) {
+    if (object[key] !== value) {
+      object[key] = value;
+      return true;
+    } else {
+      return false;
+    }
+  };
+
+  /**
+   * Throttle the given function to be only executed once every `wait` milliseconds
+   * @param {function} fn
+   * @param {number} wait    Time in milliseconds
+   * @returns {function} Returns the throttled function
+   */
+  exports.throttle = function (fn, wait) {
+    var timeout = null;
+    var needExecution = false;
+
+    return function throttled() {
+      if (!timeout) {
+        needExecution = false;
+        fn();
+
+        timeout = setTimeout(function () {
+          timeout = null;
+          if (needExecution) {
+            throttled();
+          }
+        }, wait);
+      } else {
+        needExecution = true;
+      }
+    };
+  };
+
+  /**
+   * Add and event listener. Works for all browsers
+   * @param {Element}     element    An html element
+   * @param {string}      action     The action, for example "click",
+   *                                 without the prefix "on"
+   * @param {function}    listener   The callback function to be executed
+   * @param {boolean}     [useCapture]
+   */
+  exports.addEventListener = function (element, action, listener, useCapture) {
+    if (element.addEventListener) {
+      if (useCapture === undefined) useCapture = false;
+
+      if (action === 'mousewheel' && navigator.userAgent.indexOf('Firefox') >= 0) {
+        action = 'DOMMouseScroll'; // For Firefox
+      }
+
+      element.addEventListener(action, listener, useCapture);
+    } else {
+      element.attachEvent('on' + action, listener); // IE browsers
+    }
+  };
+
+  /**
+   * Remove an event listener from an element
+   * @param {Element}     element         An html dom element
+   * @param {string}      action          The name of the event, for example "mousedown"
+   * @param {function}    listener        The listener function
+   * @param {boolean}     [useCapture]
+   */
+  exports.removeEventListener = function (element, action, listener, useCapture) {
+    if (element.removeEventListener) {
+      // non-IE browsers
+      if (useCapture === undefined) useCapture = false;
+
+      if (action === 'mousewheel' && navigator.userAgent.indexOf('Firefox') >= 0) {
+        action = 'DOMMouseScroll'; // For Firefox
+      }
+
+      element.removeEventListener(action, listener, useCapture);
+    } else {
+      // IE browsers
+      element.detachEvent('on' + action, listener);
+    }
+  };
+
+  /**
+   * Cancels the event if it is cancelable, without stopping further propagation of the event.
+   */
+  exports.preventDefault = function (event) {
+    if (!event) event = window.event;
+
+    if (event.preventDefault) {
+      event.preventDefault(); // non-IE browsers
+    } else {
+      event.returnValue = false; // IE browsers
+    }
+  };
+
+  /**
+   * Get HTML element which is the target of the event
+   * @param {Event} event
+   * @return {Element} target element
+   */
+  exports.getTarget = function (event) {
+    // code from http://www.quirksmode.org/js/events_properties.html
+    if (!event) {
+      event = window.event;
+    }
+
+    var target;
+
+    if (event.target) {
+      target = event.target;
+    } else if (event.srcElement) {
+      target = event.srcElement;
+    }
+
+    if (target.nodeType != undefined && target.nodeType == 3) {
+      // defeat Safari bug
+      target = target.parentNode;
+    }
+
+    return target;
+  };
+
+  /**
+   * Check if given element contains given parent somewhere in the DOM tree
+   * @param {Element} element
+   * @param {Element} parent
+   */
+  exports.hasParent = function (element, parent) {
+    var e = element;
+
+    while (e) {
+      if (e === parent) {
+        return true;
+      }
+      e = e.parentNode;
+    }
+
+    return false;
+  };
+
+  exports.option = {};
+
+  /**
+   * Convert a value into a boolean
+   * @param {Boolean | function | undefined} value
+   * @param {Boolean} [defaultValue]
+   * @returns {Boolean} bool
+   */
+  exports.option.asBoolean = function (value, defaultValue) {
+    if (typeof value == 'function') {
+      value = value();
+    }
+
+    if (value != null) {
+      return value != false;
+    }
+
+    return defaultValue || null;
+  };
+
+  /**
+   * Convert a value into a number
+   * @param {Boolean | function | undefined} value
+   * @param {Number} [defaultValue]
+   * @returns {Number} number
+   */
+  exports.option.asNumber = function (value, defaultValue) {
+    if (typeof value == 'function') {
+      value = value();
+    }
+
+    if (value != null) {
+      return Number(value) || defaultValue || null;
+    }
+
+    return defaultValue || null;
+  };
+
+  /**
+   * Convert a value into a string
+   * @param {String | function | undefined} value
+   * @param {String} [defaultValue]
+   * @returns {String} str
+   */
+  exports.option.asString = function (value, defaultValue) {
+    if (typeof value == 'function') {
+      value = value();
+    }
+
+    if (value != null) {
+      return String(value);
+    }
+
+    return defaultValue || null;
+  };
+
+  /**
+   * Convert a size or location into a string with pixels or a percentage
+   * @param {String | Number | function | undefined} value
+   * @param {String} [defaultValue]
+   * @returns {String} size
+   */
+  exports.option.asSize = function (value, defaultValue) {
+    if (typeof value == 'function') {
+      value = value();
+    }
+
+    if (exports.isString(value)) {
+      return value;
+    } else if (exports.isNumber(value)) {
+      return value + 'px';
+    } else {
+      return defaultValue || null;
+    }
+  };
+
+  /**
+   * Convert a value into a DOM element
+   * @param {HTMLElement | function | undefined} value
+   * @param {HTMLElement} [defaultValue]
+   * @returns {HTMLElement | null} dom
+   */
+  exports.option.asElement = function (value, defaultValue) {
+    if (typeof value == 'function') {
+      value = value();
+    }
+
+    return value || defaultValue || null;
+  };
+
+  /**
+   * http://stackoverflow.com/questions/5623838/rgb-to-hex-and-hex-to-rgb
+   *
+   * @param {String} hex
+   * @returns {{r: *, g: *, b: *}} | 255 range
+   */
+  exports.hexToRGB = function (hex) {
+    // Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF")
+    var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
+    hex = hex.replace(shorthandRegex, function (m, r, g, b) {
+      return r + r + g + g + b + b;
+    });
+    var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
+    return result ? {
+      r: parseInt(result[1], 16),
+      g: parseInt(result[2], 16),
+      b: parseInt(result[3], 16)
+    } : null;
+  };
+
+  /**
+   * This function takes color in hex format or rgb() or rgba() format and overrides the opacity. Returns rgba() string.
+   * @param color
+   * @param opacity
+   * @returns {*}
+   */
+  exports.overrideOpacity = function (color, opacity) {
+    if (color.indexOf('rgba') != -1) {
+      return color;
+    } else if (color.indexOf('rgb') != -1) {
+      var rgb = color.substr(color.indexOf('(') + 1).replace(')', '').split(',');
+      return 'rgba(' + rgb[0] + ',' + rgb[1] + ',' + rgb[2] + ',' + opacity + ')';
+    } else {
+      var rgb = exports.hexToRGB(color);
+      if (rgb == null) {
+        return color;
+      } else {
+        return 'rgba(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ',' + opacity + ')';
+      }
+    }
+  };
+
+  /**
+   *
+   * @param red     0 -- 255
+   * @param green   0 -- 255
+   * @param blue    0 -- 255
+   * @returns {string}
+   * @constructor
+   */
+  exports.RGBToHex = function (red, green, blue) {
+    return '#' + ((1 << 24) + (red << 16) + (green << 8) + blue).toString(16).slice(1);
+  };
+
+  /**
+   * Parse a color property into an object with border, background, and
+   * highlight colors
+   * @param {Object | String} color
+   * @return {Object} colorObject
+   */
+  exports.parseColor = function (color) {
+    var c;
+    if (exports.isString(color) === true) {
+      if (exports.isValidRGB(color) === true) {
+        var rgb = color.substr(4).substr(0, color.length - 5).split(',').map(function (value) {
+          return parseInt(value);
+        });
+        color = exports.RGBToHex(rgb[0], rgb[1], rgb[2]);
+      }
+      if (exports.isValidHex(color) === true) {
+        var hsv = exports.hexToHSV(color);
+        var lighterColorHSV = { h: hsv.h, s: hsv.s * 0.8, v: Math.min(1, hsv.v * 1.02) };
+        var darkerColorHSV = { h: hsv.h, s: Math.min(1, hsv.s * 1.25), v: hsv.v * 0.8 };
+        var darkerColorHex = exports.HSVToHex(darkerColorHSV.h, darkerColorHSV.s, darkerColorHSV.v);
+        var lighterColorHex = exports.HSVToHex(lighterColorHSV.h, lighterColorHSV.s, lighterColorHSV.v);
+        c = {
+          background: color,
+          border: darkerColorHex,
+          highlight: {
+            background: lighterColorHex,
+            border: darkerColorHex
+          },
+          hover: {
+            background: lighterColorHex,
+            border: darkerColorHex
+          }
+        };
+      } else {
+        c = {
+          background: color,
+          border: color,
+          highlight: {
+            background: color,
+            border: color
+          },
+          hover: {
+            background: color,
+            border: color
+          }
+        };
+      }
+    } else {
+      c = {};
+      c.background = color.background || undefined;
+      c.border = color.border || undefined;
+
+      if (exports.isString(color.highlight)) {
+        c.highlight = {
+          border: color.highlight,
+          background: color.highlight
+        };
+      } else {
+        c.highlight = {};
+        c.highlight.background = color.highlight && color.highlight.background || undefined;
+        c.highlight.border = color.highlight && color.highlight.border || undefined;
+      }
+
+      if (exports.isString(color.hover)) {
+        c.hover = {
+          border: color.hover,
+          background: color.hover
+        };
+      } else {
+        c.hover = {};
+        c.hover.background = color.hover && color.hover.background || undefined;
+        c.hover.border = color.hover && color.hover.border || undefined;
+      }
+    }
+
+    return c;
+  };
+
+  /**
+   * http://www.javascripter.net/faq/rgb2hsv.htm
+   *
+   * @param red
+   * @param green
+   * @param blue
+   * @returns {*}
+   * @constructor
+   */
+  exports.RGBToHSV = function (red, green, blue) {
+    red = red / 255;green = green / 255;blue = blue / 255;
+    var minRGB = Math.min(red, Math.min(green, blue));
+    var maxRGB = Math.max(red, Math.max(green, blue));
+
+    // Black-gray-white
+    if (minRGB == maxRGB) {
+      return { h: 0, s: 0, v: minRGB };
+    }
+
+    // Colors other than black-gray-white:
+    var d = red == minRGB ? green - blue : blue == minRGB ? red - green : blue - red;
+    var h = red == minRGB ? 3 : blue == minRGB ? 1 : 5;
+    var hue = 60 * (h - d / (maxRGB - minRGB)) / 360;
+    var saturation = (maxRGB - minRGB) / maxRGB;
+    var value = maxRGB;
+    return { h: hue, s: saturation, v: value };
+  };
+
+  var cssUtil = {
+    // split a string with css styles into an object with key/values
+    split: function split(cssText) {
+      var styles = {};
+
+      cssText.split(';').forEach(function (style) {
+        if (style.trim() != '') {
+          var parts = style.split(':');
+          var key = parts[0].trim();
+          var value = parts[1].trim();
+          styles[key] = value;
+        }
+      });
+
+      return styles;
+    },
+
+    // build a css text string from an object with key/values
+    join: function join(styles) {
+      return Object.keys(styles).map(function (key) {
+        return key + ': ' + styles[key];
+      }).join('; ');
+    }
+  };
+
+  /**
+   * Append a string with css styles to an element
+   * @param {Element} element
+   * @param {String} cssText
+   */
+  exports.addCssText = function (element, cssText) {
+    var currentStyles = cssUtil.split(element.style.cssText);
+    var newStyles = cssUtil.split(cssText);
+    var styles = exports.extend(currentStyles, newStyles);
+
+    element.style.cssText = cssUtil.join(styles);
+  };
+
+  /**
+   * Remove a string with css styles from an element
+   * @param {Element} element
+   * @param {String} cssText
+   */
+  exports.removeCssText = function (element, cssText) {
+    var styles = cssUtil.split(element.style.cssText);
+    var removeStyles = cssUtil.split(cssText);
+
+    for (var key in removeStyles) {
+      if (removeStyles.hasOwnProperty(key)) {
+        delete styles[key];
+      }
+    }
+
+    element.style.cssText = cssUtil.join(styles);
+  };
+
+  /**
+   * https://gist.github.com/mjijackson/5311256
+   * @param h
+   * @param s
+   * @param v
+   * @returns {{r: number, g: number, b: number}}
+   * @constructor
+   */
+  exports.HSVToRGB = function (h, s, v) {
+    var r, g, b;
+
+    var i = Math.floor(h * 6);
+    var f = h * 6 - i;
+    var p = v * (1 - s);
+    var q = v * (1 - f * s);
+    var t = v * (1 - (1 - f) * s);
+
+    switch (i % 6) {
+      case 0:
+        r = v, g = t, b = p;break;
+      case 1:
+        r = q, g = v, b = p;break;
+      case 2:
+        r = p, g = v, b = t;break;
+      case 3:
+        r = p, g = q, b = v;break;
+      case 4:
+        r = t, g = p, b = v;break;
+      case 5:
+        r = v, g = p, b = q;break;
+    }
+
+    return { r: Math.floor(r * 255), g: Math.floor(g * 255), b: Math.floor(b * 255) };
+  };
+
+  exports.HSVToHex = function (h, s, v) {
+    var rgb = exports.HSVToRGB(h, s, v);
+    return exports.RGBToHex(rgb.r, rgb.g, rgb.b);
+  };
+
+  exports.hexToHSV = function (hex) {
+    var rgb = exports.hexToRGB(hex);
+    return exports.RGBToHSV(rgb.r, rgb.g, rgb.b);
+  };
+
+  exports.isValidHex = function (hex) {
+    var isOk = /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(hex);
+    return isOk;
+  };
+
+  exports.isValidRGB = function (rgb) {
+    rgb = rgb.replace(' ', '');
+    var isOk = /rgb\((\d{1,3}),(\d{1,3}),(\d{1,3})\)/i.test(rgb);
+    return isOk;
+  };
+  exports.isValidRGBA = function (rgba) {
+    rgba = rgba.replace(' ', '');
+    var isOk = /rgba\((\d{1,3}),(\d{1,3}),(\d{1,3}),(.{1,3})\)/i.test(rgba);
+    return isOk;
+  };
+
+  /**
+   * This recursively redirects the prototype of JSON objects to the referenceObject
+   * This is used for default options.
+   *
+   * @param referenceObject
+   * @returns {*}
+   */
+  exports.selectiveBridgeObject = function (fields, referenceObject) {
+    if (typeof referenceObject == 'object') {
+      var objectTo = Object.create(referenceObject);
+      for (var i = 0; i < fields.length; i++) {
+        if (referenceObject.hasOwnProperty(fields[i])) {
+          if (typeof referenceObject[fields[i]] == 'object') {
+            objectTo[fields[i]] = exports.bridgeObject(referenceObject[fields[i]]);
+          }
+        }
+      }
+      return objectTo;
+    } else {
+      return null;
+    }
+  };
+
+  /**
+   * This recursively redirects the prototype of JSON objects to the referenceObject
+   * This is used for default options.
+   *
+   * @param referenceObject
+   * @returns {*}
+   */
+  exports.bridgeObject = function (referenceObject) {
+    if (typeof referenceObject == 'object') {
+      var objectTo = Object.create(referenceObject);
+      for (var i in referenceObject) {
+        if (referenceObject.hasOwnProperty(i)) {
+          if (typeof referenceObject[i] == 'object') {
+            objectTo[i] = exports.bridgeObject(referenceObject[i]);
+          }
+        }
+      }
+      return objectTo;
+    } else {
+      return null;
+    }
+  };
+
+  /**
+   * this is used to set the options of subobjects in the options object. A requirement of these subobjects
+   * is that they have an 'enabled' element which is optional for the user but mandatory for the program.
+   *
+   * @param [object] mergeTarget | this is either this.options or the options used for the groups.
+   * @param [object] options     | options
+   * @param [String] option      | this is the option key in the options argument
+   * @private
+   */
+  exports.mergeOptions = function (mergeTarget, options, option) {
+    var allowDeletion = arguments.length <= 3 || arguments[3] === undefined ? false : arguments[3];
+    var globalOptions = arguments.length <= 4 || arguments[4] === undefined ? {} : arguments[4];
+
+    if (options[option] === null) {
+      mergeTarget[option] = Object.create(globalOptions[option]);
+    } else {
+      if (options[option] !== undefined) {
+        if (typeof options[option] === 'boolean') {
+          mergeTarget[option].enabled = options[option];
+        } else {
+          if (options[option].enabled === undefined) {
+            mergeTarget[option].enabled = true;
+          }
+          for (var prop in options[option]) {
+            if (options[option].hasOwnProperty(prop)) {
+              mergeTarget[option][prop] = options[option][prop];
+            }
+          }
+        }
+      }
+    }
+  };
+
+  /**
+   * This function does a binary search for a visible item in a sorted list. If we find a visible item, the code that uses
+   * this function will then iterate in both directions over this sorted list to find all visible items.
+   *
+   * @param {Item[]} orderedItems       | Items ordered by start
+   * @param {function} searchFunction   | -1 is lower, 0 is found, 1 is higher
+   * @param {String} field
+   * @param {String} field2
+   * @returns {number}
+   * @private
+   */
+  exports.binarySearchCustom = function (orderedItems, searchFunction, field, field2) {
+    var maxIterations = 10000;
+    var iteration = 0;
+    var low = 0;
+    var high = orderedItems.length - 1;
+
+    while (low <= high && iteration < maxIterations) {
+      var middle = Math.floor((low + high) / 2);
+
+      var item = orderedItems[middle];
+      var value = field2 === undefined ? item[field] : item[field][field2];
+
+      var searchResult = searchFunction(value);
+      if (searchResult == 0) {
+        // jihaa, found a visible item!
+        return middle;
+      } else if (searchResult == -1) {
+        // it is too small --> increase low
+        low = middle + 1;
+      } else {
+        // it is too big --> decrease high
+        high = middle - 1;
+      }
+
+      iteration++;
+    }
+
+    return -1;
+  };
+
+  /**
+   * This function does a binary search for a specific value in a sorted array. If it does not exist but is in between of
+   * two values, we return either the one before or the one after, depending on user input
+   * If it is found, we return the index, else -1.
+   *
+   * @param {Array} orderedItems
+   * @param {{start: number, end: number}} target
+   * @param {String} field
+   * @param {String} sidePreference   'before' or 'after'
+   * @returns {number}
+   * @private
+   */
+  exports.binarySearchValue = function (orderedItems, target, field, sidePreference) {
+    var maxIterations = 10000;
+    var iteration = 0;
+    var low = 0;
+    var high = orderedItems.length - 1;
+    var prevValue, value, nextValue, middle;
+
+    while (low <= high && iteration < maxIterations) {
+      // get a new guess
+      middle = Math.floor(0.5 * (high + low));
+      prevValue = orderedItems[Math.max(0, middle - 1)][field];
+      value = orderedItems[middle][field];
+      nextValue = orderedItems[Math.min(orderedItems.length - 1, middle + 1)][field];
+
+      if (value == target) {
+        // we found the target
+        return middle;
+      } else if (prevValue < target && value > target) {
+        // target is in between of the previous and the current
+        return sidePreference == 'before' ? Math.max(0, middle - 1) : middle;
+      } else if (value < target && nextValue > target) {
+        // target is in between of the current and the next
+        return sidePreference == 'before' ? middle : Math.min(orderedItems.length - 1, middle + 1);
+      } else {
+        // didnt find the target, we need to change our boundaries.
+        if (value < target) {
+          // it is too small --> increase low
+          low = middle + 1;
+        } else {
+          // it is too big --> decrease high
+          high = middle - 1;
+        }
+      }
+      iteration++;
+    }
+
+    // didnt find anything. Return -1.
+    return -1;
+  };
+
+  /*
+   * Easing Functions - inspired from http://gizma.com/easing/
+   * only considering the t value for the range [0, 1] => [0, 1]
+   * https://gist.github.com/gre/1650294
+   */
+  exports.easingFunctions = {
+    // no easing, no acceleration
+    linear: function linear(t) {
+      return t;
+    },
+    // accelerating from zero velocity
+    easeInQuad: function easeInQuad(t) {
+      return t * t;
+    },
+    // decelerating to zero velocity
+    easeOutQuad: function easeOutQuad(t) {
+      return t * (2 - t);
+    },
+    // acceleration until halfway, then deceleration
+    easeInOutQuad: function easeInOutQuad(t) {
+      return t < .5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
+    },
+    // accelerating from zero velocity
+    easeInCubic: function easeInCubic(t) {
+      return t * t * t;
+    },
+    // decelerating to zero velocity
+    easeOutCubic: function easeOutCubic(t) {
+      return --t * t * t + 1;
+    },
+    // acceleration until halfway, then deceleration
+    easeInOutCubic: function easeInOutCubic(t) {
+      return t < .5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1;
+    },
+    // accelerating from zero velocity
+    easeInQuart: function easeInQuart(t) {
+      return t * t * t * t;
+    },
+    // decelerating to zero velocity
+    easeOutQuart: function easeOutQuart(t) {
+      return 1 - --t * t * t * t;
+    },
+    // acceleration until halfway, then deceleration
+    easeInOutQuart: function easeInOutQuart(t) {
+      return t < .5 ? 8 * t * t * t * t : 1 - 8 * --t * t * t * t;
+    },
+    // accelerating from zero velocity
+    easeInQuint: function easeInQuint(t) {
+      return t * t * t * t * t;
+    },
+    // decelerating to zero velocity
+    easeOutQuint: function easeOutQuint(t) {
+      return 1 + --t * t * t * t * t;
+    },
+    // acceleration until halfway, then deceleration
+    easeInOutQuint: function easeInOutQuint(t) {
+      return t < .5 ? 16 * t * t * t * t * t : 1 + 16 * --t * t * t * t * t;
+    }
+  };
+
+/***/ },
+/* 2 */
+/***/ function(module, exports, __webpack_require__) {
+
+  // first check if moment.js is already loaded in the browser window, if so,
+  // use this instance. Else, load via commonjs.
+  'use strict';
+
+  module.exports = typeof window !== 'undefined' && window['moment'] || __webpack_require__(3);
+
+/***/ },
+/* 3 */
+/***/ function(module, exports, __webpack_require__) {
+
+  /* WEBPACK VAR INJECTION */(function(module) {//! moment.js
+  //! version : 2.10.6
+  //! authors : Tim Wood, Iskren Chernev, Moment.js contributors
+  //! license : MIT
+  //! momentjs.com
+
+  (function (global, factory) {
+       true ? 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 Object.prototype.toString.call(input) === '[object Array]';
+      }
+
+      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
+          };
+      }
+
+      function getParsingFlags(m) {
+          if (m._pf == null) {
+              m._pf = defaultParsingFlags();
+          }
+          return m._pf;
+      }
+
+      function valid__isValid(m) {
+          if (m._isValid == null) {
+              var flags = getParsingFlags(m);
+              m._isValid = !isNaN(m._d.getTime()) &&
+                  flags.overflow < 0 &&
+                  !flags.empty &&
+                  !flags.invalidMonth &&
+                  !flags.invalidWeekday &&
+                  !flags.nullInput &&
+                  !flags.invalidFormat &&
+                  !flags.userInvalidated;
+
+              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;
+      }
+
+      var momentProperties = utils_hooks__hooks.momentProperties = [];
+
+      function copyConfig(to, from) {
+          var i, prop, val;
+
+          if (typeof from._isAMomentObject !== 'undefined') {
+              to._isAMomentObject = from._isAMomentObject;
+          }
+          if (typeof from._i !== 'undefined') {
+              to._i = from._i;
+          }
+          if (typeof from._f !== 'undefined') {
+              to._f = from._f;
+          }
+          if (typeof from._l !== 'undefined') {
+              to._l = from._l;
+          }
+          if (typeof from._strict !== 'undefined') {
+              to._strict = from._strict;
+          }
+          if (typeof from._tzm !== 'undefined') {
+              to._tzm = from._tzm;
+          }
+          if (typeof from._isUTC !== 'undefined') {
+              to._isUTC = from._isUTC;
+          }
+          if (typeof from._offset !== 'undefined') {
+              to._offset = from._offset;
+          }
+          if (typeof from._pf !== 'undefined') {
+              to._pf = getParsingFlags(from);
+          }
+          if (typeof from._locale !== 'undefined') {
+              to._locale = from._locale;
+          }
+
+          if (momentProperties.length > 0) {
+              for (i in momentProperties) {
+                  prop = momentProperties[i];
+                  val = from[prop];
+                  if (typeof val !== 'undefined') {
+                      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) {
+              return Math.ceil(number);
+          } else {
+              return Math.floor(number);
+          }
+      }
+
+      function toInt(argumentForCoercion) {
+          var coercedNumber = +argumentForCoercion,
+              value = 0;
+
+          if (coercedNumber !== 0 && isFinite(coercedNumber)) {
+              value = absFloor(coercedNumber);
+          }
+
+          return value;
+      }
+
+      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 Locale() {
+      }
+
+      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;
+                  !(function webpackMissingModule() { var e = new Error("Cannot find module \"./locale\""); e.code = 'MODULE_NOT_FOUND'; throw e; }());
+                  // 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 (typeof values === 'undefined') {
+                  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, values) {
+          if (values !== null) {
+              values.abbr = name;
+              locales[name] = locales[name] || new Locale();
+              locales[name].set(values);
+
+              // backwards compat for now: also set the locale
+              locale_locales__getSetGlobalLocale(name);
+
+              return locales[name];
+          } else {
+              // useful for testing
+              delete locales[name];
+              return null;
+          }
+      }
+
+      // 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);
+      }
+
+      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;
+      }
+
+      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._d['get' + (mom._isUTC ? 'UTC' : '') + unit]();
+      }
+
+      function get_set__set (mom, unit, value) {
+          return mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value);
+      }
+
+      // MOMENTS
+
+      function getSet (units, value) {
+          var unit;
+          if (typeof units === 'object') {
+              for (unit in units) {
+                  this.set(unit, units[unit]);
+              }
+          } else {
+              units = normalizeUnits(units);
+              if (typeof this[units] === 'function') {
+                  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 = /(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Q|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|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 = '';
+              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 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 matchTimestamp = /[+-]?\d+(\.\d{1,3})?/; // 123456789 123456789.123
+
+      // any word (or two) characters or numbers including two/three word month in arabic.
+      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 isFunction (sth) {
+          // https://github.com/moment/moment/issues/2325
+          return typeof sth === 'function' &&
+              Object.prototype.toString.call(sth) === '[object Function]';
+      }
+
+
+      function addRegexToken (token, regex, strictRegex) {
+          regexes[token] = isFunction(regex) ? regex : function (isStrict) {
+              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 s.replace('\\', '').replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) {
+              return p1 || p2 || p3 || p4;
+          }).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;
+
+      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');
+
+      // PARSING
+
+      addRegexToken('M',    match1to2);
+      addRegexToken('MM',   match1to2, match2);
+      addRegexToken('MMM',  matchWord);
+      addRegexToken('MMMM', matchWord);
+
+      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 defaultLocaleMonths = 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_');
+      function localeMonths (m) {
+          return this._months[m.month()];
+      }
+
+      var defaultLocaleMonthsShort = 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_');
+      function localeMonthsShort (m) {
+          return this._monthsShort[m.month()];
+      }
+
+      function localeMonthsParse (monthName, format, strict) {
+          var i, mom, regex;
+
+          if (!this._monthsParse) {
+              this._monthsParse = [];
+              this._longMonthsParse = [];
+              this._shortMonthsParse = [];
+          }
+
+          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;
+
+          // TODO: Move this out of here!
+          if (typeof value === 'string') {
+              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());
+      }
+
+      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;
+              }
+
+              getParsingFlags(m).overflow = overflow;
+          }
+
+          return m;
+      }
+
+      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 (firstTime) {
+                  warn(msg + '\n' + (new Error()).stack);
+                  firstTime = false;
+              }
+              return fn.apply(this, arguments);
+          }, fn);
+      }
+
+      var deprecations = {};
+
+      function deprecateSimple(name, msg) {
+          if (!deprecations[name]) {
+              warn(msg);
+              deprecations[name] = true;
+          }
+      }
+
+      utils_hooks__hooks.suppressDeprecationWarnings = false;
+
+      var from_string__isoRegex = /^\s*(?:[+-]\d{6}|\d{4})-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/;
+
+      var isoDates = [
+          ['YYYYYY-MM-DD', /[+-]\d{6}-\d{2}-\d{2}/],
+          ['YYYY-MM-DD', /\d{4}-\d{2}-\d{2}/],
+          ['GGGG-[W]WW-E', /\d{4}-W\d{2}-\d/],
+          ['GGGG-[W]WW', /\d{4}-W\d{2}/],
+          ['YYYY-DDD', /\d{4}-\d{3}/]
+      ];
+
+      // iso time formats and regexes
+      var isoTimes = [
+          ['HH:mm:ss.SSSS', /(T| )\d\d:\d\d:\d\d\.\d+/],
+          ['HH:mm:ss', /(T| )\d\d:\d\d:\d\d/],
+          ['HH:mm', /(T| )\d\d:\d\d/],
+          ['HH', /(T| )\d\d/]
+      ];
+
+      var aspNetJsonRegex = /^\/?Date\((\-?\d+)/i;
+
+      // date from iso format
+      function configFromISO(config) {
+          var i, l,
+              string = config._i,
+              match = from_string__isoRegex.exec(string);
+
+          if (match) {
+              getParsingFlags(config).iso = true;
+              for (i = 0, l = isoDates.length; i < l; i++) {
+                  if (isoDates[i][1].exec(string)) {
+                      config._f = isoDates[i][0];
+                      break;
+                  }
+              }
+              for (i = 0, l = isoTimes.length; i < l; i++) {
+                  if (isoTimes[i][1].exec(string)) {
+                      // match[6] should be 'T' or space
+                      config._f += (match[6] || ' ') + isoTimes[i][0];
+                      break;
+                  }
+              }
+              if (string.match(matchOffset)) {
+                  config._f += 'Z';
+              }
+              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 ' +
+          'https://github.com/moment/moment/issues/1407 for more info.',
+          function (config) {
+              config._d = new Date(config._i + (config._useUTC ? ' UTC' : ''));
+          }
+      );
+
+      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 doesn't accept years < 1970
+          if (y < 1970) {
+              date.setFullYear(y);
+          }
+          return date;
+      }
+
+      function createUTCDate (y) {
+          var date = new Date(Date.UTC.apply(null, arguments));
+          if (y < 1970) {
+              date.setUTCFullYear(y);
+          }
+          return date;
+      }
+
+      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');
+
+      // 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);
+      });
+
+      // 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', false);
+
+      function getIsLeapYear () {
+          return isLeapYear(this.year());
+      }
+
+      addFormatToken('w', ['ww', 2], 'wo', 'week');
+      addFormatToken('W', ['WW', 2], 'Wo', 'isoWeek');
+
+      // ALIASES
+
+      addUnitAlias('week', 'w');
+      addUnitAlias('isoWeek', 'W');
+
+      // 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
+
+      // firstDayOfWeek       0 = sun, 6 = sat
+      //                      the day of the week that starts the week
+      //                      (usually sunday or monday)
+      // firstDayOfWeekOfYear 0 = sun, 6 = sat
+      //                      the first week is the week that contains the first
+      //                      of this day of the week
+      //                      (eg. ISO weeks use thursday (4))
+      function weekOfYear(mom, firstDayOfWeek, firstDayOfWeekOfYear) {
+          var end = firstDayOfWeekOfYear - firstDayOfWeek,
+              daysToDayOfWeek = firstDayOfWeekOfYear - mom.day(),
+              adjustedMoment;
+
+
+          if (daysToDayOfWeek > end) {
+              daysToDayOfWeek -= 7;
+          }
+
+          if (daysToDayOfWeek < end - 7) {
+              daysToDayOfWeek += 7;
+          }
+
+          adjustedMoment = local__createLocal(mom).add(daysToDayOfWeek, 'd');
+          return {
+              week: Math.ceil(adjustedMoment.dayOfYear() / 7),
+              year: adjustedMoment.year()
+          };
+      }
+
+      // LOCALES
+
+      function localeWeek (mom) {
+          return weekOfYear(mom, this._week.dow, this._week.doy).week;
+      }
+
+      var defaultLocaleWeek = {
+          dow : 0, // Sunday is the first day of the week.
+          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');
+      }
+
+      addFormatToken('DDD', ['DDDD', 3], 'DDDo', 'dayOfYear');
+
+      // ALIASES
+
+      addUnitAlias('dayOfYear', 'DDD');
+
+      // PARSING
+
+      addRegexToken('DDD',  match1to3);
+      addRegexToken('DDDD', match3);
+      addParseToken(['DDD', 'DDDD'], function (input, array, config) {
+          config._dayOfYear = toInt(input);
+      });
+
+      // HELPERS
+
+      //http://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday
+      function dayOfYearFromWeeks(year, week, weekday, firstDayOfWeekOfYear, firstDayOfWeek) {
+          var week1Jan = 6 + firstDayOfWeek - firstDayOfWeekOfYear, janX = createUTCDate(year, 0, 1 + week1Jan), d = janX.getUTCDay(), dayOfYear;
+          if (d < firstDayOfWeek) {
+              d += 7;
+          }
+
+          weekday = weekday != null ? 1 * weekday : firstDayOfWeek;
+
+          dayOfYear = 1 + week1Jan + 7 * (week - 1) - d + weekday;
+
+          return {
+              year: dayOfYear > 0 ? year : year - 1,
+              dayOfYear: dayOfYear > 0 ?  dayOfYear : daysInYear(year - 1) + dayOfYear
+          };
+      }
+
+      // 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');
+      }
+
+      // 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) {
+          var now = new Date();
+          if (config._useUTC) {
+              return [now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()];
+          }
+          return [now.getFullYear(), now.getMonth(), now.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;
+
+          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);
+          } 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 < dow) {
+                      ++week;
+                  }
+              } else if (w.e != null) {
+                  // local weekday -- counting starts from begining of week
+                  weekday = w.e + dow;
+              } else {
+                  // default to begining of week
+                  weekday = dow;
+              }
+          }
+          temp = dayOfYearFromWeeks(weekYear, week, weekday, doy, dow);
+
+          config._a[YEAR] = temp.year;
+          config._dayOfYear = temp.dayOfYear;
+      }
+
+      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];
+              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 (getParsingFlags(config).bigHour === true &&
+                  config._a[HOUR] <= 12 &&
+                 

<TRUNCATED>