<commit_before>var debug = require('debug')('hci-ble');

var events = require('events');
var spawn = require('child_process').spawn;
var util = require('util');

var HciBle = function() {
  var hciBle = __dirname + '/../../build/Release/hci-ble';
  
  debug('hciBle = ' + hciBle);

  this._hciBle = spawn('stdbuf', ['-o', '0', '-e', '0', '-i', '0', hciBle]);
  this._hciBle.on('close', this.onClose.bind(this));

  this._hciBle.stdout.on('data', this.onStdoutData.bind(this));
  this._hciBle.stderr.on('data', this.onStderrData.bind(this));

  this._hciBle.on('error', function() { });

  this._buffer = "";

  this._discoveries = {};
};

util.inherits(HciBle, events.EventEmitter);

HciBle.prototype.onClose = function(code) {
  debug('close = ' + code);
};

HciBle.prototype.onStdoutData = function(data) {
  this._buffer += data.toString();

  debug('buffer = ' + JSON.stringify(this._buffer));

  var newLineIndex;
  while ((newLineIndex = this._buffer.indexOf('\n')) !== -1) {
    var line = this._buffer.substring(0, newLineIndex);
    var found;
    
    this._buffer = this._buffer.substring(newLineIndex + 1);

    debug('line = ' + line);

    if ((found = line.match(/^adapterState (.*)$/))) {
      var adapterState = found[1];

      debug('adapterState = ' + adapterState);

      if (adapterState === 'unauthorized') {
        console.log('noble warning: adapter state unauthorized, please run as root or with sudo');
      }
      
      this.emit('stateChange', adapterState);
    } else if ((found = line.match(/^event (.*)$/))) {
      var event = found[1];
      var splitEvent = event.split(',');

      var address = splitEvent[0];
      var addressType = splitEvent[1];
      var eir = new Buffer(splitEvent[2], 'hex');
      var rssi = parseInt(splitEvent[3], 10);

      debug('address = ' + address);
      debug('addressType = ' + addressType);
      debug('eir = ' + eir.toString('hex'));
      debug('rssi = ' + rssi);

      var previouslyDiscovered = !!this._discoveries[address];
      var advertisement =  previouslyDiscovered ? this._discoveries[address].advertisement : {
        localName: undefined,
        serviceData: undefined,
        txPowerLevel: undefined,
        manufacturerData: undefined,
        serviceUuids: []
      };

      var i = 0;
      var j = 0;

      while (i < eir.length) {
        var length = eir.readUInt8(i);
        var type = eir.readUInt8(i + 1); // https://www.bluetooth.org/en-us/specification/assigned-numbers/generic-access-profile
        var bytes = eir.slice(i + 2).slice(0, length - 1);

        switch(type) {
          case 0x02: // Incomplete List of 16-bit Service Class UUID
          case 0x03: // Complete List of 16-bit Service Class UUIDs
            for (j = 0; j < bytes.length; j += 2) {
              advertisement.serviceUuids.push(bytes.readUInt16LE(j).toString(16));
            }
            break;

          case 0x06: // Incomplete List of 128-bit Service Class UUIDs
          case 0x07: // Complete List of 128-bit Service Class UUIDs
            for (j = 0; j < bytes.length; j += 16) {
              advertisement.serviceUuids.push(bytes.slice(j, j + 16).toString('hex').match(/.{1,2}/g).reverse().join(''));
            }
            break;

          case 0x08: // Shortened Local Name
          case 0x09: // Complete Local Name»
            advertisement.localName = bytes.toString('utf8');
            break;

          case 0x0a: // Tx Power Level
            advertisement.txPowerLevel = bytes.readInt8(0);
            break;

          case 0x16: // Service Data
            // TODO: maybe this should be a buffer, do we need to reverse?
            advertisement.serviceData = bytes.toString('hex');
            break;

          case 0xff: // Manufacturer Specific Data
            // TODO: maybe this should be a buffer, do we need to reverse?
            advertisement.manufacturerData = bytes.toString('hex');
            break;
        }

        i += (length + 1);
      }

      debug('advertisement = ' + JSON.stringify(advertisement, null, 0));

      var discoveryCount = previouslyDiscovered ? this._discoveries[address].count : 0;

      this._discoveries[address] = {
        address: address,
        addressType: addressType,
        advertisement: advertisement,
        rssi: rssi,
        count: (discoveryCount + 1)
      };

      // only report after an even number of events, so more advertisement data can be collected
      if (this._discoveries[address].count % 2 === 0) {
        this.emit('discover', address, addressType, advertisement, rssi);
      }<commit_msg>- don't add existing services to advertisement service uuids, leave service and manufacturer data as is<commit_after>var debug = require('debug')('hci-ble');

var events = require('events');
var spawn = require('child_process').spawn;
var util = require('util');

var HciBle = function() {
  var hciBle = __dirname + '/../../build/Release/hci-ble';
  
  debug('hciBle = ' + hciBle);

  this._hciBle = spawn('stdbuf', ['-o', '0', '-e', '0', '-i', '0', hciBle]);
  this._hciBle.on('close', this.onClose.bind(this));

  this._hciBle.stdout.on('data', this.onStdoutData.bind(this));
  this._hciBle.stderr.on('data', this.onStderrData.bind(this));

  this._hciBle.on('error', function() { });

  this._buffer = "";

  this._discoveries = {};
};

util.inherits(HciBle, events.EventEmitter);

HciBle.prototype.onClose = function(code) {
  debug('close = ' + code);
};

HciBle.prototype.onStdoutData = function(data) {
  this._buffer += data.toString();

  debug('buffer = ' + JSON.stringify(this._buffer));

  var newLineIndex;
  while ((newLineIndex = this._buffer.indexOf('\n')) !== -1) {
    var line = this._buffer.substring(0, newLineIndex);
    var found;
    
    this._buffer = this._buffer.substring(newLineIndex + 1);

    debug('line = ' + line);

    if ((found = line.match(/^adapterState (.*)$/))) {
      var adapterState = found[1];

      debug('adapterState = ' + adapterState);

      if (adapterState === 'unauthorized') {
        console.log('noble warning: adapter state unauthorized, please run as root or with sudo');
      }
      
      this.emit('stateChange', adapterState);
    } else if ((found = line.match(/^event (.*)$/))) {
      var event = found[1];
      var splitEvent = event.split(',');

      var address = splitEvent[0];
      var addressType = splitEvent[1];
      var eir = new Buffer(splitEvent[2], 'hex');
      var rssi = parseInt(splitEvent[3], 10);

      debug('address = ' + address);
      debug('addressType = ' + addressType);
      debug('eir = ' + eir.toString('hex'));
      debug('rssi = ' + rssi);

      var previouslyDiscovered = !!this._discoveries[address];
      var advertisement =  previouslyDiscovered ? this._discoveries[address].advertisement : {
        localName: undefined,
        serviceData: undefined,
        txPowerLevel: undefined,
        manufacturerData: undefined,
        serviceUuids: []
      };

      var i = 0;
      var j = 0;

      while (i < eir.length) {
        var length = eir.readUInt8(i);
        var type = eir.readUInt8(i + 1); // https://www.bluetooth.org/en-us/specification/assigned-numbers/generic-access-profile
        var bytes = eir.slice(i + 2).slice(0, length - 1);

        switch(type) {
          case 0x02: // Incomplete List of 16-bit Service Class UUID
          case 0x03: // Complete List of 16-bit Service Class UUIDs
            for (j = 0; j < bytes.length; j += 2) {
              var uuid = bytes.readUInt16LE(j).toString(16);
              if (advertisement.serviceUuids.indexOf(uuid) === -1) {
                advertisement.serviceUuids.push();
              }
            }
            break;

          case 0x06: // Incomplete List of 128-bit Service Class UUIDs
          case 0x07: // Complete List of 128-bit Service Class UUIDs
            for (j = 0; j < bytes.length; j += 16) {
              var uuid = bytes.slice(j, j + 16).toString('hex').match(/.{1,2}/g).reverse().join('');
              if (advertisement.serviceUuids.indexOf(uuid) === -1) {
                advertisement.serviceUuids.push();
              }
            }
            break;

          case 0x08: // Shortened Local Name
          case 0x09: // Complete Local Name»
            advertisement.localName = bytes.toString('utf8');
            break;

          case 0x0a: // Tx Power Level
            advertisement.txPowerLevel = bytes.readInt8(0);
            break;

          case 0x16: // Service Data
            advertisement.serviceData = bytes;
            break;

          case 0xff: // Manufacturer Specific Data
            advertisement.manufacturerData = bytes;
            break;
        }

        i += (length + 1);
      }

      debug('advertisement = ' + JSON.stringify(advertisement, null, 0));

      var discoveryCount = previouslyDiscovered ? this._discoveries[address].count : 0;

      this._discoveries[address] = {
        address: address,
        addressType: addressType,
        advertisement: advertisement,
        rssi: rssi,
        count: (discoveryCount + 1)
      };

      // only report after an even number of events, so more advertisement data can be collected
      if (this._discoveries[address].count % 2 === 0) {
        this.emit('discover', address, addressType, advertisement, rssi);
      }
{'fraction_non_alphanumeric': 0.1443398245238605, 'fraction_numerical': 0.016905628076182323, 'mean_word_length': 2.390279289082336, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 3, 'https://': 2, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1508009', 'n_tokens_mistral': 2984, 'n_tokens_neox': 2819, 'n_words': 667}