text: var events = require('events');
  var os = require('os');
  var util = require('util');
  
  var debug = require('debug')('mavericks-bindings');
  
  var XpcConnection = require('@s524797336/xpc-connection');
  
  var localAddress  = require('./local-address');
  var uuidToAddress = require('./uuid-to-address');
  
  var NobleBindings = function() {
    this._peripherals = {};
  
    this._xpcConnection = new XpcConnection('com.apple.blued');
  
    this._xpcConnection.on('error', function(message) {
      this.emit('xpcError', message);
    }.bind(this));
  
    this._xpcConnection.on('event', function(event) {
      this.emit('xpcEvent', event);
    }.bind(this));
  };
  
  util.inherits(NobleBindings, events.EventEmitter);
  
  NobleBindings.prototype.sendXpcMessage = function(message) {
    this._xpcConnection.sendMessage(message);
  };
  
  var nobleBindings = new NobleBindings();
  
  nobleBindings.on('xpcEvent', function(event) {
    var kCBMsgId = event.kCBMsgId;
    var kCBMsgArgs = event.kCBMsgArgs;
  
    debug('xpcEvent: ' + JSON.stringify(event, undefined, 2));
  
    this.emit('kCBMsgId' + kCBMsgId, kCBMsgArgs);
  });
  
  nobleBindings.on('xpcError', function(message) {
    console.error('xpcError: ' + message);
  });
  
  nobleBindings.sendCBMsg = function(id, args) {
    debug('sendCBMsg: ' + id + ', ' + JSON.stringify(args, undefined, 2));
    this.sendXpcMessage({
      kCBMsgId: id,
      kCBMsgArgs: args
    });
  };
  
  nobleBindings.init = function() {
    this._xpcConnection.setup();
  
    localAddress(function(address) {
      if (address) {
        this.emit('addressChange', address);
      }
  
      this.sendCBMsg(1, {
        kCBMsgArgName: 'node-' + (new Date()).getTime(),
        kCBMsgArgOptions: {
            kCBInitOptionShowPowerAlert: 0
        },
        kCBMsgArgType: 0
      });
    }.bind(this));
  };
  
  nobleBindings.on('kCBMsgId6', function(args) {
    var state = ['unknown', 'resetting', 'unsupported', 'unauthorized', 'poweredOff', 'poweredOn'][args.kCBMsgArgState];
    debug('state change ' + state);
    this.emit('stateChange', state);
  });
  
  nobleBindings.startScanning = function(serviceUuids, allowDuplicates) {
    var args = {
      kCBMsgArgOptions: {},
      kCBMsgArgUUIDs: []
    };
  
    if (serviceUuids) {
      for(var i = 0; i < serviceUuids.length; i++) {
        args.kCBMsgArgUUIDs[i] = new Buffer(serviceUuids[i], 'hex');
      }
    }
  
    if (allowDuplicates) {
      args.kCBMsgArgOptions.kCBScanOptionAllowDuplicates = 1;
    }
  
    this.sendCBMsg(29, args);
  
    this.emit('scanStart');
  };
  
  nobleBindings.stopScanning = function() {
    this.sendCBMsg(30, null);
  
    this.emit('scanStop');
  };
  
  nobleBindings.on('kCBMsgId37', function(args) {
    if (Object.keys(args.kCBMsgArgAdvertisementData).length === 0) {
      return;
    }
  
    var deviceUuid = args.kCBMsgArgDeviceUUID.toString('hex');
    var advertisement = {
      localName: args.kCBMsgArgAdvertisementData.kCBAdvDataLocalName || args.kCBMsgArgName,
      txPowerLevel: args.kCBMsgArgAdvertisementData.kCBAdvDataTxPowerLevel,
      manufacturerData: args.kCBMsgArgAdvertisementData.kCBAdvDataManufacturerData,
      serviceData: [],
      serviceUuids: []
    };
    var rssi = args.kCBMsgArgRssi;
    var i;
  
    if (args.kCBMsgArgAdvertisementData.kCBAdvDataServiceUUIDs) {
      for(i = 0; i < args.kCBMsgArgAdvertisementData.kCBAdvDataServiceUUIDs.length; i++) {
        advertisement.serviceUuids.push(args.kCBMsgArgAdvertisementData.kCBAdvDataServiceUUIDs[i].toString('hex'));
      }
    }
  
    var serviceData = args.kCBMsgArgAdvertisementData.kCBAdvDataServiceData;
    if (serviceData) {
      for (i = 0; i < serviceData.length; i += 2) {
        var serviceDataUuid = serviceData[i].toString('hex');
        var data = serviceData[i + 1];
  
        advertisement.serviceData.push({
          uuid: serviceDataUuid,
          data: data
        });
      }
    }
  
    debug('peripheral ' + deviceUuid + ' discovered');
  
    var uuid = new Buffer(deviceUuid, 'hex');
    uuid.isUuid = true;
  
    if(!this._peripherals[deviceUuid]) {
      this._peripherals[deviceUuid] = {};
    }
    this._peripherals[deviceUuid].uuid = uuid;
    this._peripherals[deviceUuid].advertisement = advertisement;
    this._peripherals[deviceUuid].rssi = rssi;
  
    (function(deviceUuid, advertisement, rssi) {
      uuidToAddress(deviceUuid, function(error, address, addressType) {
        address = address || 'unknown';
        addressType = addressType || 'unknown';
  
        this._peripherals[deviceUuid].address = address;
        this._peripherals[deviceUuid].addressType = addressType;
  
        this.emit('discover', deviceUuid, address, addressType, undefined, advertisement, rssi);
      }.bind(this));
    }.bind(this))(deviceUuid, advertisement, rssi);
  });
  
  nobleBindings.connect = function(deviceUuid) {
    this.sendCBMsg(31, {
      kCBMsgArgOptions: {
        kCBConnectOptionNotifyOnDisconnection: 1
      },
      kCBMsgArgDeviceUUID: this._peripherals[deviceUuid].uuid
    });
  };
  
  nobleBindings.on('kCBMsgId38', function(args) {
    var deviceUuid = args.kCBMsgArgDeviceUUID.toString('hex');
  
    debug('peripheral ' + deviceUuid + ' connected');
  
    this.emit('connect', deviceUuid);
  });
  
  nobleBindings.disconnect = function(deviceUuid) {
    this.sendCBMsg(32, {
      kCBMsgArgDeviceUUID: this._peripherals[deviceUuid].uuid
    });
  };
  
  nobleBindings.on('kCBMsgId40', function(args) {
    var deviceUuid = args.kCBMsgArgDeviceUUID.toString('hex');
  
    debug('peripheral ' + deviceUuid + ' disconnected');
  
    this.emit('disconnect', deviceUuid);
  });
  
  nobleBindings.updateRssi = function(deviceUuid) {
    this.sendCBMsg(43, {
      kCBMsgArgDeviceUUID: this._peripherals[deviceUuid].uuid
    });
  };
  
  nobleBindings.on('kCBMsgId54', function(args) {
    var deviceUuid = args.kCBMsgArgDeviceUUID.toString('hex');
    var rssi = args.kCBMsgArgData;
  
    this._peripherals[deviceUuid].rssi = rssi;
  
    debug('peripheral ' + deviceUuid + ' RSSI update ' + rssi);
  
    this.emit('rssiUpdate', deviceUuid, rssi);
  });
  
  nobleBindings.discoverServices = function(deviceUuid, uuids) {
    var args = {
      kCBMsgArgDeviceUUID: this._peripherals[deviceUuid].uuid,
      kCBMsgArgUUIDs: []
    };
  
    if (uuids) {
      for(var i = 0; i < uuids.length; i++) {
        args.kCBMsgArgUUIDs[i] = new Buffer(uuids[i], 'hex');
      }
    }
  
    this.sendCBMsg(44, args);
  };
  
  nobleBindings.on('kCBMsgId55', function(args) {
    var deviceUuid = args.kCBMsgArgDeviceUUID.toString('hex');
    var serviceUuids = [];
  
    this._peripherals[deviceUuid].services = this._peripherals[deviceUuid].services || {};
  
    if (args.kCBMsgArgServices) {
      for(var i = 0; i < args.kCBMsgArgServices.length; i++) {
        var service = {
          uuid: args.kCBMsgArgServices[i].kCBMsgArgUUID.toString('hex'),
          startHandle: args.kCBMsgArgServices[i].kCBMsgArgServiceStartHandle,
          endHandle: args.kCBMsgArgServices[i].kCBMsgArgServiceEndHandle
        };
  
        this._peripherals[deviceUuid].services[service.uuid] = this._peripherals[deviceUuid].services[service.startHandle] = service;
  
        serviceUuids.push(service.uuid);
      }
    }
    // TODO: result 24 => device not connected
  
    this.emit('servicesDiscover', deviceUuid, serviceUuids);
  });
  
  nobleBindings.discoverIncludedServices = function(deviceUuid, serviceUuid, serviceUuids) {
    var args = {
      kCBMsgArgDeviceUUID: this._peripherals[deviceUuid].uuid,
      kCBMsgArgServiceStartHandle: this._peripherals[deviceUuid].services[serviceUuid].startHandle,
      kCBMsgArgServiceEndHandle: this._peripherals[deviceUuid].services[serviceUuid].endHandle,
      kCBMsgArgUUIDs: []
    };
  
    if (serviceUuids) {
      for(var i = 0; i < serviceUuids.length; i++) {
        args.kCBMsgArgUUIDs[i] = new Buffer(serviceUuids[i], 'hex');
      }
    }
  
    this.sendCBMsg(60, args);
  };
  
  nobleBindings.on('kCBMsgId62', function(args) {
    var deviceUuid = args.kCBMsgArgDeviceUUID.toString('hex');
    var serviceStartHandle = args.kCBMsgArgServiceStartHandle;
    var serviceUuid = this._peripherals[deviceUuid].services[serviceStartHandle].uuid;
    var result = args.kCBMsgArgResult;
    var includedServiceUuids = [];
  
    this._peripherals[deviceUuid].services[serviceStartHandle].includedServices =
      this._peripherals[deviceUuid].services[serviceStartHandle].includedServices || {};
  
    for(var i = 0; i < args.kCBMsgArgServices.length; i++) {
      var includedService = {
        uuid: args.kCBMsgArgServices[i].kCBMsgArgUUID.toString('hex'),
        startHandle: args.kCBMsgArgServices[i].kCBMsgArgServiceStartHandle,
        endHandle: args.kCBMsgArgServices[i].kCBMsgArgServiceEndHandle
      };
  
      if (! this._peripherals[deviceUuid].services[serviceStartHandle].includedServices[includedServices.uuid]) {
        this._peripherals[deviceUuid].services[serviceStartHandle].includedServices[includedServices.uuid] =
          this._peripherals[deviceUuid].services[serviceStartHandle].includedServices[includedServices.startHandle] = includedService;
      }
  
      includedServiceUuids.push(includedService.uuid);
    }
  
    this.emit('includedServicesDiscover', deviceUuid, serviceUuid, includedServiceUuids);
  });
  
  nobleBindings.discoverCharacteristics = function(deviceUuid, serviceUuid, characteristicUuids) {
    var args = {
      kCBMsgArgDeviceUUID: this._peripherals[deviceUuid].uuid,
      kCBMsgArgServiceStartHandle: this._peripherals[deviceUuid].services[serviceUuid].startHandle,
      kCBMsgArgServiceEndHandle: this._peripherals[deviceUuid].services[serviceUuid].endHandle,
      kCBMsgArgUUIDs: []
    };
  
    if (characteristicUuids) {
      for(var i = 0; i < characteristicUuids.length; i++) {
        args.kCBMsgArgUUIDs[i] = new Buffer(characteristicUuids[i], 'hex');
      }
    }
  
    this.sendCBMsg(61, args);
  };
  
  nobleBindings.on('kCBMsgId63', function(args) {
    var deviceUuid = args.kCBMsgArgDeviceUUID.toString('hex');
    var serviceStartHandle = args.kCBMsgArgServiceStartHandle;
    var serviceUuid = this._peripherals[deviceUuid].services[serviceStartHandle].uuid;
    var result = args.kCBMsgArgResult;
    var characteristics = [];
  
    this._peripherals[deviceUuid].services[serviceStartHandle].characteristics =
      this._peripherals[deviceUuid].services[serviceStartHandle].characteristics || {};
  
    for(var i = 0; i < args.kCBMsgArgCharacteristics.length; i++) {
      var properties = args.kCBMsgArgCharacteristics[i].kCBMsgArgCharacteristicProperties;
  
      var characteristic = {
        uuid: args.kCBMsgArgCharacteristics[i].kCBMsgArgUUID.toString('hex'),
        handle: args.kCBMsgArgCharacteristics[i].kCBMsgArgCharacteristicHandle,
        valueHandle: args.kCBMsgArgCharacteristics[i].kCBMsgArgCharacteristicValueHandle,
        properties: []
      };
  
      if (properties & 0x01) {
        characteristic.properties.push('broadcast');
      }
  
      if (properties & 0x02) {
        characteristic.properties.push('read');
      }
  
      if (properties & 0x04) {
        characteristic.properties.push('writeWithoutResponse');
      }
  
      if (properties & 0x08) {
        characteristic.properties.push('write');
      }
  
      if (properties & 0x10) {
        characteristic.properties.push('notify');
      }
  
      if (properties & 0x20) {
        characteristic.properties.push('indicate');
      }
  
      if (properties & 0x40) {
        characteristic.properties.push('authenticatedSignedWrites');
      }
  
      if (properties & 0x80) {
        characteristic.properties.push('extendedProperties');
      }
  
      this._peripherals[deviceUuid].services[serviceStartHandle].characteristics[characteristic.uuid] =
        this._peripherals[deviceUuid].services[serviceStartHandle].characteristics[characteristic.handle] =
        this._peripherals[deviceUuid].services[serviceStartHandle].characteristics[characteristic.valueHandle] = characteristic;
  
      characteristics.push({
        uuid: characteristic.uuid,
        properties: characteristic.properties
      });
    }
  
    this.emit('characteristicsDiscover', deviceUuid, serviceUuid, characteristics);
  });
  
  nobleBindings.read = function(deviceUuid, serviceUuid, characteristicUuid) {
    this.sendCBMsg(64 , {
      kCBMsgArgDeviceUUID: this._peripherals[deviceUuid].uuid,
      kCBMsgArgCharacteristicHandle: this._peripherals[deviceUuid].services[serviceUuid].characteristics[characteristicUuid].handle,
      kCBMsgArgCharacteristicValueHandle: this._peripherals[deviceUuid].services[serviceUuid].characteristics[characteristicUuid].valueHandle
    });
  };
  
  nobleBindings.on('kCBMsgId70', function(args) {
    var deviceUuid = args.kCBMsgArgDeviceUUID.toString('hex');
    var characteristicHandle = args.kCBMsgArgCharacteristicHandle;
    var isNotification = args.kCBMsgArgIsNotification ? true : false;
    var data = args.kCBMsgArgData;
  
    var peripheral = this._peripherals[deviceUuid];
  
    if (peripheral) {
      for(var i in peripheral.services) {
        if (peripheral.services[i].characteristics &&
            peripheral.services[i].characteristics[characteristicHandle]) {
  
          this.emit('read', deviceUuid, peripheral.services[i].uuid,
            peripheral.services[i].characteristics[characteristicHandle].uuid, data, isNotification);
          break;
        }
      }
    } else {
      console.warn('noble (mac mavericks): received read event from unknown peripheral: ' + deviceUuid + ' !');
    }
  });
  
  nobleBindings.write = function(deviceUuid, serviceUuid, characteristicUuid, data, withoutResponse) {
    this.sendCBMsg(65, {
      kCBMsgArgDeviceUUID: this._peripherals[deviceUuid].uuid,
      kCBMsgArgCharacteristicHandle: this._peripherals[deviceUuid].services[serviceUuid].characteristics[characteristicUuid].handle,
      kCBMsgArgCharacteristicValueHandle: this._peripherals[deviceUuid].services[serviceUuid].characteristics[characteristicUuid].valueHandle,
      kCBMsgArgData: data,
      kCBMsgArgType: (withoutResponse ? 1 : 0)
    });
  
    if (withoutResponse) {
      this.emit('write', deviceUuid, serviceUuid, characteristicUuid);
    }
  };
  
  nobleBindings.on('kCBMsgId71', function(args) {
    var deviceUuid = args.kCBMsgArgDeviceUUID.toString('hex');
    var characteristicHandle = args.kCBMsgArgCharacteristicHandle;
    var result = args.kCBMsgArgResult;
  
    for(var i in this._peripherals[deviceUuid].services) {
      if (this._peripherals[deviceUuid].services[i].characteristics &&
          this._peripherals[deviceUuid].services[i].characteristics[characteristicHandle]) {
        this.emit('write', deviceUuid, this._peripherals[deviceUuid].services[i].uuid,
          this._peripherals[deviceUuid].services[i].characteristics[characteristicHandle].uuid);
        break;
      }
    }
  });
  
  nobleBindings.broadcast = function(deviceUuid, serviceUuid, characteristicUuid, broadcast) {
    this.sendCBMsg(66, {
      kCBMsgArgDeviceUUID: this._peripherals[deviceUuid].uuid,
      kCBMsgArgCharacteristicHandle: this._peripherals[deviceUuid].services[serviceUuid].characteristics[characteristicUuid].handle,
      kCBMsgArgCharacteristicValueHandle: this._peripherals[deviceUuid].services[serviceUuid].characteristics[characteristicUuid].valueHandle,
      kCBMsgArgState: (broadcast ? 1 : 0)
    });
  };
  
  nobleBindings.on('kCBMsgId72', function(args) {
    var deviceUuid = args.kCBMsgArgDeviceUUID.toString('hex');
    var characteristicHandle = args.kCBMsgArgCharacteristicHandle;
    var result = args.kCBMsgArgResult;
    var state = args.kCBMsgArgState ? true : false;
  
    for(var i in this._peripherals[deviceUuid].services) {
      if (this._peripherals[deviceUuid].services[i].characteristics &&
          this._peripherals[deviceUuid].services[i].characteristics[characteristicHandle]) {
        this.emit('broadcast', deviceUuid, this._peripherals[deviceUuid].services[i].uuid,
          this._peripherals[deviceUuid].services[i].characteristics[characteristicHandle].uuid, state);
        break;
      }
    }
  });
  
  nobleBindings.notify = function(deviceUuid, serviceUuid, characteristicUuid, notify) {
    this.sendCBMsg(67, {
      kCBMsgArgDeviceUUID: this._peripherals[deviceUuid].uuid,
      kCBMsgArgCharacteristicHandle: this._peripherals[deviceUuid].services[serviceUuid].characteristics[characteristicUuid].handle,
      kCBMsgArgCharacteristicValueHandle: this._peripherals[deviceUuid].services[serviceUuid].characteristics[characteristicUuid].valueHandle,
      kCBMsgArgState: (notify ? 1 : 0)
    });
  };
  
  nobleBindings.on('kCBMsgId73', function(args) {
    var deviceUuid = args.kCBMsgArgDeviceUUID.toString('hex');
    var characteristicHandle = args.kCBMsgArgCharacteristicHandle;
    var result = args.kCBMsgArgResult;
    var state = args.kCBMsgArgState ? true : false;
  
    for(var i in this._peripherals[deviceUuid].services) {
      if (this._peripherals[deviceUuid].services[i].characteristics &&
          this._peripherals[deviceUuid].services[i].characteristics[characteristicHandle]) {
        this.emit('notify', deviceUuid, this._peripherals[deviceUuid].services[i].uuid,
          this._peripherals[deviceUuid].services[i].characteristics[characteristicHandle].uuid, state);
        break;
      }
    }
  });
  
  nobleBindings.discoverDescriptors = function(deviceUuid, serviceUuid, characteristicUuid) {
    this.sendCBMsg(69, {
      kCBMsgArgDeviceUUID: this._peripherals[deviceUuid].uuid,
      kCBMsgArgCharacteristicHandle: this._peripherals[deviceUuid].services[serviceUuid].characteristics[characteristicUuid].handle,
      kCBMsgArgCharacteristicValueHandle: this._peripherals[deviceUuid].services[serviceUuid].characteristics[characteristicUuid].valueHandle
    });
  };
  
  nobleBindings.on('kCBMsgId75', function(args) {
    var deviceUuid = args.kCBMsgArgDeviceUUID.toString('hex');
    var characteristicHandle = args.kCBMsgArgCharacteristicHandle;
    var result = args.kCBMsgArgResult;
    var descriptors = []; //args.kCBMsgArgDescriptors;
  
    for(var i in this._peripherals[deviceUuid].services) {
      if (this._peripherals[deviceUuid].services[i].characteristics &&
          this._peripherals[deviceUuid].services[i].characteristics[characteristicHandle]) {
  
        this._peripherals[deviceUuid].services[i].characteristics[characteristicHandle].descriptors = {};
  
        for(var j = 0; j < args.kCBMsgArgDescriptors.length; j++) {
          var descriptor = {
            uuid: args.kCBMsgArgDescriptors[j].kCBMsgArgUUID.toString('hex'),
            handle: args.kCBMsgArgDescriptors[j].kCBMsgArgDescriptorHandle
          };
  
          this._peripherals[deviceUuid].services[i].characteristics[characteristicHandle].descriptors[descriptor.uuid] =
            this._peripherals[deviceUuid].services[i].characteristics[characteristicHandle].descriptors[descriptor.handle] = descriptor;
  
          descriptors.push(descriptor.uuid);
        }
  
        this.emit('descriptorsDiscover', deviceUuid, this._peripherals[deviceUuid].services[i].uuid,
          this._peripherals[deviceUuid].services[i].characteristics[characteristicHandle].uuid, descriptors);
        break;
      }
    }
  });
  
  nobleBindings.readValue = function(deviceUuid, serviceUuid, characteristicUuid, descriptorUuid) {
    this.sendCBMsg(76, {
      kCBMsgArgDeviceUUID: this._peripherals[deviceUuid].uuid,
      kCBMsgArgDescriptorHandle: this._peripherals[deviceUuid].services[serviceUuid].characteristics[characteristicUuid].descriptors[descriptorUuid].handle
    });
  };
  
  nobleBindings.on('kCBMsgId78', function(args) {
    var deviceUuid = args.kCBMsgArgDeviceUUID.toString('hex');
    var descriptorHandle = args.kCBMsgArgDescriptorHandle;
    var result = args.kCBMsgArgResult;
    var data = args.kCBMsgArgData;
  
    this.emit('handleRead', deviceUuid, descriptorHandle, data);
  
    for(var i in this._peripherals[deviceUuid].services) {
      for(var j in this._peripherals[deviceUuid].services[i].characteristics) {
        if (this._peripherals[deviceUuid].services[i].characteristics[j].descriptors &&
          this._peripherals[deviceUuid].services[i].characteristics[j].descriptors[descriptorHandle]) {
  
          this.emit('valueRead', deviceUuid, this._peripherals[deviceUuid].services[i].uuid,
            this._peripherals[deviceUuid].services[i].characteristics[j].uuid,
            this._peripherals[deviceUuid].services[i].characteristics[j].descriptors[descriptorHandle].uuid, data);
          return; // break;
        }
      }
    }
  });
  
  nobleBindings.writeValue = function(deviceUuid, serviceUuid, characteristicUuid, descriptorUuid, data) {
    this.sendCBMsg(77, {
      kCBMsgArgDeviceUUID: this._peripherals[deviceUuid].uuid,
      kCBMsgArgDescriptorHandle: this._peripherals[deviceUuid].services[serviceUuid].characteristics[characteristicUuid].descriptors[descriptorUuid].handle,
      kCBMsgArgData: data
    });
  };
  
  nobleBindings.on('kCBMsgId79', function(args) {
    var deviceUuid = args.kCBMsgArgDeviceUUID.toString('hex');
    var descriptorHandle = args.kCBMsgArgDescriptorHandle;
    var result = args.kCBMsgArgResult;
  
    this.emit('handleWrite', deviceUuid, descriptorHandle);
  
    for(var i in this._peripherals[deviceUuid].services) {
      for(var j in this._peripherals[deviceUuid].services[i].characteristics) {
        if (this._peripherals[deviceUuid].services[i].characteristics[j].descriptors &&
          this._peripherals[deviceUuid].services[i].characteristics[j].descriptors[descriptorHandle]) {
  
          this.emit('valueWrite', deviceUuid, this._peripherals[deviceUuid].services[i].uuid,
            this._peripherals[deviceUuid].services[i].characteristics[j].uuid,
            this._peripherals[deviceUuid].services[i].characteristics[j].descriptors[descriptorHandle].uuid);
          return; // break;
        }
      }
    }
  });
  
  nobleBindings.readHandle = function(deviceUuid, handle) {
    this.sendCBMsg(76, {
      kCBMsgArgDeviceUUID: this._peripherals[deviceUuid].uuid,
      kCBMsgArgDescriptorHandle: handle
    });
  };
  
  nobleBindings.writeHandle = function(deviceUuid, handle, data, withoutResponse) {
    // TODO: use without response
    this.sendCBMsg(77, {
      kCBMsgArgDeviceUUID: this._peripherals[deviceUuid].uuid,
      kCBMsgArgDescriptorHandle: handle,
      kCBMsgArgData: data
    });
  };
  
  module.exports = nobleBindings;
  