<commit_before>var HID = require('node-hid');

var VENDOR_ID = 0x27B8;
var PRODUCT_ID = 0x01ED;

var REPORT_ID = 1;
var REPORT_LENGTH = 9;
var REPORT2_ID = 2;
var REPORT2_LENGTH = 61;
var NOTE_LENGTH = 50;

var _blink1HIDdevices = function() {
  return HID.devices(VENDOR_ID, PRODUCT_ID);
};

var devices = function() {
  var serialNumbers = [];

  _blink1HIDdevices().forEach(function(device) {
    serialNumbers.push(device.serialNumber);
  });

  return serialNumbers;
};

function Blink1(serialNumber) {
  var blink1HIDdevices = _blink1HIDdevices();

  if (blink1HIDdevices.length === 0) {
    throw new Error('No blink(1)\'s could be found');
  }

  var blink1HIDdevicePath = null;

  if (serialNumber === undefined) {
    serialNumber =  blink1HIDdevices[0].serialNumber;
  }

  blink1HIDdevices.some(function(blink1HIDdevice) {
    if (serialNumber === blink1HIDdevice.serialNumber) {
      blink1HIDdevicePath = blink1HIDdevice.path;
    }

    return (blink1HIDdevicePath !== null);
  });

  if (blink1HIDdevicePath === null) {
    throw new Error('No blink(1)\'s with serial number ' + serialNumber + ' could be found');
  }

  this.serialNumber = serialNumber;
  this.hidDevice = new HID.HID(blink1HIDdevicePath);
}

Blink1.prototype._sendCommand = function(/* command [, args ...]*/) {
  var featureReport = new Array(REPORT_LENGTH).fill(0);
  featureReport[0] = REPORT_ID;
  featureReport[1] = arguments[0].charCodeAt(0); // command
  var len = Math.min(arguments.length, featureReport.length);
  for (var i = 1; i < len; i++) {
    featureReport[i + 1] = arguments[i];
  }
  this.hidDevice.sendFeatureReport(featureReport);
};

Blink1.prototype._sendCommand2 = function(/* command [, args ...]*/) {
  var featureReport = new Array(REPORT2_LENGTH).fill(0);
  featureReport[0] = REPORT2_ID;
  featureReport[1] = arguments[0].charCodeAt(0); //command
  var len = Math.min(arguments.length, featureReport.length);
  for (var i = 1; i < len; i++) {
    featureReport[i + 1] = arguments[i];
  }
  this.hidDevice.sendFeatureReport(featureReport);
};

Blink1.prototype._isValidCallback = function(callback) {
  return (typeof callback === 'function');
};

Blink1.prototype._validateNumber = function(number, name, min, max) {
  if (typeof number !== 'number') {
    throw new Error(name + ' must be a number');
  }

  if (number < min || number > max) {
    throw new Error(name + ' must be between ' + min + ' and ' + max);
  }
};

Blink1.prototype._validateAddress = function(address) {
  this._validateNumber(address, 'address', 0, 0xffff);
};

Blink1.prototype._validateValue = function(value) {
  this._validateNumber(value, 'value', 0, 0xff);
};

Blink1.prototype._validateCount = function(value) {
  this._validateNumber(value, 'count', 0, 0xff);
};

Blink1.prototype._validateFadeMillis = function(fadeMillis) {
  this._validateNumber(fadeMillis, 'fadeMillis', 0, 0x9FFF6);
};

Blink1.prototype._validateRGB = function(r, g, b) {
  this._validateNumber(r, 'r', 0, 0xff);
  this._validateNumber(g, 'g', 0, 0xff);
  this._validateNumber(b, 'b', 0, 0xff);
};

Blink1.prototype._validateMillis = function(millis) {
  this._validateNumber(millis, 'millis', 0, 0x9FFF6);
};

Blink1.prototype._validatePosition = function(position) {
  this._validateNumber(position, 'position', 0, 31); // mk1:12, mk2:32
};

Blink1.prototype._validateIndex = function(index) {
  this._validateNumber(index, 'index', 0, 2);
};

Blink1.prototype._readResponse = function(callback) {
  if (this._isValidCallback(callback)) {
    callback.apply(this, [this.hidDevice.getFeatureReport(REPORT_ID, REPORT_LENGTH)]);
  }
};

Blink1.prototype._readResponse2 = function(callback) {
  if (this._isValidCallback(callback)) {
    callback.apply(this, [this.hidDevice.getFeatureReport(REPORT2_ID, REPORT2_LENGTH)]);
  }
};

Blink1.prototype.version = function(callback) {
  this._sendCommand('v');

  this._readResponse(function(response) {
    var version = Number.parseInt(String.fromCharCode(response[3])) * 100 +
                  Number.parseInt(String.fromCharCode(response[4]))
    if(this._isValidCallback(callback)) {
      callback(version);
    }
  });
};

Blink1.prototype.eeRead = function(address, callback) {
  this._validateAddress(address);

  this._sendCommand('e', address);

  this._readResponse(function(response) {
    var value = response[3];

    if(this._isValidCallback(callback)) {
      callback(value);
    }
  });
};

Blink1.prototype.eeWrite = function(address, value, callback) {
  this._validateAddress(address);
  this._validateValue(value);

  this._sendCommand('E', address, value);

  if(this._isValidCallback(callback)) {
    callback();
  }
};

Blink1.prototype.degamma = function(n) {
  return Math.floor(((1 << Math.floor(n / 32)) - 1) +
          Math.floor((1 << Math.floor(n / 32)) * Math.floor((n % 32) + 1) + 15) / 32);
};

Blink1.prototype.fadeToRGB = function(fadeMillis, r, g, b, index, callback) {
  this._validateFadeMillis(fadeMillis);
  this._validateRGB(r, g, b);

  var dms = fadeMillis / 10;

  if (this._isValidCallback(index)) {
    // backwards compatible API, no index
    callback = index;
    index = 0;
  } else if (index === undefined) {
    index = 0;
  }

  this._validateIndex(index);

  this._sendCommand('c', this.degamma(r), this.degamma(g), this.degamma(b), dms >> 8, dms % 0xff, index);

  if(this._isValidCallback(callback)) {
    setTimeout(callback, fadeMillis);
  }
};

Blink1.prototype.setRGB = function(r, g, b, callback) {
  this._validateRGB(r, g, b);

  this._sendCommand('n', this.degamma(r), this.degamma(g), this.degamma(b));

  if(this._isValidCallback(callback)) {
    callback();
  }
};

Blink1.prototype.off = function(callback) {
  this.setRGB(0, 0, 0, callback);
};

Blink1.prototype.rgb = function(index, callback) {
  if (this._isValidCallback(index)) {
    callback = index;
    index = 0;
  } else if (index === undefined) {
    index = 0;
  }

  this._sendCommand('r', index, 0, 0, 0, 0, index);

  this._readResponse(function(response) {
    var r = response[2];
    var g = response[3];
    var b = response[4];

    if(this._isValidCallback(callback)) {
      callback(r, g, b);
    }
  });
};

Blink1.prototype._serverDown = function(on, millis, callback) {
  var dms = millis / 10;

  this._sendCommand('D', on, dms >> 8, dms % 0xff);

  if(this._isValidCallback(callback)) {
    setTimeout(callback, millis);
  }
};

Blink1.prototype.enableServerDown = function(millis, callback) {
  this._validateMillis(millis);

  this._serverDown(1, millis, callback);
};

Blink1.prototype.disableServerDown = function(millis, callback) {
  this._validateMillis(millis);

  this._serverDown(0, millis, callback);
};

Blink1.prototype._play = function(play, position, callback) {
  this._sendCommand('p', play, position);

  if(this._isValidCallback(callback)) {
    callback();
  }
};

Blink1.prototype.play = function(position, callback) {
  this._validatePosition(position);

  this._play(1, position, callback);
};

Blink1.prototype._playLoop = function(play, position, endPosition, count, callback) {
  this._sendCommand('p', play, position, endPosition, count);

  if(this._isValidCallback(callback)) {
    callback();
  }
};

Blink1.prototype.playLoop = function(startPosition, endPosition, count, callback) {
  this._validatePosition(startPosition);
  this._validatePosition(endPosition);
  this._validateCount(count);

  this._playLoop(1, startPosition, endPosition, count, callback);
};

Blink1.prototype.pause = function(callback) {
  this._play(0, 0, callback);
};

Blink1.prototype.writePatternLine = function(fadeMillis, r, g, b, position, callback) {
  this._validateFadeMillis(fadeMillis);
  this._validateRGB(r, g, b);
  this._validatePosition(position);

  var dms = fadeMillis / 10;

  this._sendCommand('P', this.degamma(r), this.degamma(g), this.degamma(b), dms >> 8, dms % 0xff, position, 0);

  if(this._isValidCallback(callback)) {
    callback();
  }
};

Blink1.prototype.readPatternLine = function(position, callback) {
  this._validatePosition(position);

  this._sendCommand('R', 0, 0, 0, 0, 0, position, 0);

  this._readResponse(function(response) {
    var value = {
      r: response[2],
      g: response[3],
      b: response[4],
      fadeMillis: ((response[5] << 8) + (response[6] & 0xff)) * 10
    };

    if(this._isValidCallback(callback)) {
      callback(value);
    }
  });
};

Blink1.prototype.setLedN = function(index, callback) {
  this._validateIndex(index);

  this._sendCommand('l', index, 0,0 );

  if(this._isValidCallback(callback)) {
    callback();
  }
};

Blink1.prototype.savePattern = function(callback) {
  this._sendCommand('W', 0xBE, 0xEF, 0xCA, 0xFE, 0x00, 0x00);
  if(this._isValidCallback(callback)) {
    callback();
  }
};

Blink1.prototype.setStartupParams = function(param, callback) {
  // FIXME: check
  this._sendCommand('B', params.bootmode, params.playstart, params.playend, params.playcount,0,0);
  if(this._isValidCallback(callback)) {
    callback();
  }
};

Blink1.prototype.getStartupParams = function(callback) {
  // FIXME: check
  this._sendCommand('B');
  this._readResponse(function(response) {
    var params = { bootmode:  response[2],
                   playstart: response[3],
                   playend:   response[4],
                   playcount: response[5]
                 };
    if(this._isValidCallback(callback)) {
      callback(params);
    }
  });
};

Blink1.prototype.writeNote = function(noteId, noteData, callback ) {
  var data = []
  if( typeof(noteData) === 'string' ) {
    for(var i=0; i < noteData.length; i++) {
      data.push(noteData.charCodeAt(i));
    }
  }
  else if( Array.isArray(noteData) ) {
    data = noteData;
  }
  else { // unknown
    throw new Error('noteData must be String or Array');
  }
  // console.log("sending: noteId:"+noteId+" noteData:",data);
  this._sendCommand2('F', noteId, ...data);
  if(this._isValidCallback(callback)) {
    callback();
  }
};

Blink1.prototype.readNote = function(noteId, asString, callback) {
  if( typeof(asString) != 'boolean' ) {
    callback = asString
    asString = true
  }
  this._sendCommand2('f', noteId);
  this._readResponse2(function(response) {
    if(this._isValidCallback(callback)) {
      // skip over reaportId, cmd, noteId, only note data
      var data = response.slice(3, 3+NOTE_LENGTH);
      if( asString ) {
        data = String.fromCharCode(...data);
      }
      callback(data);
    }
  });
};

Blink1.prototype.goBootload = function(callback) {
  this._sendCommand2('G', 'o','B', 'o', 'o', 't');
  this._readResponse2(function(response) {
    if(this._isValidCallback(callback)) {
      callback();
    }
  });
};

Blink1.prototype.getId = function(callback) {
  this._sendCommand2('U');
  this._readResponse2(function(response) {
    if(this._isValidCallback(callback)) {
      var data = response.slice(1); // remove reportId
      callback(data);
    }
  });
};

Blink1.prototype.close = function(callback) {
	this.hidDevice.close();

  if(this._isValidCallback(callback)) {
    callback();
  }
};

Blink1.devices = devices;

module.exports = Blink1;
module.exports.Blink1 = Blink1; // backwards compatibility with older version
<commit_msg>add enableDegamma attribute to selectively disable gamma correction<commit_after>var HID = require('node-hid');

var VENDOR_ID = 0x27B8;
var PRODUCT_ID = 0x01ED;

var REPORT_ID = 1;
var REPORT_LENGTH = 9;
var REPORT2_ID = 2;
var REPORT2_LENGTH = 61;
var NOTE_LENGTH = 50;

var _blink1HIDdevices = function() {
  return HID.devices(VENDOR_ID, PRODUCT_ID);
};

var devices = function() {
  var serialNumbers = [];

  _blink1HIDdevices().forEach(function(device) {
    serialNumbers.push(device.serialNumber);
  });

  return serialNumbers;
};

function Blink1(serialNumber) {
  var blink1HIDdevices = _blink1HIDdevices();

  if (blink1HIDdevices.length === 0) {
    throw new Error('No blink(1)\'s could be found');
  }

  var blink1HIDdevicePath = null;

  if (serialNumber === undefined) {
    serialNumber =  blink1HIDdevices[0].serialNumber;
  }

  blink1HIDdevices.some(function(blink1HIDdevice) {
    if (serialNumber === blink1HIDdevice.serialNumber) {
      blink1HIDdevicePath = blink1HIDdevice.path;
    }

    return (blink1HIDdevicePath !== null);
  });

  if (blink1HIDdevicePath === null) {
    throw new Error('No blink(1)\'s with serial number ' + serialNumber + ' could be found');
  }

  this.enableDegamma = true;
  this.serialNumber = serialNumber;
  this.hidDevice = new HID.HID(blink1HIDdevicePath);
}

Blink1.prototype._sendCommand = function(/* command [, args ...]*/) {
  var featureReport = new Array(REPORT_LENGTH).fill(0);
  featureReport[0] = REPORT_ID;
  featureReport[1] = arguments[0].charCodeAt(0); // command
  var len = Math.min(arguments.length, featureReport.length);
  for (var i = 1; i < len; i++) {
    featureReport[i + 1] = arguments[i];
  }
  this.hidDevice.sendFeatureReport(featureReport);
};

Blink1.prototype._sendCommand2 = function(/* command [, args ...]*/) {
  var featureReport = new Array(REPORT2_LENGTH).fill(0);
  featureReport[0] = REPORT2_ID;
  featureReport[1] = arguments[0].charCodeAt(0); //command
  var len = Math.min(arguments.length, featureReport.length);
  for (var i = 1; i < len; i++) {
    featureReport[i + 1] = arguments[i];
  }
  this.hidDevice.sendFeatureReport(featureReport);
};

Blink1.prototype._isValidCallback = function(callback) {
  return (typeof callback === 'function');
};

Blink1.prototype._validateNumber = function(number, name, min, max) {
  if (typeof number !== 'number') {
    throw new Error(name + ' must be a number');
  }

  if (number < min || number > max) {
    throw new Error(name + ' must be between ' + min + ' and ' + max);
  }
};

Blink1.prototype._validateAddress = function(address) {
  this._validateNumber(address, 'address', 0, 0xffff);
};

Blink1.prototype._validateValue = function(value) {
  this._validateNumber(value, 'value', 0, 0xff);
};

Blink1.prototype._validateCount = function(value) {
  this._validateNumber(value, 'count', 0, 0xff);
};

Blink1.prototype._validateFadeMillis = function(fadeMillis) {
  this._validateNumber(fadeMillis, 'fadeMillis', 0, 0x9FFF6);
};

Blink1.prototype._validateRGB = function(r, g, b) {
  this._validateNumber(r, 'r', 0, 0xff);
  this._validateNumber(g, 'g', 0, 0xff);
  this._validateNumber(b, 'b', 0, 0xff);
};

Blink1.prototype._validateMillis = function(millis) {
  this._validateNumber(millis, 'millis', 0, 0x9FFF6);
};

Blink1.prototype._validatePosition = function(position) {
  this._validateNumber(position, 'position', 0, 31); // mk1:12, mk2:32
};

Blink1.prototype._validateIndex = function(index) {
  this._validateNumber(index, 'index', 0, 2);
};

Blink1.prototype._readResponse = function(callback) {
  if (this._isValidCallback(callback)) {
    callback.apply(this, [this.hidDevice.getFeatureReport(REPORT_ID, REPORT_LENGTH)]);
  }
};

Blink1.prototype._readResponse2 = function(callback) {
  if (this._isValidCallback(callback)) {
    callback.apply(this, [this.hidDevice.getFeatureReport(REPORT2_ID, REPORT2_LENGTH)]);
  }
};

Blink1.prototype.version = function(callback) {
  this._sendCommand('v');

  this._readResponse(function(response) {
    var version = Number.parseInt(String.fromCharCode(response[3])) * 100 +
                  Number.parseInt(String.fromCharCode(response[4]))
    if(this._isValidCallback(callback)) {
      callback(version);
    }
  });
};

Blink1.prototype.eeRead = function(address, callback) {
  this._validateAddress(address);

  this._sendCommand('e', address);

  this._readResponse(function(response) {
    var value = response[3];

    if(this._isValidCallback(callback)) {
      callback(value);
    }
  });
};

Blink1.prototype.eeWrite = function(address, value, callback) {
  this._validateAddress(address);
  this._validateValue(value);

  this._sendCommand('E', address, value);

  if(this._isValidCallback(callback)) {
    callback();
  }
};

Blink1.prototype.degamma = function(n) {
  if( this.enableDegamma == false ) { return n; }
  return Math.floor(((1 << Math.floor(n / 32)) - 1) +
          Math.floor((1 << Math.floor(n / 32)) * Math.floor((n % 32) + 1) + 15) / 32);
};

Blink1.prototype.fadeToRGB = function(fadeMillis, r, g, b, index, callback) {
  this._validateFadeMillis(fadeMillis);
  this._validateRGB(r, g, b);

  var dms = fadeMillis / 10;

  if (this._isValidCallback(index)) {
    // backwards compatible API, no index
    callback = index;
    index = 0;
  } else if (index === undefined) {
    index = 0;
  }

  this._validateIndex(index);

  this._sendCommand('c', this.degamma(r), this.degamma(g), this.degamma(b), dms >> 8, dms % 0xff, index);

  if(this._isValidCallback(callback)) {
    setTimeout(callback, fadeMillis);
  }
};

Blink1.prototype.setRGB = function(r, g, b, callback) {
  this._validateRGB(r, g, b);

  this._sendCommand('n', this.degamma(r), this.degamma(g), this.degamma(b));

  if(this._isValidCallback(callback)) {
    callback();
  }
};

Blink1.prototype.off = function(callback) {
  this.setRGB(0, 0, 0, callback);
};

Blink1.prototype.rgb = function(index, callback) {
  if (this._isValidCallback(index)) {
    callback = index;
    index = 0;
  } else if (index === undefined) {
    index = 0;
  }

  this._sendCommand('r', index, 0, 0, 0, 0, index);

  this._readResponse(function(response) {
    var r = response[2];
    var g = response[3];
    var b = response[4];

    if(this._isValidCallback(callback)) {
      callback(r, g, b);
    }
  });
};

Blink1.prototype._serverDown = function(on, millis, callback) {
  var dms = millis / 10;

  this._sendCommand('D', on, dms >> 8, dms % 0xff);

  if(this._isValidCallback(callback)) {
    setTimeout(callback, millis);
  }
};

Blink1.prototype.enableServerDown = function(millis, callback) {
  this._validateMillis(millis);

  this._serverDown(1, millis, callback);
};

Blink1.prototype.disableServerDown = function(millis, callback) {
  this._validateMillis(millis);

  this._serverDown(0, millis, callback);
};

Blink1.prototype._play = function(play, position, callback) {
  this._sendCommand('p', play, position);

  if(this._isValidCallback(callback)) {
    callback();
  }
};

Blink1.prototype.play = function(position, callback) {
  this._validatePosition(position);

  this._play(1, position, callback);
};

Blink1.prototype._playLoop = function(play, position, endPosition, count, callback) {
  this._sendCommand('p', play, position, endPosition, count);

  if(this._isValidCallback(callback)) {
    callback();
  }
};

Blink1.prototype.playLoop = function(startPosition, endPosition, count, callback) {
  this._validatePosition(startPosition);
  this._validatePosition(endPosition);
  this._validateCount(count);

  this._playLoop(1, startPosition, endPosition, count, callback);
};

Blink1.prototype.pause = function(callback) {
  this._play(0, 0, callback);
};

Blink1.prototype.writePatternLine = function(fadeMillis, r, g, b, position, callback) {
  this._validateFadeMillis(fadeMillis);
  this._validateRGB(r, g, b);
  this._validatePosition(position);

  var dms = fadeMillis / 10;

  this._sendCommand('P', this.degamma(r), this.degamma(g), this.degamma(b), dms >> 8, dms % 0xff, position, 0);

  if(this._isValidCallback(callback)) {
    callback();
  }
};

Blink1.prototype.readPatternLine = function(position, callback) {
  this._validatePosition(position);

  this._sendCommand('R', 0, 0, 0, 0, 0, position, 0);

  this._readResponse(function(response) {
    var value = {
      r: response[2],
      g: response[3],
      b: response[4],
      fadeMillis: ((response[5] << 8) + (response[6] & 0xff)) * 10
    };

    if(this._isValidCallback(callback)) {
      callback(value);
    }
  });
};

Blink1.prototype.setLedN = function(index, callback) {
  this._validateIndex(index);

  this._sendCommand('l', index, 0,0 );

  if(this._isValidCallback(callback)) {
    callback();
  }
};

Blink1.prototype.savePattern = function(callback) {
  this._sendCommand('W', 0xBE, 0xEF, 0xCA, 0xFE, 0x00, 0x00);
  if(this._isValidCallback(callback)) {
    callback();
  }
};

Blink1.prototype.setStartupParams = function(param, callback) {
  // FIXME: check
  this._sendCommand('B', params.bootmode, params.playstart, params.playend, params.playcount,0,0);
  if(this._isValidCallback(callback)) {
    callback();
  }
};

Blink1.prototype.getStartupParams = function(callback) {
  // FIXME: check
  this._sendCommand('B');
  this._readResponse(function(response) {
    var params = { bootmode:  response[2],
                   playstart: response[3],
                   playend:   response[4],
                   playcount: response[5]
                 };
    if(this._isValidCallback(callback)) {
      callback(params);
    }
  });
};

Blink1.prototype.writeNote = function(noteId, noteData, callback ) {
  var data = []
  if( typeof(noteData) === 'string' ) {
    for(var i=0; i < noteData.length; i++) {
      data.push(noteData.charCodeAt(i));
    }
  }
  else if( Array.isArray(noteData) ) {
    data = noteData;
  }
  else { // unknown
    throw new Error('noteData must be String or Array');
  }
  // console.log("sending: noteId:"+noteId+" noteData:",data);
  this._sendCommand2('F', noteId, ...data);
  if(this._isValidCallback(callback)) {
    callback();
  }
};

Blink1.prototype.readNote = function(noteId, asString, callback) {
  if( typeof(asString) != 'boolean' ) {
    callback = asString
    asString = true
  }
  this._sendCommand2('f', noteId);
  this._readResponse2(function(response) {
    if(this._isValidCallback(callback)) {
      // skip over reaportId, cmd, noteId, only note data
      var data = response.slice(3, 3+NOTE_LENGTH);
      if( asString ) {
        data = String.fromCharCode(...data);
      }
      callback(data);
    }
  });
};

Blink1.prototype.goBootload = function(callback) {
  this._sendCommand2('G', 'o','B', 'o', 'o', 't');
  this._readResponse2(function(response) {
    if(this._isValidCallback(callback)) {
      callback();
    }
  });
};

Blink1.prototype.getId = function(callback) {
  this._sendCommand2('U');
  this._readResponse2(function(response) {
    if(this._isValidCallback(callback)) {
      var data = response.slice(1); // remove reportId
      callback(data);
    }
  });
};

Blink1.prototype.close = function(callback) {
	this.hidDevice.close();

  if(this._isValidCallback(callback)) {
    callback();
  }
};

Blink1.devices = devices;

module.exports = Blink1;
module.exports.Blink1 = Blink1; // backwards compatibility with older version
<|endoftext|>


<commit_before>/*global chrome queue*/
(function(){
function getHostname(url) {
  var a = document.createElement('a');
  a.href = url;
  return a.hostname;
}

// Returns whether or not a URL is either HTTP or HTTPS.
function urlIsHttp(url) {
  var a = document.createElement('a');
  a.href = url;
  return a.protocol == 'http:' || a.protocol == 'https:' ;
}

function getHostnameFromUrl(url) {
  return urlIsHttp(url) ? getHostname(url) : null;
}

function getDomainProfiles(cb) {
  var xhr = new XMLHttpRequest();
  xhr.onload = function() {
    return cb(null, JSON.parse(xhr.responseText));
  };
  xhr.open("GET", "/domainprofiles.json", true);
  xhr.send();
}

function blotString(info) {
  var base = info.domain;
  if (info.email) base = info.email + ' ' + base;
  if (info.salt) base = base + ' ' + info.salt;
  return base;
}

function getLocalNamespaces(namespaces,cb) {
  return chrome.storage.local.get(null, function(items) {
    var results = {};
    namespaces.forEach(function(namespace) {
      results[namespace] = {};
    });
    Object.keys(items).forEach(function (key) {
      namespaces.forEach(function(namespace) {
        var prefix = namespace + '.';
        if (key.slice(0,prefix.length) == prefix) {
          results[namespace][key.slice(prefix.length)] = items.key;
        }
      });
    });
    return cb(null, results);
  });
}

function getDefaults(cb){
  getLocalNamespaces(['defaults'], function(err,res) {
    return cb(err,res.defaults);
  });
}

function getDomainAndInfo(hostname, cb) {
  var components = hostname.split('.');
  queue()
    .defer(getDomainProfiles)
    .defer(getLocalNamespaces, ['records', 'defaults'])
    .await(function(err, profiles, local) {
      var records = local.records;
      var i = 0;
      // For every level of the domain by specificity
      while (i < components.length) {
        var domain = components.slice(i, components.length).join('.');

        // If there is a profile or record for this domain
        if (profiles[domain] || records[domain]) {
          return cb(null,{
            domain: domain,
            profile: profiles[domain],
            record: records[domain],
            defaults: local.defaults
          });
        }

        ++i;
      }
      // if no profile or record found
      return cb(null,{
        domain:
          // strip 'www' prefix, if present
          // check lastIndexOf because if www appears multiple times in
          // the components, something freaky is going on, and we're not
          // going to touch that
          components.lastIndexOf('www') == 0 ? components.slice(1).join('.')
            : hostname,
        defaults: local.defaults
      });
    });
}

window.blotpw = {
  blotString: blotString,
  getHostnameFromUrl: getHostnameFromUrl,
  getDomainAndInfo: getDomainAndInfo,
  getDefaults: getDefaults
};
})();
<commit_msg>Index correctly<commit_after>/*global chrome queue*/
(function(){
function getHostname(url) {
  var a = document.createElement('a');
  a.href = url;
  return a.hostname;
}

// Returns whether or not a URL is either HTTP or HTTPS.
function urlIsHttp(url) {
  var a = document.createElement('a');
  a.href = url;
  return a.protocol == 'http:' || a.protocol == 'https:' ;
}

function getHostnameFromUrl(url) {
  return urlIsHttp(url) ? getHostname(url) : null;
}

function getDomainProfiles(cb) {
  var xhr = new XMLHttpRequest();
  xhr.onload = function() {
    return cb(null, JSON.parse(xhr.responseText));
  };
  xhr.open("GET", "/domainprofiles.json", true);
  xhr.send();
}

function blotString(info) {
  var base = info.domain;
  if (info.email) base = info.email + ' ' + base;
  if (info.salt) base = base + ' ' + info.salt;
  return base;
}

function getLocalNamespaces(namespaces,cb) {
  return chrome.storage.local.get(null, function(items) {
    var results = {};
    namespaces.forEach(function(namespace) {
      results[namespace] = {};
    });
    Object.keys(items).forEach(function (key) {
      namespaces.forEach(function(namespace) {
        var prefix = namespace + '.';
        if (key.slice(0,prefix.length) == prefix) {
          results[namespace][key.slice(prefix.length)] = items[key];
        }
      });
    });
    return cb(null, results);
  });
}

function getDefaults(cb){
  getLocalNamespaces(['defaults'], function(err,res) {
    return cb(err,res.defaults);
  });
}

function getDomainAndInfo(hostname, cb) {
  var components = hostname.split('.');
  queue()
    .defer(getDomainProfiles)
    .defer(getLocalNamespaces, ['records', 'defaults'])
    .await(function(err, profiles, local) {
      var records = local.records;
      var i = 0;
      // For every level of the domain by specificity
      while (i < components.length) {
        var domain = components.slice(i, components.length).join('.');

        // If there is a profile or record for this domain
        if (profiles[domain] || records[domain]) {
          return cb(null,{
            domain: domain,
            profile: profiles[domain],
            record: records[domain],
            defaults: local.defaults
          });
        }

        ++i;
      }
      // if no profile or record found
      return cb(null,{
        domain:
          // strip 'www' prefix, if present
          // check lastIndexOf because if www appears multiple times in
          // the components, something freaky is going on, and we're not
          // going to touch that
          components.lastIndexOf('www') == 0 ? components.slice(1).join('.')
            : hostname,
        defaults: local.defaults
      });
    });
}

window.blotpw = {
  blotString: blotString,
  getHostnameFromUrl: getHostnameFromUrl,
  getDomainAndInfo: getDomainAndInfo,
  getDefaults: getDefaults
};
})();
<|endoftext|>


<commit_before>var express = require("express");
var app = express();
var passport = require('passport');
var FacebookStrategy = require('passport-facebook').Strategy;

app.use(express.cookieParser());
app.use(express.session({secret: process.env.SUPER_SECRET_SESSIONS_KEY}));

passport.use(new FacebookStrategy({
    clientID: process.env.FACEBOOK_APP_ID,
    clientSecret: process.env.FACEBOOK_APP_SECRET,
    callbackURL: "http://energiesbalanced.herokuapp.com/auth/facebook/callback"
  },
  function(accessToken, refreshToken, profile, done) {
    console.log(accessToken);
    console.log(refreshToken);
    console.log(profile);
    console.log(done);
  }
));

// Redirect the user to Facebook for authentication.  When complete,
// Facebook will redirect the user back to the application at
//     /auth/facebook/callback
app.get('/auth/facebook', passport.authenticate('facebook'));

// Facebook will redirect the user to this URL after approval.  Finish the
// authentication process by attempting to obtain an access token.  If
// access was granted, the user will be logged in.  Otherwise,
// authentication has failed.
app.get('/auth/facebook/callback',
  passport.authenticate('facebook', { successRedirect: '/',
                                      failureRedirect: '/login' }));

app.use(express.logger());
app.use(express.static(__dirname + '/public'));
var port = process.env.PORT || 5000;
app.listen(port, function() {
  console.log("Listening on " + port);
});<commit_msg>more of same<commit_after>var express = require("express");
var app = express();
var passport = require('passport');
var FacebookStrategy = require('passport-facebook').Strategy;

app.configure(function() {
  app.use(express.static('public'));
  app.use(express.cookieParser());
  app.use(express.bodyParser());
  app.use(express.session({ secret: process.env.SUPER_SECRET_SESSIONS_KEY}));
  app.use(passport.initialize());
  app.use(passport.session());
  app.use(app.router);
});

passport.use(new FacebookStrategy({
    clientID: process.env.FACEBOOK_APP_ID,
    clientSecret: process.env.FACEBOOK_APP_SECRET,
    callbackURL: "http://energiesbalanced.herokuapp.com/auth/facebook/callback"
  },
  function(accessToken, refreshToken, profile, done) {
    console.log(accessToken);
    console.log(refreshToken);
    console.log(profile);
    console.log(done);
  }
));

passport.serializeUser(function(user, done) {
  done(null, user);
});

passport.deserializeUser(function(user, done) {
    done(err, user);
});

app.get('/session', function(req, response){
  response.send({session: req.session.user});
});

// Redirect the user to Facebook for authentication.  When complete,
// Facebook will redirect the user back to the application at
//     /auth/facebook/callback
app.get('/auth/facebook', passport.authenticate('facebook'));

// Facebook will redirect the user to this URL after approval.  Finish the
// authentication process by attempting to obtain an access token.  If
// access was granted, the user will be logged in.  Otherwise,
// authentication has failed.
app.get('/auth/facebook/callback',
  passport.authenticate('facebook', {
  	successRedirect: '/',
    failureRedirect: '/login'
  }, function(req, resp){
  	   req.session
  }));

app.use(express.logger());
app.use(express.static(__dirname + '/public'));
var port = process.env.PORT || 5000;
app.listen(port, function() {
  console.log("Listening on " + port);
});<|endoftext|>


<commit_before>/**
 * AuthController
 * @description :: Server-side logic for manage user's authorization
 */

var passport = require('passport');

module.exports = {
    /**
     * Sign in by local strategy in passport
     */
    signin: function (req, res) {
        passport.authenticate('local', function (error, user, info) {
            if (error) {
                sails.log.error(error);
                res.serverError(error);
            } else if (info) {
                res.unauthorized(null, info.code, info.message);
            } else {
                res.ok({
                    token: CipherService.create('jwt', {id: user.id}).hashSync(),
                    user: user
                });
            }
        })(req, res);
    },

    /**
     * Sign up in system
     */
    signup: function (req, res) {
        // TODO: think about model duplicate

        User
            .create(req.allParams())
            .exec(function (error, user) {
                if (error) {
                    sails.log.error(error);
                    res.serverError(error);
                } else {
                    res.ok({
                        token: CipherService.create('jwt', {id: user.id}).hashSync(),
                        user: user
                    });
                }
            });
    },

    /**
     * Facebook authorization\linking
     */
    facebook: function (req, res) {
        passport.authenticate('jwt', function (error, user) {
            req.user = user;

            passport.authenticate('facebook-token', function (error, user, info) {
                if (error) {
                    sails.log.error(error);
                    res.serverError(error);
                } else if (info) {
                    res.unauthorized(null, info.code, info.message);
                } else {
                    res.ok({
                        token: CipherService.create('jwt', {id: user.id}).hashSync(),
                        user: user
                    });
                }
            })(req, res);
        })(req, res);
    },

    /**
     * Twitter authorization\linking
     */
    twitter: function (req, res) {
        passport.authenticate('jwt', function (error, user) {
            req.user = user;

            passport.authenticate('twitter-token', function (error, user, info) {
                if (error) {
                    sails.log.error(error);
                    res.serverError(error);
                } else if (info) {
                    res.unauthorized(null, info.code, info.message);
                } else {
                    res.ok({
                        token: CipherService.create('jwt', {id: user.id}).hashSync(),
                        user: user
                    });
                }
            })(req, res);
        })(req, res);
    }
};
<commit_msg>Replace ok with created response<commit_after>/**
 * AuthController
 * @description :: Server-side logic for manage user's authorization
 */

var passport = require('passport');

module.exports = {
    /**
     * Sign in by local strategy in passport
     */
    signin: function (req, res) {
        passport.authenticate('local', function (error, user, info) {
            if (error) {
                sails.log.error(error);
                res.serverError(error);
            } else if (info) {
                res.unauthorized(null, info.code, info.message);
            } else {
                res.ok({
                    token: CipherService.create('jwt', {id: user.id}).hashSync(),
                    user: user
                });
            }
        })(req, res);
    },

    /**
     * Sign up in system
     */
    signup: function (req, res) {
        // TODO: think about model duplicate

        User
            .create(req.allParams())
            .exec(function (error, user) {
                if (error) {
                    sails.log.error(error);
                    res.serverError(error);
                } else {
                    res.created({
                        token: CipherService.create('jwt', {id: user.id}).hashSync(),
                        user: user
                    });
                }
            });
    },

    /**
     * Facebook authorization\linking
     */
    facebook: function (req, res) {
        passport.authenticate('jwt', function (error, user) {
            req.user = user;

            passport.authenticate('facebook-token', function (error, user, info) {
                if (error) {
                    sails.log.error(error);
                    res.serverError(error);
                } else if (info) {
                    res.unauthorized(null, info.code, info.message);
                } else {
                    res.ok({
                        token: CipherService.create('jwt', {id: user.id}).hashSync(),
                        user: user
                    });
                }
            })(req, res);
        })(req, res);
    },

    /**
     * Twitter authorization\linking
     */
    twitter: function (req, res) {
        passport.authenticate('jwt', function (error, user) {
            req.user = user;

            passport.authenticate('twitter-token', function (error, user, info) {
                if (error) {
                    sails.log.error(error);
                    res.serverError(error);
                } else if (info) {
                    res.unauthorized(null, info.code, info.message);
                } else {
                    res.ok({
                        token: CipherService.create('jwt', {id: user.id}).hashSync(),
                        user: user
                    });
                }
            })(req, res);
        })(req, res);
    }
};
<|endoftext|>


<commit_before>const User = require('./../user');
const {encode, decode, CLIENT_ID_PATTERN} = require('../utils');
const assert = require('assert');
const _ = require('lodash');
const jwt = require('jsonwebtoken');
const expressJwt = require('express-jwt');
const jwks = require('jwks-rsa');
const Debug = require('debug');
const auth0js = require('auth0-js');
const request = require('superagent');

const debug = Debug('handlers.mozilla-auth0');

class Handler {
  constructor({name, cfg}) {
    let handlerCfg = cfg.handlers[name];
    assert(handlerCfg.domain, `${name}.domain is required`);
    assert(handlerCfg.apiAudience, `${name}.apiAudience is required`);
    assert(handlerCfg.clientId, `${name}.clientId is required`);
    assert(handlerCfg.clientSecret, `${name}.clientSecret is required`);
    _.assign(this, handlerCfg);

    // use express-jwt to validate JWTs against auth0
    this.jwtCheck = expressJwt({
      secret: jwks.expressJwtSecret({
        cache: true,
        rateLimit: true,
        jwksRequestsPerMinute: 5,
        jwksUri: `https://${this.domain}/.well-known/jwks.json`,
      }),
      // expect to see our audience in the JWT
      audience: this.apiAudience,
      // and expect a token issued by auth0
      issuer: `https://${this.domain}/`,
      algorithms: ['RS256'],
      credentialsRequired: true,
    });

    this._managementApiExp = null;
    this._managementApi = null;
    this._identityProviderId = 'mozilla-auth0';
  }

  get identityProviderId() {
    return this._identityProviderId;
  }

  // Get a management API instance, by requesting an API token as needed
  // see https://auth0.com/docs/api/management/v2/tokens
  async getManagementApi() {
    if (this._managementApi && new Date().getTime() / 1000 < this._managementApiExp - 10) {
      return this._managementApi;
    }

    let res = await request.post(`https://${this.domain}/oauth/token`)
      .set('content-type', 'application/json')
      .send({
        grant_type: 'client_credentials',
        client_id: this.clientId,
        client_secret: this.clientSecret,
        audience: `https://${this.domain}/api/v2/`,
      });

    let token = JSON.parse(res.text).access_token;
    if (!token) {
      throw new Error('did not receive a token from Auth0 /oauth/token endpoint');
    }

    // parse the token just enough to figure out when it expires
    let decoded = jwt.decode(token);
    let expires = decoded.exp;

    // create a new
    this._managementApi = new auth0js.Management({
      domain: this.domain,
      token: token,
    });
    this._managementApiExp = expires;

    return this._managementApi;
  }

  async profileFromUserId(userId) {
    const a0 = await this.getManagementApi();

    const profile = new Promise((resolve, reject) =>
      a0.getUser(userId, (err, prof) => err ? reject(err) : resolve(prof)));

    return profile;
  }

  async userFromRequest(req, res) {
    // check the JWT's validity, setting req.user if sucessful
    try {
      await new Promise((resolve, reject) =>
        this.jwtCheck(req, res, (err) => err ? reject(err) : resolve()));
    } catch (err) {
      debug(`error validating jwt: ${err}`);
      return;
    }

    debug(`received valid access_token for subject ${req.user.sub}`);

    let scopes = req.user.scope ? req.user.scope.split(' ') : [];
    if (!scopes.includes('taskcluster-credentials')) {
      debug(`request did not have the 'taskcluster-credentials' scope; had ${req.user.scope}`);
      return;
    }

    try {
      const profile = await this.profileFromUserId(req.user.sub);

      if ('active' in profile && !profile.active) {
        debug('user is not active; rejecting');
        return;
      }

      const user = this.userFromProfile(profile);
      user.expires = new Date(req.user.exp * 1000);

      return user;
    } catch (err) {
      debug(`error retrieving profile: ${err}`);
      return;
    }
  }

  async userFromUserId(userId) {
    try {
      const profile = await this.profileFromUserId(userId);
      const user = this.userFromProfile(profile);

      return user;
    } catch (err) {
      debug(`error retrieving profile: ${err}`);
      return;
    }
  }

  userFromClientId(clientId) {
    const userId = this.userIdFromClientId(clientId);
    if (!userId) {
      return;
    }

    return this.userFromUserId(userId);
  }

  identityFromClientId(clientId) {
    const patternMatch = CLIENT_ID_PATTERN.exec(clientId);
    return patternMatch && patternMatch[1];
  }

  userIdFromClientId(clientId) {
    const identity = this.identityFromClientId(clientId);

    if (!identity) {
      return;
    }

    let encodedUserId = identity.split('/')[1];

    // Reverse the username appending, stripping the username.
    if (encodedUserId.startsWith('github|') || encodedUserId.startsWith('oauth2|firefoxaccounts|')) {
      encodedUserId = encodedUserId.replace(/\|[^|]*$/, '');
    }

    return decode(encodedUserId);
  }

  identityFromProfile(profile) {
    let identity;

    // Look for a profile.identities element we recognize.  In practice, this is a one-element
    // array as we do not use Auth0 user linking.
    profile.identities.forEach(({provider, connection}) => {
      if (
        provider === 'ad' && connection === 'Mozilla-LDAP' ||
        // The 'email' connection corresponds to a passwordless login.
        provider === 'email' && connection === 'email' ||
        provider === 'google-oauth2' && connection === 'google-oauth2'
      ) {
        assert(!profile.user_id.startsWith('github|'));
        identity = `${this.identityProviderId}/${encode(profile.user_id)}`;
      // we annotate some userids with `|nickname` since otherwise the userid
      // is just numeric and difficult for humans to interpret
      } else if (provider === 'github' && connection === 'github') {
        assert(profile.user_id.startsWith('github|'));
        identity = `${this.identityProviderId}/${encode(profile.user_id)}|${profile.nickname}`;
      } else if (provider === 'oauth2' && connection === 'firefoxaccounts') {
        assert(profile.user_id.startsWith('oauth2|firefoxaccounts|'));
        identity = `${this.identityProviderId}/${encode(profile.user_id)}|${profile.nickname}`;
      }
    });

    return identity;
  }

  userFromProfile(profile) {
    const user = new User();

    user.identity = this.identityFromProfile(profile);
    if (!user.identity) {
      debug('No recognized identity providers');
      return;
    }

    // take a user and attach roles to it
    this.addRoles(profile, user);

    return user;
  }

  addRoles(profile, user) {
    const mozGroupPrefix = 'mozilliansorg_';
    const hrisGroupPrefix = 'hris_';
    const groups = Array.from(new Set([
      ...profile.groups || [],
      ...(profile.app_metadata || {}).groups || [],
    ]));

    // Non-prefixed groups are what is known as Mozilla LDAP groups. Groups prefixed by a provider
    // name and underscore are provided by a specific group engine. For example,
    // `providername_groupone` is provided by `providername`. Per https://goo.gl/bwWjvE.
    // For our own purposes, if the prefix is not mozilliansorg. then we treat it as an ldap group
    user.addRole(
      ...groups
        .filter(g => !g.startsWith(hrisGroupPrefix))
        .filter(g => !g.startsWith(mozGroupPrefix))
        .map(g => `mozilla-group:${g}`)
    );
    user.addRole(
      ...groups
        .filter(g => !g.startsWith(hrisGroupPrefix))
        .filter(g => g.startsWith(mozGroupPrefix))
        .map(g => g.slice(mozGroupPrefix.length))
        .map(g => `mozillians-group:${g}`)
    );
  }
}

module.exports = Handler;
<commit_msg>(hotfix) include more debugging output<commit_after>const User = require('./../user');
const {encode, decode, CLIENT_ID_PATTERN} = require('../utils');
const assert = require('assert');
const _ = require('lodash');
const jwt = require('jsonwebtoken');
const expressJwt = require('express-jwt');
const jwks = require('jwks-rsa');
const Debug = require('debug');
const auth0js = require('auth0-js');
const request = require('superagent');

const debug = Debug('handlers.mozilla-auth0');

class Handler {
  constructor({name, cfg}) {
    let handlerCfg = cfg.handlers[name];
    assert(handlerCfg.domain, `${name}.domain is required`);
    assert(handlerCfg.apiAudience, `${name}.apiAudience is required`);
    assert(handlerCfg.clientId, `${name}.clientId is required`);
    assert(handlerCfg.clientSecret, `${name}.clientSecret is required`);
    _.assign(this, handlerCfg);

    // use express-jwt to validate JWTs against auth0
    this.jwtCheck = expressJwt({
      secret: jwks.expressJwtSecret({
        cache: true,
        rateLimit: true,
        jwksRequestsPerMinute: 5,
        jwksUri: `https://${this.domain}/.well-known/jwks.json`,
      }),
      // expect to see our audience in the JWT
      audience: this.apiAudience,
      // and expect a token issued by auth0
      issuer: `https://${this.domain}/`,
      algorithms: ['RS256'],
      credentialsRequired: true,
    });

    this._managementApiExp = null;
    this._managementApi = null;
    this._identityProviderId = 'mozilla-auth0';
  }

  get identityProviderId() {
    return this._identityProviderId;
  }

  // Get a management API instance, by requesting an API token as needed
  // see https://auth0.com/docs/api/management/v2/tokens
  async getManagementApi() {
    if (this._managementApi && new Date().getTime() / 1000 < this._managementApiExp - 10) {
      return this._managementApi;
    }

    let res = await request.post(`https://${this.domain}/oauth/token`)
      .set('content-type', 'application/json')
      .send({
        grant_type: 'client_credentials',
        client_id: this.clientId,
        client_secret: this.clientSecret,
        audience: `https://${this.domain}/api/v2/`,
      });

    let token = JSON.parse(res.text).access_token;
    if (!token) {
      throw new Error('did not receive a token from Auth0 /oauth/token endpoint');
    }

    // parse the token just enough to figure out when it expires
    let decoded = jwt.decode(token);
    let expires = decoded.exp;

    // create a new
    this._managementApi = new auth0js.Management({
      domain: this.domain,
      token: token,
    });
    this._managementApiExp = expires;

    return this._managementApi;
  }

  async profileFromUserId(userId) {
    const a0 = await this.getManagementApi();

    const profile = new Promise((resolve, reject) =>
      a0.getUser(userId, (err, prof) => err ? reject(err) : resolve(prof)));

    return profile;
  }

  async userFromRequest(req, res) {
    // check the JWT's validity, setting req.user if sucessful
    try {
      await new Promise((resolve, reject) =>
        this.jwtCheck(req, res, (err) => err ? reject(err) : resolve()));
    } catch (err) {
      debug(`error validating jwt: ${err}`);
      return;
    }

    debug(`received valid access_token for subject ${req.user.sub}`);

    let scopes = req.user.scope ? req.user.scope.split(' ') : [];
    if (!scopes.includes('taskcluster-credentials')) {
      debug(`request did not have the 'taskcluster-credentials' scope; had ${req.user.scope}`);
      return;
    }

    try {
      const profile = await this.profileFromUserId(req.user.sub);

      if ('active' in profile && !profile.active) {
        debug('user is not active; rejecting');
        return;
      }

      const user = this.userFromProfile(profile);
      user.expires = new Date(req.user.exp * 1000);

      return user;
    } catch (err) {
      debug(`error retrieving profile from request: ${err}\n${err.stack}`);
      return;
    }
  }

  async userFromUserId(userId) {
    try {
      const profile = await this.profileFromUserId(userId);
      const user = this.userFromProfile(profile);

      return user;
    } catch (err) {
      debug(`error retrieving profile from userId: ${err}\n${err.stack}`);
      return;
    }
  }

  userFromClientId(clientId) {
    const userId = this.userIdFromClientId(clientId);
    if (!userId) {
      return;
    }

    return this.userFromUserId(userId);
  }

  identityFromClientId(clientId) {
    const patternMatch = CLIENT_ID_PATTERN.exec(clientId);
    return patternMatch && patternMatch[1];
  }

  userIdFromClientId(clientId) {
    const identity = this.identityFromClientId(clientId);

    if (!identity) {
      return;
    }

    let encodedUserId = identity.split('/')[1];

    // Reverse the username appending, stripping the username.
    if (encodedUserId.startsWith('github|') || encodedUserId.startsWith('oauth2|firefoxaccounts|')) {
      encodedUserId = encodedUserId.replace(/\|[^|]*$/, '');
    }

    return decode(encodedUserId);
  }

  identityFromProfile(profile) {
    let identity;

    // Look for a profile.identities element we recognize.  In practice, this is a one-element
    // array as we do not use Auth0 user linking.
    profile.identities.forEach(({provider, connection}) => {
      if (
        provider === 'ad' && connection === 'Mozilla-LDAP' ||
        // The 'email' connection corresponds to a passwordless login.
        provider === 'email' && connection === 'email' ||
        provider === 'google-oauth2' && connection === 'google-oauth2'
      ) {
        assert(!profile.user_id.startsWith('github|'));
        identity = `${this.identityProviderId}/${encode(profile.user_id)}`;
      // we annotate some userids with `|nickname` since otherwise the userid
      // is just numeric and difficult for humans to interpret
      } else if (provider === 'github' && connection === 'github') {
        assert(profile.user_id.startsWith('github|'));
        identity = `${this.identityProviderId}/${encode(profile.user_id)}|${profile.nickname}`;
      } else if (provider === 'oauth2' && connection === 'firefoxaccounts') {
        assert(profile.user_id.startsWith('oauth2|firefoxaccounts|'));
        identity = `${this.identityProviderId}/${encode(profile.user_id)}|${profile.nickname}`;
      }
    });

    return identity;
  }

  userFromProfile(profile) {
    const user = new User();

    user.identity = this.identityFromProfile(profile);
    if (!user.identity) {
      debug('No recognized identity providers');
      return;
    }

    // take a user and attach roles to it
    this.addRoles(profile, user);

    return user;
  }

  addRoles(profile, user) {
    const mozGroupPrefix = 'mozilliansorg_';
    const hrisGroupPrefix = 'hris_';
    const groups = Array.from(new Set([
      ...profile.groups || [],
      ...(profile.app_metadata || {}).groups || [],
    ]));

    // Non-prefixed groups are what is known as Mozilla LDAP groups. Groups prefixed by a provider
    // name and underscore are provided by a specific group engine. For example,
    // `providername_groupone` is provided by `providername`. Per https://goo.gl/bwWjvE.
    // For our own purposes, if the prefix is not mozilliansorg. then we treat it as an ldap group
    user.addRole(
      ...groups
        .filter(g => !g.startsWith(hrisGroupPrefix))
        .filter(g => !g.startsWith(mozGroupPrefix))
        .map(g => `mozilla-group:${g}`)
    );
    user.addRole(
      ...groups
        .filter(g => !g.startsWith(hrisGroupPrefix))
        .filter(g => g.startsWith(mozGroupPrefix))
        .map(g => g.slice(mozGroupPrefix.length))
        .map(g => `mozillians-group:${g}`)
    );
  }
}

module.exports = Handler;
<|endoftext|>


<commit_before>/**
 * Number-Field
 */
function initNumberField(){
	var targets = $('.number-field input');
	jQuery.each(targets, function(i, target) {
		if(target !== undefined) {
			var jQueryTarget = $(target);
			$(jQueryTarget).on('change', function() {
				var jQuerySelf = $(this);
				var functionName = jQuerySelf.attr('data-onchange');

		  	    if(jQuerySelf.val() !==  jQuerySelf.attr('data-previousValue')) {
		  	    	var f = new Function(functionName);
					f.call();
					jQuerySelf.attr('data-previousValue', jQuerySelf.val());
		  	    }
			});

		}
	});
}

function fncUppercase() {
	$("input").keyup(function() {
		var textUpperCase = $(this).val().toUpperCase();
		if(window.getSelection().toString() === $(this).val()) {
			$(this).val(textUpperCase);
			$(this).select();
		} else {
			$(this).val(textUpperCase);
		}
	});
	$("textarea").keyup(function() {
		var textUpperCase = $(this).val().toUpperCase();
		if(window.getSelection().toString() === $(this).val()) {
			$(this).val(textUpperCase);
			$(this).select();
		} else {
			$(this).val(textUpperCase);
		}
	});
}

function numbersOnly() {
	jQuery('.numbersOnly').keyup(function () {
	    this.value = this.value.replace(/[^0-9\.]/g,'');
	});
}

function formatMask() {
	$('.cns').mask('999.9999.9999.9999');
	$(".cpf").mask("999.999.999-99");
	$(".cep").mask("99999-999");
	$(".rg").mask("99.999.999-9");
}<commit_msg>Teste de build com js<commit_after>/**
 * Number-Field
 */
function initNumberField(){
	var targets = $('.number-field input');
	jQuery.each(targets, function(i, target) {
		if(target !== undefined) {
			var jQueryTarget = $(target);
			$(jQueryTarget).on('change', function() {
				var jQuerySelf = $(this);
				var functionName = jQuerySelf.attr('data-onchange');

		  	    if(jQuerySelf.val() !==  jQuerySelf.attr('data-previousValue')) {
		  	    	var f = new Function(functionName);
					f.call();
					jQuerySelf.attr('data-previousValue', jQuerySelf.val());
		  	    }
			});

		}
	});
}

function fncUppercase() {
	$("input").keyup(function() {
		var textUpperCase = $(this).val().toUpperCase();
		if(window.getSelection().toString() === $(this).val()) {
			$(this).val(textUpperCase);
			$(this).select();
		} else {
			$(this).val(textUpperCase);
		}
	});
	$("textarea").keyup(function() {
		var textUpperCase = $(this).val().toUpperCase();
		if(window.getSelection().toString() === $(this).val()) {
			$(this).val(textUpperCase);
			$(this).select();
		} else {
			$(this).val(textUpperCase);
		}
	});
}

function numbersOnly() {
	jQuery('.numbersOnly').keyup(function () {
	    this.value = this.value.replace(/[^0-9\.]/g,'');
	});
}

function formatMask() {
	$('.cns').mask('999.9999.9999.9999');
	$(".cpf").mask("999.999.999-99");
	$(".cnpj").mask("99.999.999/9999-99");
	$(".cep").mask("99999-999");
	$(".rg").mask("99.999.999-9");
}<|endoftext|>


<commit_before>/*
 * @flow
 * @format
 */

import type Suite from 'flow-dev-tools/src/test/Suite.js';
import {suite, test} from 'flow-dev-tools/src/test/Tester';

/**
 * This test suite takes each query tested by lsp/queries and runs it once with
 * wait_for_recheck=true and once with wait_for_recheck=false. In each case,
 * we've triggered a 20s recheck and have a 2s timeout. Queries that run in
 * parallel with a recheck will return a response. Those that don't will
 * timeout
 */
export default (suite(
  ({
    lspStartAndConnect,
    lspNotification,
    lspRequestAndWaitUntilResponse,
    addFile,
    addFiles,
    lspIgnoreStatusAndCancellation,
  }) => [
    test('invalid_method handled immediately when wait_for_recheck=true', [
      lspStartAndConnect(),
      addFile('sleep.js.ignored', 'sleep.js').verifyAllLSPMessagesInStep(
        [''],
        [...lspIgnoreStatusAndCancellation],
      ),
      lspRequestAndWaitUntilResponse('foobar', {}).verifyAllLSPMessagesInStep(
        [['foobar', '{unexpected error}']],
        [...lspIgnoreStatusAndCancellation],
      ),
      lspNotification('barfoo', {})
        .waitUntilLSPMessage(2000, 'barfoo')
        .verifyAllLSPMessagesInStep(
          [['telemetry/event', '{not implemented}']],
          [...lspIgnoreStatusAndCancellation],
        ),
    ]).waitForRecheck(true),

    test('invalid_method handled immediately when wait_for_recheck=false', [
      lspStartAndConnect(),
      addFile('sleep.js.ignored', 'sleep.js').verifyAllLSPMessagesInStep(
        [''],
        [...lspIgnoreStatusAndCancellation],
      ),
      lspRequestAndWaitUntilResponse('foobar', {}).verifyAllLSPMessagesInStep(
        [['foobar', '{unexpected error}']],
        [...lspIgnoreStatusAndCancellation],
      ),
      lspNotification('barfoo', {})
        .waitUntilLSPMessage(2000, 'barfoo')
        .verifyAllLSPMessagesInStep(
          [['telemetry/event', '{not implemented}']],
          [...lspIgnoreStatusAndCancellation],
        ),
    ]).waitForRecheck(false),

    test('textDocument/definition will time out with wait_for_recheck=true', [
      addFile('definition.js'),
      lspStartAndConnect(),
      addFile('sleep.js.ignored', 'sleep.js').verifyAllLSPMessagesInStep(
        [''],
        [...lspIgnoreStatusAndCancellation],
      ),
      lspRequestAndWaitUntilResponse('textDocument/definition', {
        textDocument: {uri: '<PLACEHOLDER_PROJECT_URL>/definition.js'},
        position: {line: 6, character: 1},
      })
        .verifyAllLSPMessagesInStep([], [...lspIgnoreStatusAndCancellation])
        .timeout(2000),
    ]).waitForRecheck(true),

    test('textDocument/definition will return with wait_for_recheck=false', [
      addFile('definition.js'),
      lspStartAndConnect(),
      addFile('sleep.js.ignored', 'sleep.js').verifyAllLSPMessagesInStep(
        [''],
        [...lspIgnoreStatusAndCancellation],
      ),
      lspRequestAndWaitUntilResponse('textDocument/definition', {
        textDocument: {uri: '<PLACEHOLDER_PROJECT_URL>/definition.js'},
        position: {line: 6, character: 1},
      })
        .verifyAllLSPMessagesInStep(
          [
            [
              'textDocument/definition',
              '{definition.js,"start":{"line":2,"character":9}}',
            ],
          ],
          [...lspIgnoreStatusAndCancellation],
        )
        .timeout(2000),
    ]).waitForRecheck(false),

    test('textDocument/hover will time out with wait_for_recheck=true', [
      addFile('hover.js'),
      lspStartAndConnect(),
      addFile('sleep.js.ignored', 'sleep.js').verifyAllLSPMessagesInStep(
        [''],
        [...lspIgnoreStatusAndCancellation],
      ),
      lspRequestAndWaitUntilResponse('textDocument/hover', {
        textDocument: {uri: '<PLACEHOLDER_PROJECT_URL>/hover.js'},
        position: {line: 6, character: 1}, // over a function use
      })
        .verifyAllLSPMessagesInStep([], [...lspIgnoreStatusAndCancellation])
        .timeout(2000),
    ]).waitForRecheck(true),

    test('textDocument/hover will return with wait_for_recheck=false', [
      addFile('hover.js'),
      lspStartAndConnect(),
      addFile('sleep.js.ignored', 'sleep.js').verifyAllLSPMessagesInStep(
        [''],
        [...lspIgnoreStatusAndCancellation],
      ),
      lspRequestAndWaitUntilResponse('textDocument/hover', {
        textDocument: {uri: '<PLACEHOLDER_PROJECT_URL>/hover.js'},
        position: {line: 6, character: 1}, // over a function use
      })
        .verifyAllLSPMessagesInStep(
          [['textDocument/hover', '{() => number}']],
          [...lspIgnoreStatusAndCancellation],
        )
        .timeout(2000),
    ]).waitForRecheck(false),

    test('textDocument/completion will time out with wait_for_recheck=true', [
      addFile('completion.js'),
      lspStartAndConnect(),
      addFile('sleep.js.ignored', 'sleep.js').verifyAllLSPMessagesInStep(
        [''],
        [...lspIgnoreStatusAndCancellation],
      ),
      lspRequestAndWaitUntilResponse('textDocument/completion', {
        textDocument: {uri: '<PLACEHOLDER_PROJECT_URL>/completion.js'},
        position: {line: 10, character: 15}, // statement position
      })
        .verifyAllLSPMessagesInStep([], [...lspIgnoreStatusAndCancellation])
        .timeout(2000),
    ]).waitForRecheck(true),

    test('textDocument/completion will return with wait_for_recheck=false', [
      addFile('completion.js'),
      lspStartAndConnect(),
      addFile('sleep.js.ignored', 'sleep.js').verifyAllLSPMessagesInStep(
        [''],
        [...lspIgnoreStatusAndCancellation],
      ),
      lspRequestAndWaitUntilResponse('textDocument/completion', {
        textDocument: {uri: '<PLACEHOLDER_PROJECT_URL>/completion.js'},
        position: {line: 10, character: 15}, // statement position
      })
        .verifyAllLSPMessagesInStep(
          [
            [
              'textDocument/completion',
              '{"label":"x","label":"fred","detail":"(a: number, b: string) => number"}',
            ],
          ],
          [...lspIgnoreStatusAndCancellation],
        )
        .timeout(2000),
    ]).waitForRecheck(false),

    test(
      'textDocument/documentHighlight will return with wait_for_recheck=false',
      [
        addFiles('references.js', 'references2.js'),
        lspStartAndConnect(),
        addFile('sleep.js.ignored', 'sleep.js').verifyAllLSPMessagesInStep(
          [''],
          [...lspIgnoreStatusAndCancellation],
        ),
        lspRequestAndWaitUntilResponse('textDocument/documentHighlight', {
          textDocument: {uri: '<PLACEHOLDER_PROJECT_URL>/references.js'},
          position: {line: 9, character: 17}, // on an identifier
        })
          .verifyAllLSPMessagesInStep(
            ['textDocument/documentHighlight'],
            [...lspIgnoreStatusAndCancellation],
          )
          .timeout(2000),
      ],
    ).waitForRecheck(false),

    test(
      'textDocument/documentHighlight will time out with wait_for_recheck=true',
      [
        addFiles('references.js', 'references2.js'),
        lspStartAndConnect(),
        addFile('sleep.js.ignored', 'sleep.js').verifyAllLSPMessagesInStep(
          [''],
          [...lspIgnoreStatusAndCancellation],
        ),
        lspRequestAndWaitUntilResponse('textDocument/documentHighlight', {
          textDocument: {uri: '<PLACEHOLDER_PROJECT_URL>/references.js'},
          position: {line: 9, character: 17}, // on an identifier
        })
          .verifyAllLSPMessagesInStep([], [...lspIgnoreStatusAndCancellation])
          .timeout(2000),
      ],
    ).waitForRecheck(true),

    test('textDocument/references will time out with wait_for_recheck=true', [
      addFiles('references.js', 'references2.js'),
      lspStartAndConnect(),
      addFile('sleep.js.ignored', 'sleep.js').verifyAllLSPMessagesInStep(
        [''],
        [...lspIgnoreStatusAndCancellation],
      ),
      lspRequestAndWaitUntilResponse('textDocument/references', {
        textDocument: {uri: '<PLACEHOLDER_PROJECT_URL>/references.js'},
        position: {line: 9, character: 17}, // on an identifier
      })
        .verifyAllLSPMessagesInStep([], [...lspIgnoreStatusAndCancellation])
        .timeout(2000),
    ]).waitForRecheck(true),

    test('textDocument/references will time out with wait_for_recheck=false', [
      addFiles('references.js', 'references2.js'),
      lspStartAndConnect(),
      addFile('sleep.js.ignored', 'sleep.js').verifyAllLSPMessagesInStep(
        [''],
        [...lspIgnoreStatusAndCancellation],
      ),
      lspRequestAndWaitUntilResponse('textDocument/references', {
        textDocument: {uri: '<PLACEHOLDER_PROJECT_URL>/references.js'},
        position: {line: 9, character: 17}, // on an identifier
      })
        .verifyAllLSPMessagesInStep([], [...lspIgnoreStatusAndCancellation])
        .timeout(2000),
    ]).waitForRecheck(false),

    test('textDocument/rename will time out with wait_for_recheck=true', [
      addFiles('references.js', 'references2.js'),
      lspStartAndConnect(),
      addFile('sleep.js.ignored', 'sleep.js').verifyAllLSPMessagesInStep(
        [''],
        [...lspIgnoreStatusAndCancellation],
      ),
      lspRequestAndWaitUntilResponse('textDocument/rename', {
        textDocument: {uri: '<PLACEHOLDER_PROJECT_URL>/references.js'},
        position: {line: 9, character: 17}, // on an identifier
        newName: 'foobar',
      })
        .verifyAllLSPMessagesInStep([], [...lspIgnoreStatusAndCancellation])
        .timeout(2000),
    ]).waitForRecheck(true),

    test('textDocument/rename will time out with wait_for_recheck=false', [
      addFiles('references.js', 'references2.js'),
      lspStartAndConnect(),
      addFile('sleep.js.ignored', 'sleep.js').verifyAllLSPMessagesInStep(
        [''],
        [...lspIgnoreStatusAndCancellation],
      ),
      lspRequestAndWaitUntilResponse('textDocument/rename', {
        textDocument: {uri: '<PLACEHOLDER_PROJECT_URL>/references.js'},
        position: {line: 9, character: 17}, // on an identifier
        newName: 'foobar',
      })
        .verifyAllLSPMessagesInStep([], [...lspIgnoreStatusAndCancellation])
        .timeout(2000),
    ]).waitForRecheck(false),

    test('textDocument/documentSymbol will return with wait_for_recheck=true', [
      addFiles('outline.js', 'references.js'),
      lspStartAndConnect(),
      addFile('sleep.js.ignored', 'sleep.js').verifyAllLSPMessagesInStep(
        [''],
        [...lspIgnoreStatusAndCancellation],
      ),
      lspRequestAndWaitUntilResponse('textDocument/documentSymbol', {
        textDocument: {uri: '<PLACEHOLDER_PROJECT_URL>/outline.js'},
      })
        .verifyAllLSPMessagesInStep(
          [
            [
              'textDocument/documentSymbol',
              '{WORD_REGEX,State,Preferences,pref1,EPrefs,pref2,MyClass1,_projectRoot,command,constructor,dispose,MyInterface2,getFoo,myFunction3}',
            ],
          ],
          [...lspIgnoreStatusAndCancellation],
        )
        .timeout(2000),
    ]).waitForRecheck(true),

    test(
      'textDocument/documentSymbol will return with wait_for_recheck=false',
      [
        addFiles('outline.js', 'references.js'),
        lspStartAndConnect(),
        addFile('sleep.js.ignored', 'sleep.js').verifyAllLSPMessagesInStep(
          [''],
          [...lspIgnoreStatusAndCancellation],
        ),
        lspRequestAndWaitUntilResponse('textDocument/documentSymbol', {
          textDocument: {uri: '<PLACEHOLDER_PROJECT_URL>/outline.js'},
        })
          .verifyAllLSPMessagesInStep(
            [
              [
                'textDocument/documentSymbol',
                '{WORD_REGEX,State,Preferences,pref1,EPrefs,pref2,MyClass1,_projectRoot,command,constructor,dispose,MyInterface2,getFoo,myFunction3}',
              ],
            ],
            [...lspIgnoreStatusAndCancellation],
          )
          .timeout(2000),
      ],
    ).waitForRecheck(false),

    test('textDocument/typeCoverage will time out with wait_for_recheck=true', [
      addFiles('coverage.js'),
      lspStartAndConnect(),
      addFile('sleep.js.ignored', 'sleep.js').verifyAllLSPMessagesInStep(
        [''],
        [...lspIgnoreStatusAndCancellation],
      ),
      lspRequestAndWaitUntilResponse('textDocument/typeCoverage', {
        textDocument: {uri: '<PLACEHOLDER_PROJECT_URL>/coverage.js'},
      })
        .verifyAllLSPMessagesInStep([], [...lspIgnoreStatusAndCancellation])
        .timeout(2000),
    ]).waitForRecheck(true),

    test('textDocument/typeCoverage will return with wait_for_recheck=false', [
      addFiles('coverage.js'),
      lspStartAndConnect(),
      addFile('sleep.js.ignored', 'sleep.js').verifyAllLSPMessagesInStep(
        [''],
        [...lspIgnoreStatusAndCancellation],
      ),
      lspRequestAndWaitUntilResponse('textDocument/typeCoverage', {
        textDocument: {uri: '<PLACEHOLDER_PROJECT_URL>/coverage.js'},
      })
        .verifyAllLSPMessagesInStep(
          [['textDocument/typeCoverage', '{"line":12,"line":8,"line":6}']],
          [...lspIgnoreStatusAndCancellation],
        )
        .timeout(2000),
    ]).waitForRecheck(false),

    test('telemetry/rage will time out with wait_for_recheck=true', [
      lspStartAndConnect(),
      addFile('sleep.js.ignored', 'sleep.js').verifyAllLSPMessagesInStep(
        [''],
        [...lspIgnoreStatusAndCancellation],
      ),
      lspRequestAndWaitUntilResponse('textDocument/typeCoverage', {
        textDocument: {uri: '<PLACEHOLDER_PROJECT_DIR>/coverage2.js'},
      })
        .verifyAllLSPMessagesInStep([], [...lspIgnoreStatusAndCancellation])
        .timeout(2000),
    ]).waitForRecheck(true),

    test('telemetry/rage will return with wait_for_recheck=false', [
      lspStartAndConnect(),
      addFile('sleep.js.ignored', 'sleep.js').verifyAllLSPMessagesInStep(
        [''],
        [...lspIgnoreStatusAndCancellation],
      ),
      lspRequestAndWaitUntilResponse('textDocument/typeCoverage', {
        textDocument: {uri: '<PLACEHOLDER_PROJECT_DIR>/coverage2.js'},
      })
        .verifyAllLSPMessagesInStep(
          [['textDocument/typeCoverage', '{Use @flow}']],
          [...lspIgnoreStatusAndCancellation],
        )
        .timeout(2000),
    ]).waitForRecheck(false),
  ],
): Suite);
<commit_msg>fix wait_for_recheck telemetry/rage test<commit_after>/*
 * @flow
 * @format
 */

import type Suite from 'flow-dev-tools/src/test/Suite.js';
import {suite, test} from 'flow-dev-tools/src/test/Tester';

/**
 * This test suite takes each query tested by lsp/queries and runs it once with
 * wait_for_recheck=true and once with wait_for_recheck=false. In each case,
 * we've triggered a 20s recheck and have a 2s timeout. Queries that run in
 * parallel with a recheck will return a response. Those that don't will
 * timeout
 */
export default (suite(
  ({
    lspStartAndConnect,
    lspNotification,
    lspRequestAndWaitUntilResponse,
    addFile,
    addFiles,
    lspIgnoreStatusAndCancellation,
  }) => [
    test('invalid_method handled immediately when wait_for_recheck=true', [
      lspStartAndConnect(),
      addFile('sleep.js.ignored', 'sleep.js').verifyAllLSPMessagesInStep(
        [''],
        [...lspIgnoreStatusAndCancellation],
      ),
      lspRequestAndWaitUntilResponse('foobar', {}).verifyAllLSPMessagesInStep(
        [['foobar', '{unexpected error}']],
        [...lspIgnoreStatusAndCancellation],
      ),
      lspNotification('barfoo', {})
        .waitUntilLSPMessage(2000, 'barfoo')
        .verifyAllLSPMessagesInStep(
          [['telemetry/event', '{not implemented}']],
          [...lspIgnoreStatusAndCancellation],
        ),
    ]).waitForRecheck(true),

    test('invalid_method handled immediately when wait_for_recheck=false', [
      lspStartAndConnect(),
      addFile('sleep.js.ignored', 'sleep.js').verifyAllLSPMessagesInStep(
        [''],
        [...lspIgnoreStatusAndCancellation],
      ),
      lspRequestAndWaitUntilResponse('foobar', {}).verifyAllLSPMessagesInStep(
        [['foobar', '{unexpected error}']],
        [...lspIgnoreStatusAndCancellation],
      ),
      lspNotification('barfoo', {})
        .waitUntilLSPMessage(2000, 'barfoo')
        .verifyAllLSPMessagesInStep(
          [['telemetry/event', '{not implemented}']],
          [...lspIgnoreStatusAndCancellation],
        ),
    ]).waitForRecheck(false),

    test('textDocument/definition will time out with wait_for_recheck=true', [
      addFile('definition.js'),
      lspStartAndConnect(),
      addFile('sleep.js.ignored', 'sleep.js').verifyAllLSPMessagesInStep(
        [''],
        [...lspIgnoreStatusAndCancellation],
      ),
      lspRequestAndWaitUntilResponse('textDocument/definition', {
        textDocument: {uri: '<PLACEHOLDER_PROJECT_URL>/definition.js'},
        position: {line: 6, character: 1},
      })
        .verifyAllLSPMessagesInStep([], [...lspIgnoreStatusAndCancellation])
        .timeout(2000),
    ]).waitForRecheck(true),

    test('textDocument/definition will return with wait_for_recheck=false', [
      addFile('definition.js'),
      lspStartAndConnect(),
      addFile('sleep.js.ignored', 'sleep.js').verifyAllLSPMessagesInStep(
        [''],
        [...lspIgnoreStatusAndCancellation],
      ),
      lspRequestAndWaitUntilResponse('textDocument/definition', {
        textDocument: {uri: '<PLACEHOLDER_PROJECT_URL>/definition.js'},
        position: {line: 6, character: 1},
      })
        .verifyAllLSPMessagesInStep(
          [
            [
              'textDocument/definition',
              '{definition.js,"start":{"line":2,"character":9}}',
            ],
          ],
          [...lspIgnoreStatusAndCancellation],
        )
        .timeout(2000),
    ]).waitForRecheck(false),

    test('textDocument/hover will time out with wait_for_recheck=true', [
      addFile('hover.js'),
      lspStartAndConnect(),
      addFile('sleep.js.ignored', 'sleep.js').verifyAllLSPMessagesInStep(
        [''],
        [...lspIgnoreStatusAndCancellation],
      ),
      lspRequestAndWaitUntilResponse('textDocument/hover', {
        textDocument: {uri: '<PLACEHOLDER_PROJECT_URL>/hover.js'},
        position: {line: 6, character: 1}, // over a function use
      })
        .verifyAllLSPMessagesInStep([], [...lspIgnoreStatusAndCancellation])
        .timeout(2000),
    ]).waitForRecheck(true),

    test('textDocument/hover will return with wait_for_recheck=false', [
      addFile('hover.js'),
      lspStartAndConnect(),
      addFile('sleep.js.ignored', 'sleep.js').verifyAllLSPMessagesInStep(
        [''],
        [...lspIgnoreStatusAndCancellation],
      ),
      lspRequestAndWaitUntilResponse('textDocument/hover', {
        textDocument: {uri: '<PLACEHOLDER_PROJECT_URL>/hover.js'},
        position: {line: 6, character: 1}, // over a function use
      })
        .verifyAllLSPMessagesInStep(
          [['textDocument/hover', '{() => number}']],
          [...lspIgnoreStatusAndCancellation],
        )
        .timeout(2000),
    ]).waitForRecheck(false),

    test('textDocument/completion will time out with wait_for_recheck=true', [
      addFile('completion.js'),
      lspStartAndConnect(),
      addFile('sleep.js.ignored', 'sleep.js').verifyAllLSPMessagesInStep(
        [''],
        [...lspIgnoreStatusAndCancellation],
      ),
      lspRequestAndWaitUntilResponse('textDocument/completion', {
        textDocument: {uri: '<PLACEHOLDER_PROJECT_URL>/completion.js'},
        position: {line: 10, character: 15}, // statement position
      })
        .verifyAllLSPMessagesInStep([], [...lspIgnoreStatusAndCancellation])
        .timeout(2000),
    ]).waitForRecheck(true),

    test('textDocument/completion will return with wait_for_recheck=false', [
      addFile('completion.js'),
      lspStartAndConnect(),
      addFile('sleep.js.ignored', 'sleep.js').verifyAllLSPMessagesInStep(
        [''],
        [...lspIgnoreStatusAndCancellation],
      ),
      lspRequestAndWaitUntilResponse('textDocument/completion', {
        textDocument: {uri: '<PLACEHOLDER_PROJECT_URL>/completion.js'},
        position: {line: 10, character: 15}, // statement position
      })
        .verifyAllLSPMessagesInStep(
          [
            [
              'textDocument/completion',
              '{"label":"x","label":"fred","detail":"(a: number, b: string) => number"}',
            ],
          ],
          [...lspIgnoreStatusAndCancellation],
        )
        .timeout(2000),
    ]).waitForRecheck(false),

    test(
      'textDocument/documentHighlight will return with wait_for_recheck=false',
      [
        addFiles('references.js', 'references2.js'),
        lspStartAndConnect(),
        addFile('sleep.js.ignored', 'sleep.js').verifyAllLSPMessagesInStep(
          [''],
          [...lspIgnoreStatusAndCancellation],
        ),
        lspRequestAndWaitUntilResponse('textDocument/documentHighlight', {
          textDocument: {uri: '<PLACEHOLDER_PROJECT_URL>/references.js'},
          position: {line: 9, character: 17}, // on an identifier
        })
          .verifyAllLSPMessagesInStep(
            ['textDocument/documentHighlight'],
            [...lspIgnoreStatusAndCancellation],
          )
          .timeout(2000),
      ],
    ).waitForRecheck(false),

    test(
      'textDocument/documentHighlight will time out with wait_for_recheck=true',
      [
        addFiles('references.js', 'references2.js'),
        lspStartAndConnect(),
        addFile('sleep.js.ignored', 'sleep.js').verifyAllLSPMessagesInStep(
          [''],
          [...lspIgnoreStatusAndCancellation],
        ),
        lspRequestAndWaitUntilResponse('textDocument/documentHighlight', {
          textDocument: {uri: '<PLACEHOLDER_PROJECT_URL>/references.js'},
          position: {line: 9, character: 17}, // on an identifier
        })
          .verifyAllLSPMessagesInStep([], [...lspIgnoreStatusAndCancellation])
          .timeout(2000),
      ],
    ).waitForRecheck(true),

    test('textDocument/references will time out with wait_for_recheck=true', [
      addFiles('references.js', 'references2.js'),
      lspStartAndConnect(),
      addFile('sleep.js.ignored', 'sleep.js').verifyAllLSPMessagesInStep(
        [''],
        [...lspIgnoreStatusAndCancellation],
      ),
      lspRequestAndWaitUntilResponse('textDocument/references', {
        textDocument: {uri: '<PLACEHOLDER_PROJECT_URL>/references.js'},
        position: {line: 9, character: 17}, // on an identifier
      })
        .verifyAllLSPMessagesInStep([], [...lspIgnoreStatusAndCancellation])
        .timeout(2000),
    ]).waitForRecheck(true),

    test('textDocument/references will time out with wait_for_recheck=false', [
      addFiles('references.js', 'references2.js'),
      lspStartAndConnect(),
      addFile('sleep.js.ignored', 'sleep.js').verifyAllLSPMessagesInStep(
        [''],
        [...lspIgnoreStatusAndCancellation],
      ),
      lspRequestAndWaitUntilResponse('textDocument/references', {
        textDocument: {uri: '<PLACEHOLDER_PROJECT_URL>/references.js'},
        position: {line: 9, character: 17}, // on an identifier
      })
        .verifyAllLSPMessagesInStep([], [...lspIgnoreStatusAndCancellation])
        .timeout(2000),
    ]).waitForRecheck(false),

    test('textDocument/rename will time out with wait_for_recheck=true', [
      addFiles('references.js', 'references2.js'),
      lspStartAndConnect(),
      addFile('sleep.js.ignored', 'sleep.js').verifyAllLSPMessagesInStep(
        [''],
        [...lspIgnoreStatusAndCancellation],
      ),
      lspRequestAndWaitUntilResponse('textDocument/rename', {
        textDocument: {uri: '<PLACEHOLDER_PROJECT_URL>/references.js'},
        position: {line: 9, character: 17}, // on an identifier
        newName: 'foobar',
      })
        .verifyAllLSPMessagesInStep([], [...lspIgnoreStatusAndCancellation])
        .timeout(2000),
    ]).waitForRecheck(true),

    test('textDocument/rename will time out with wait_for_recheck=false', [
      addFiles('references.js', 'references2.js'),
      lspStartAndConnect(),
      addFile('sleep.js.ignored', 'sleep.js').verifyAllLSPMessagesInStep(
        [''],
        [...lspIgnoreStatusAndCancellation],
      ),
      lspRequestAndWaitUntilResponse('textDocument/rename', {
        textDocument: {uri: '<PLACEHOLDER_PROJECT_URL>/references.js'},
        position: {line: 9, character: 17}, // on an identifier
        newName: 'foobar',
      })
        .verifyAllLSPMessagesInStep([], [...lspIgnoreStatusAndCancellation])
        .timeout(2000),
    ]).waitForRecheck(false),

    test('textDocument/documentSymbol will return with wait_for_recheck=true', [
      addFiles('outline.js', 'references.js'),
      lspStartAndConnect(),
      addFile('sleep.js.ignored', 'sleep.js').verifyAllLSPMessagesInStep(
        [''],
        [...lspIgnoreStatusAndCancellation],
      ),
      lspRequestAndWaitUntilResponse('textDocument/documentSymbol', {
        textDocument: {uri: '<PLACEHOLDER_PROJECT_URL>/outline.js'},
      })
        .verifyAllLSPMessagesInStep(
          [
            [
              'textDocument/documentSymbol',
              '{WORD_REGEX,State,Preferences,pref1,EPrefs,pref2,MyClass1,_projectRoot,command,constructor,dispose,MyInterface2,getFoo,myFunction3}',
            ],
          ],
          [...lspIgnoreStatusAndCancellation],
        )
        .timeout(2000),
    ]).waitForRecheck(true),

    test(
      'textDocument/documentSymbol will return with wait_for_recheck=false',
      [
        addFiles('outline.js', 'references.js'),
        lspStartAndConnect(),
        addFile('sleep.js.ignored', 'sleep.js').verifyAllLSPMessagesInStep(
          [''],
          [...lspIgnoreStatusAndCancellation],
        ),
        lspRequestAndWaitUntilResponse('textDocument/documentSymbol', {
          textDocument: {uri: '<PLACEHOLDER_PROJECT_URL>/outline.js'},
        })
          .verifyAllLSPMessagesInStep(
            [
              [
                'textDocument/documentSymbol',
                '{WORD_REGEX,State,Preferences,pref1,EPrefs,pref2,MyClass1,_projectRoot,command,constructor,dispose,MyInterface2,getFoo,myFunction3}',
              ],
            ],
            [...lspIgnoreStatusAndCancellation],
          )
          .timeout(2000),
      ],
    ).waitForRecheck(false),

    test('textDocument/typeCoverage will time out with wait_for_recheck=true', [
      addFiles('coverage.js'),
      lspStartAndConnect(),
      addFile('sleep.js.ignored', 'sleep.js').verifyAllLSPMessagesInStep(
        [''],
        [...lspIgnoreStatusAndCancellation],
      ),
      lspRequestAndWaitUntilResponse('textDocument/typeCoverage', {
        textDocument: {uri: '<PLACEHOLDER_PROJECT_URL>/coverage.js'},
      })
        .verifyAllLSPMessagesInStep([], [...lspIgnoreStatusAndCancellation])
        .timeout(2000),
    ]).waitForRecheck(true),

    test('textDocument/typeCoverage will return with wait_for_recheck=false', [
      addFiles('coverage.js'),
      lspStartAndConnect(),
      addFile('sleep.js.ignored', 'sleep.js').verifyAllLSPMessagesInStep(
        [''],
        [...lspIgnoreStatusAndCancellation],
      ),
      lspRequestAndWaitUntilResponse('textDocument/typeCoverage', {
        textDocument: {uri: '<PLACEHOLDER_PROJECT_URL>/coverage.js'},
      })
        .verifyAllLSPMessagesInStep(
          [['textDocument/typeCoverage', '{"line":12,"line":8,"line":6}']],
          [...lspIgnoreStatusAndCancellation],
        )
        .timeout(2000),
    ]).waitForRecheck(false),

    test('telemetry/rage will time out with wait_for_recheck=true', [
      lspStartAndConnect(),
      addFile('sleep.js.ignored', 'sleep.js').verifyAllLSPMessagesInStep(
        [''],
        [...lspIgnoreStatusAndCancellation],
      ),
      lspRequestAndWaitUntilResponse('telemetry/rage', {})
        .verifyAllLSPMessagesInStep([], [...lspIgnoreStatusAndCancellation])
        .timeout(10000),
    ]).waitForRecheck(true),

    test('telemetry/rage will return with wait_for_recheck=false', [
      lspStartAndConnect(),
      addFile('sleep.js.ignored', 'sleep.js').verifyAllLSPMessagesInStep(
        [''],
        [...lspIgnoreStatusAndCancellation],
      ),
      lspRequestAndWaitUntilResponse('telemetry/rage', {})
        .verifyAllLSPMessagesInStep(
          ['telemetry/rage'],
          [...lspIgnoreStatusAndCancellation],
        )
        .timeout(10000),
    ]).waitForRecheck(false),
  ],
): Suite);
<|endoftext|>