Source: util.js

/**
 * Exception class.
 * @class
 * @name Exception
 * @exports Exception as Twilio.Exception
 * @memberOf Twilio
 * @param {string} message The exception message
 */
function TwilioException(message) {
  if (!(this instanceof TwilioException)) {
    return new TwilioException(message);
  }
  this.message = message;
}

/**
 * Returns the exception message.
 *
 * @return {string} The exception message.
 */
TwilioException.prototype.toString = function() {
  return `Twilio.Exception: ${this.message}`;
};

function average(values) {
  return values.reduce((t, v) => t + v) / values.length;
}

function difference(lefts, rights, getKey) {
  getKey = getKey || (a => a);
  const rightKeys = new Set(rights.map(getKey));
  return lefts.filter(left => !rightKeys.has(getKey(left)));
}

function isFirefox(navigator) {
  navigator = navigator || (typeof window === 'undefined'
    ? global.navigator : window.navigator);

  return navigator && typeof navigator.userAgent === 'string'
    && /firefox|fxios/i.test(navigator.userAgent);
}

function isEdge(navigator) {
  navigator = navigator || (typeof window === 'undefined'
    ? global.navigator : window.navigator);

  return navigator && typeof navigator.userAgent === 'string'
    && /edge\/\d+/i.test(navigator.userAgent);
}

function queryToJson(params) {
  if (!params) {
    return '';
  }

  return params.split('&').reduce((output, pair) => {
    const parts = pair.split('=');
    const key = parts[0];
    const value = decodeURIComponent((parts[1] || '').replace(/\+/g, '%20'));

    if (key) { output[key] = value; }
    return output;
  }, { });
}

exports.Exception = TwilioException;
exports.average = average;
exports.difference = difference;
exports.isFirefox = isFirefox;
exports.isEdge = isEdge;
exports.queryToJson = queryToJson;