text: /**
  * The `Matter.Common` module contains utility functions that are common to all modules.
  *
  * @class Common
  */
  
  var Common = {};
  
  module.exports = Common;
  
  (function() {
  
      Common._timeUnit = 1000 / 60;
      Common._nextId = 0;
      Common._seed = 0;
      Common._nowStartTime = +(new Date());
      Common._warnedOnce = {};
      Common._decomp = null;
      
      /**
       * Extends the object in the first argument using the object in the second argument.
       * @method extend
       * @param {} obj
       * @param {boolean} deep
       * @return {} obj extended
       */
      Common.extend = function(obj, deep) {
          var argsStart,
              args,
              deepClone;
  
          if (typeof deep === 'boolean') {
              argsStart = 2;
              deepClone = deep;
          } else {
              argsStart = 1;
              deepClone = true;
          }
  
          for (var i = argsStart; i < arguments.length; i++) {
              var source = arguments[i];
  
              if (source) {
                  for (var prop in source) {
                      if (deepClone && source[prop] && source[prop].constructor === Object) {
                          if (!obj[prop] || obj[prop].constructor === Object) {
                              obj[prop] = obj[prop] || {};
                              Common.extend(obj[prop], deepClone, source[prop]);
                          } else {
                              obj[prop] = source[prop];
                          }
                      } else {
                          obj[prop] = source[prop];
                      }
                  }
              }
          }
          
          return obj;
      };
  
      /**
       * Creates a new clone of the object, if deep is true references will also be cloned.
       * @method clone
       * @param {} obj
       * @param {bool} deep
       * @return {} obj cloned
       */
      Common.clone = function(obj, deep) {
          return Common.extend({}, deep, obj);
      };
  
      /**
       * Returns the list of keys for the given object.
       * @method keys
       * @param {} obj
       * @return {string[]} keys
       */
      Common.keys = function(obj) {
          if (Object.keys)
              return Object.keys(obj);
  
          // avoid hasOwnProperty for performance
          var keys = [];
          for (var key in obj)
              keys.push(key);
          return keys;
      };
  
      /**
       * Returns the list of values for the given object.
       * @method values
       * @param {} obj
       * @return {array} Array of the objects property values
       */
      Common.values = function(obj) {
          var values = [];
          
          if (Object.keys) {
              var keys = Object.keys(obj);
              for (var i = 0; i < keys.length; i++) {
                  values.push(obj[keys[i]]);
              }
              return values;
          }
          
          // avoid hasOwnProperty for performance
          for (var key in obj)
              values.push(obj[key]);
          return values;
      };
  
      /**
       * Gets a value from `base` relative to the `path` string.
       * @method get
       * @param {} obj The base object
       * @param {string} path The path relative to `base`, e.g. 'Foo.Bar.baz'
       * @param {number} [begin] Path slice begin
       * @param {number} [end] Path slice end
       * @return {} The object at the given path
       */
      Common.get = function(obj, path, begin, end) {
          path = path.split('.').slice(begin, end);
  
          for (var i = 0; i < path.length; i += 1) {
              obj = obj[path[i]];
          }
  
          return obj;
      };
  
      /**
       * Sets a value on `base` relative to the given `path` string.
       * @method set
       * @param {} obj The base object
       * @param {string} path The path relative to `base`, e.g. 'Foo.Bar.baz'
       * @param {} val The value to set
       * @param {number} [begin] Path slice begin
       * @param {number} [end] Path slice end
       * @return {} Pass through `val` for chaining
       */
      Common.set = function(obj, path, val, begin, end) {
          var parts = path.split('.').slice(begin, end);
          Common.get(obj, path, 0, -1)[parts[parts.length - 1]] = val;
          return val;
      };
  
      /**
       * Shuffles the given array in-place.
       * The function uses a seeded random generator.
       * @method shuffle
       * @param {array} array
       * @return {array} array shuffled randomly
       */
      Common.shuffle = function(array) {
          for (var i = array.length - 1; i > 0; i--) {
              var j = Math.floor(Common.random() * (i + 1));
              var temp = array[i];
              array[i] = array[j];
              array[j] = temp;
          }
          return array;
      };
  
      /**
       * Randomly chooses a value from a list with equal probability.
       * The function uses a seeded random generator.
       * @method choose
       * @param {array} choices
       * @return {object} A random choice object from the array
       */
      Common.choose = function(choices) {
          return choices[Math.floor(Common.random() * choices.length)];
      };
  
      /**
       * Returns true if the object is a HTMLElement, otherwise false.
       * @method isElement
       * @param {object} obj
       * @return {boolean} True if the object is a HTMLElement, otherwise false
       */
      Common.isElement = function(obj) {
          if (typeof HTMLElement !== 'undefined') {
              return obj instanceof HTMLElement;
          }
  
          return !!(obj && obj.nodeType && obj.nodeName);
      };
  
      /**
       * Returns true if the object is an array.
       * @method isArray
       * @param {object} obj
       * @return {boolean} True if the object is an array, otherwise false
       */
      Common.isArray = function(obj) {
          return Object.prototype.toString.call(obj) === '[object Array]';
      };
  
      /**
       * Returns true if the object is a function.
       * @method isFunction
       * @param {object} obj
       * @return {boolean} True if the object is a function, otherwise false
       */
      Common.isFunction = function(obj) {
          return typeof obj === "function";
      };
  
      /**
       * Returns true if the object is a plain object.
       * @method isPlainObject
       * @param {object} obj
       * @return {boolean} True if the object is a plain object, otherwise false
       */
      Common.isPlainObject = function(obj) {
          return typeof obj === 'object' && obj.constructor === Object;
      };
  
      /**
       * Returns true if the object is a string.
       * @method isString
       * @param {object} obj
       * @return {boolean} True if the object is a string, otherwise false
       */
      Common.isString = function(obj) {
          return toString.call(obj) === '[object String]';
      };
      
      /**
       * Returns the given value clamped between a minimum and maximum value.
       * @method clamp
       * @param {number} value
       * @param {number} min
       * @param {number} max
       * @return {number} The value clamped between min and max inclusive
       */
      Common.clamp = function(value, min, max) {
          if (value < min)
              return min;
          if (value > max)
              return max;
          return value;
      };
      
      /**
       * Returns the sign of the given value.
       * @method sign
       * @param {number} value
       * @return {number} -1 if negative, +1 if 0 or positive
       */
      Common.sign = function(value) {
          return value < 0 ? -1 : 1;
      };
      
      /**
       * Returns the current timestamp since the time origin (e.g. from page load).
       * The result is in milliseconds and will use high-resolution timing if available.
       * @method now
       * @return {number} the current timestamp in milliseconds
       */
      Common.now = function() {
          if (typeof window !== 'undefined' && window.performance) {
              if (window.performance.now) {
                  return window.performance.now();
              } else if (window.performance.webkitNow) {
                  return window.performance.webkitNow();
              }
          }
  
          if (Date.now) {
              return Date.now();
          }
  
          return (new Date()) - Common._nowStartTime;
      };
      
      /**
       * Returns a random value between a minimum and a maximum value inclusive.
       * The function uses a seeded random generator.
       * @method random
       * @param {number} min
       * @param {number} max
       * @return {number} A random number between min and max inclusive
       */
      Common.random = function(min, max) {
          min = (typeof min !== "undefined") ? min : 0;
          max = (typeof max !== "undefined") ? max : 1;
          return min + _seededRandom() * (max - min);
      };
  
      var _seededRandom = function() {
          // https://en.wikipedia.org/wiki/Linear_congruential_generator
          Common._seed = (Common._seed * 9301 + 49297) % 233280;
          return Common._seed / 233280;
      };
  
      /**
       * Converts a CSS hex colour string into an integer.
       * @method colorToNumber
       * @param {string} colorString
       * @return {number} An integer representing the CSS hex string
       */
      Common.colorToNumber = function(colorString) {
          colorString = colorString.replace('#','');
  
          if (colorString.length == 3) {
              colorString = colorString.charAt(0) + colorString.charAt(0)
                          + colorString.charAt(1) + colorString.charAt(1)
                          + colorString.charAt(2) + colorString.charAt(2);
          }
  
          return parseInt(colorString, 16);
      };
  
      /**
       * The console logging level to use, where each level includes all levels above and excludes the levels below.
       * The default level is 'debug' which shows all console messages.  
       *
       * Possible level values are:
       * - 0 = None
       * - 1 = Debug
       * - 2 = Info
       * - 3 = Warn
       * - 4 = Error
       * @property Common.logLevel
       * @type {Number}
       * @default 1
       */
      Common.logLevel = 1;
  
      /**
       * Shows a `console.log` message only if the current `Common.logLevel` allows it.
       * The message will be prefixed with 'matter-js' to make it easily identifiable.
       * @method log
       * @param ...objs {} The objects to log.
       */
      Common.log = function() {
          if (console && Common.logLevel > 0 && Common.logLevel <= 3) {
              console.log.apply(console, ['matter-js:'].concat(Array.prototype.slice.call(arguments)));
          }
      };
  
      /**
       * Shows a `console.info` message only if the current `Common.logLevel` allows it.
       * The message will be prefixed with 'matter-js' to make it easily identifiable.
       * @method info
       * @param ...objs {} The objects to log.
       */
      Common.info = function() {
          if (console && Common.logLevel > 0 && Common.logLevel <= 2) {
              console.info.apply(console, ['matter-js:'].concat(Array.prototype.slice.call(arguments)));
          }
      };
  
      /**
       * Shows a `console.warn` message only if the current `Common.logLevel` allows it.
       * The message will be prefixed with 'matter-js' to make it easily identifiable.
       * @method warn
       * @param ...objs {} The objects to log.
       */
      Common.warn = function() {
          if (console && Common.logLevel > 0 && Common.logLevel <= 3) {
              console.warn.apply(console, ['matter-js:'].concat(Array.prototype.slice.call(arguments)));
          }
      };
  
      /**
       * Uses `Common.warn` to log the given message one time only.
       * @method warnOnce
       * @param ...objs {} The objects to log.
       */
      Common.warnOnce = function() {
          var message = Array.prototype.slice.call(arguments).join(' ');
  
          if (!Common._warnedOnce[message]) {
              Common.warn(message);
              Common._warnedOnce[message] = true;
          }
      };
  
      /**
       * Shows a deprecated console warning when the function on the given object is called.
       * The target function will be replaced with a new function that first shows the warning
       * and then calls the original function.
       * @method deprecated
       * @param {object} obj The object or module
       * @param {string} name The property name of the function on obj
       * @param {string} warning The one-time message to show if the function is called
       */
      Common.deprecated = function(obj, prop, warning) {
          obj[prop] = Common.chain(function() {
              Common.warnOnce('🔅 deprecated 🔅', warning);
          }, obj[prop]);
      };
  
      /**
       * Returns the next unique sequential ID.
       * @method nextId
       * @return {Number} Unique sequential ID
       */
      Common.nextId = function() {
          return Common._nextId++;
      };
  
      /**
       * A cross browser compatible indexOf implementation.
       * @method indexOf
       * @param {array} haystack
       * @param {object} needle
       * @return {number} The position of needle in haystack, otherwise -1.
       */
      Common.indexOf = function(haystack, needle) {
          if (haystack.indexOf)
              return haystack.indexOf(needle);
  
          for (var i = 0; i < haystack.length; i++) {
              if (haystack[i] === needle)
                  return i;
          }
  
          return -1;
      };
  
      /**
       * A cross browser compatible array map implementation.
       * @method map
       * @param {array} list
       * @param {function} func
       * @return {array} Values from list transformed by func.
       */
      Common.map = function(list, func) {
          if (list.map) {
              return list.map(func);
          }
  
          var mapped = [];
  
          for (var i = 0; i < list.length; i += 1) {
              mapped.push(func(list[i]));
          }
  
          return mapped;
      };
  
      /**
       * Takes a directed graph and returns the partially ordered set of vertices in topological order.
       * Circular dependencies are allowed.
       * @method topologicalSort
       * @param {object} graph
       * @return {array} Partially ordered set of vertices in topological order.
       */
      Common.topologicalSort = function(graph) {
          // https://github.com/mgechev/javascript-algorithms
          // Copyright (c) Minko Gechev (MIT license)
          // Modifications: tidy formatting and naming
          var result = [],
              visited = [],
              temp = [];
  
          for (var node in graph) {
              if (!visited[node] && !temp[node]) {
                  Common._topologicalSort(node, visited, temp, graph, result);
              }
          }
  
          return result;
      };
  
      Common._topologicalSort = function(node, visited, temp, graph, result) {
          var neighbors = graph[node] || [];
          temp[node] = true;
  
          for (var i = 0; i < neighbors.length; i += 1) {
              var neighbor = neighbors[i];
  
              if (temp[neighbor]) {
                  // skip circular dependencies
                  continue;
              }
  
              if (!visited[neighbor]) {
                  Common._topologicalSort(neighbor, visited, temp, graph, result);
              }
          }
  
          temp[node] = false;
          visited[node] = true;
  
          result.push(node);
      };
  
      /**
       * Takes _n_ functions as arguments and returns a new function that calls them in order.
       * The arguments applied when calling the new function will also be applied to every function passed.
       * The value of `this` refers to the last value returned in the chain that was not `undefined`.
       * Therefore if a passed function does not return a value, the previously returned value is maintained.
       * After all passed functions have been called the new function returns the last returned value (if any).
       * If any of the passed functions are a chain, then the chain will be flattened.
       * @method chain
       * @param ...funcs {function} The functions to chain.
       * @return {function} A new function that calls the passed functions in order.
       */
      Common.chain = function() {
          var funcs = [];
  
          for (var i = 0; i < arguments.length; i += 1) {
              var func = arguments[i];
  
              if (func._chained) {
                  // flatten already chained functions
                  funcs.push.apply(funcs, func._chained);
              } else {
                  funcs.push(func);
              }
          }
  
          var chain = function() {
              // https://github.com/GoogleChrome/devtools-docs/issues/53#issuecomment-51941358
              var lastResult,
                  args = new Array(arguments.length);
  
              for (var i = 0, l = arguments.length; i < l; i++) {
                  args[i] = arguments[i];
              }
  
              for (i = 0; i < funcs.length; i += 1) {
                  var result = funcs[i].apply(lastResult, args);
  
                  if (typeof result !== 'undefined') {
                      lastResult = result;
                  }
              }
  
              return lastResult;
          };
  
          chain._chained = funcs;
  
          return chain;
      };
  
      /**
       * Chains a function to excute before the original function on the given `path` relative to `base`.
       * See also docs for `Common.chain`.
       * @method chainPathBefore
       * @param {} base The base object
       * @param {string} path The path relative to `base`
       * @param {function} func The function to chain before the original
       * @return {function} The chained function that replaced the original
       */
      Common.chainPathBefore = function(base, path, func) {
          return Common.set(base, path, Common.chain(
              func,
              Common.get(base, path)
          ));
      };
  
      /**
       * Chains a function to excute after the original function on the given `path` relative to `base`.
       * See also docs for `Common.chain`.
       * @method chainPathAfter
       * @param {} base The base object
       * @param {string} path The path relative to `base`
       * @param {function} func The function to chain after the original
       * @return {function} The chained function that replaced the original
       */
      Common.chainPathAfter = function(base, path, func) {
          return Common.set(base, path, Common.chain(
              Common.get(base, path),
              func
          ));
      };
  
      /**
       * Provide the [poly-decomp](https://github.com/schteppe/poly-decomp.js) library module to enable
       * concave vertex decomposition support when using `Bodies.fromVertices` e.g. `Common.setDecomp(require('poly-decomp'))`.
       * @method setDecomp
       * @param {} decomp The [poly-decomp](https://github.com/schteppe/poly-decomp.js) library module.
       */
      Common.setDecomp = function(decomp) {
          Common._decomp = decomp;
      };
  
      /**
       * Returns the [poly-decomp](https://github.com/schteppe/poly-decomp.js) library module provided through `Common.setDecomp`,
       * otherwise returns the global `decomp` if set.
       * @method getDecomp
       * @return {} The [poly-decomp](https://github.com/schteppe/poly-decomp.js) library module if provided.
       */
      Common.getDecomp = function() {
          // get user provided decomp if set
          var decomp = Common._decomp;
  
          try {
              // otherwise from window global
              if (!decomp && typeof window !== 'undefined') {
                  decomp = window.decomp;
              }
      
              // otherwise from node global
              if (!decomp && typeof global !== 'undefined') {
                  decomp = global.decomp;
              }
          } catch (e) {
              // decomp not available
              decomp = null;
          }
  
          return decomp;
      };
  })();
  