<commit_before>;
/*!
 * Tarsier JavaScript Library v1.0.1
 * http://github.com/moky/Tarsier/
 *
 * Copyright 2013 moKy at slanissue.com
 * Released under the MIT license
 * http://jquery.org/license
 *
 * Date: 2013-12-11 T10:43Z
 */

/**
 *
 *  String utilities
 *
 *  Author: moKy @ Jan. 14, 2014
 *
 */

(function(tarsier) {

	function alert(message) {
		message = "[Tarsier] string.js > " + message;
		if (typeof(tarsier.log) === "function") {
			tarsier.log(message);
		} else {
			window.alert(message);
		}
	}

	function lowercase(str) {
		for (var i = str.length - 1; i >= 0; --i) {
			str[0] = str[0].toLowerCase();
		}
		return str;
	}
	// standard key? short key?
	function _sk(str) {
		return lowercase(str.replace(/\-/g, ""));
	}
	// convertor key
	function convertor_key(from, to) {
		return _sk(from) + " -> " + _sk(to);
	}

	//
	// convertor
	//
	var _convertors = []; // key: 'from -> to'

	// getter
	tarsier.convertor = function(from, to) {
		var key = convertor_key(from, to);
		// 1. convert directly
		var conv = _convertors[key];
		if (conv) {
			return conv;
		}
		// 2. convert via 'utf-8'
		var key1 = convertor_key(from, "utf-8");
		var key2 = convertor_key("utf-8", to);
		var conv1 = _convertors[key1];
		var conv2 = _convertors[key2];
		if (conv1 && conv2) {
			// save it for next query
			conv = function(str) { return conv2(conv1(str)); };
			_convertors[key] = conv;
			return conv;
		}
		alert("cannot find convertor: (" + from + " -> " + to + ")");
		return null;
	};
	// setter
	tarsier.setConvertor = function(from, to, convertor) {
		var key = convertor_key(from, to);
		_convertors[key] = convertor;
	};
	// conv
	tarsier.convert = function(from, to, data) {
		// same charsets
		if (from === to) {
			return data;
		}
		var conv = this.convertor(from, to);
		if (conv) {
			return conv(data);
		}
		// sorry....
		return data;
	};

	//
	// en/decoder
	//
	var _encoders = [];
	var _decoders = [];

	// getter
	tarsier.encoder = function(name) {
		return _encoders[_sk(name)];
	};
	tarsier.decoder = function(name) {
		return _decoders[_sk(name)];
	};
	// setter
	tarsier.setEncoder = function(name, encoder) {
		_encoders[_sk(name)] = encoder;
	};
	tarsier.setDecoder = function(name, decoder) {
		_decoders[_sk(name)] = decoder;
	};
	// encode
	tarsier.encode = function(name, data) {
		var func = this.encoder(name);
		if (func) {
			return func(data);
		}
		alert("unsupported encoder: " + name);
		return data;
	};
	// decode
	tarsier.decode = function(name, data) {
		var func = this.decode(name);
		if (func) {
			return func(data);
		}
		alert("unsupported decoder: " + name);
		return data;
	};

	//--------------------------------------------------------------------------

	// class: String
	tarsier.String = function(string, charset) {
		this.charset = charset || "utf-16";
		this.data = string;
		return this;
	};

	// converting string from 'this.charset' to 'charset'
	tarsier.String.prototype.convertTo = function(charset) {
		return tarsier.convert(this.charset, charset, this.data);
	};

	// encode
	tarsier.String.prototype.encode = function(name, data) {
		data = data || this.data;
		var encode = tarsier.encoder(name);
		if (encode) {
			return encode(data);
		} else {
			alert("unsupported encoder: " + name);
			return data;
		}
	};
	// decode
	tarsier.String.prototype.decode = function(name, data) {
		data = data || this.data;
		var decode = tarsier.decoder(name);
		if (decode) {
			return decode(data);
		} else {
			alert("unsupported decoder: " + name);
			return data;
		}
	};

})(tarsier);
<commit_msg>v1.0.2<commit_after>;
/*!
 * Tarsier JavaScript Library v1.0.1
 * http://github.com/moky/Tarsier/
 *
 * Copyright 2013 moKy at slanissue.com
 * Released under the MIT license
 * http://jquery.org/license
 *
 * Date: 2013-12-11 T10:43Z
 */

/**
 *
 *  String utilities
 *
 *  Author: moKy @ Jan. 14, 2014
 *
 */

(function(tarsier) {

	function alert(message) {
		message = "[Tarsier] string.js > " + message;
		if (typeof(tarsier.log) === "function") {
			tarsier.log(message);
		} else {
			window.alert(message);
		}
	}

	function lowercase(str) {
		for (var i = str.length - 1; i >= 0; --i) {
			str[0] = str[0].toLowerCase();
		}
		return str;
	}
	// standard key? short key?
	function _sk(str) {
		return lowercase(str.replace(/\-/g, ""));
	}
	// convertor key
	function convertor_key(from, to) {
		return _sk(from) + " -> " + _sk(to);
	}

	//--------------------------------------------------------------------------

	//
	// convertor
	//
	var _convertors = []; // key: 'from -> to'

	// getter
	tarsier.convertor = function(from, to) {
		var key = convertor_key(from, to);
		// 1. convert directly
		var conv = _convertors[key];
		if (conv) {
			return conv;
		}
		// 2. convert via 'utf-8'
		var key1 = convertor_key(from, "utf-8");
		var key2 = convertor_key("utf-8", to);
		var conv1 = _convertors[key1];
		var conv2 = _convertors[key2];
		if (conv1 && conv2) {
			// save it for next query
			conv = function(str) { return conv2(conv1(str)); };
			_convertors[key] = conv;
			return conv;
		}
		alert("cannot find convertor: (" + from + " -> " + to + ")");
		return null;
	};
	// setter
	tarsier.setConvertor = function(from, to, convertor) {
		var key = convertor_key(from, to);
		_convertors[key] = convertor;
	};
	// conv
	tarsier.convert = function(from, to, data) {
		// same charsets
		if (from === to) {
			return data;
		}
		var conv = this.convertor(from, to);
		if (conv) {
			return conv(data);
		}
		// sorry....
		return data;
	};

	//--------------------------------------------------------------------------

	//
	// en/decoder
	//
	var _encoders = [];
	var _decoders = [];

	// getter
	tarsier.encoder = function(name) {
		return _encoders[_sk(name)];
	};
	tarsier.decoder = function(name) {
		return _decoders[_sk(name)];
	};
	// setter
	tarsier.setEncoder = function(name, encoder) {
		_encoders[_sk(name)] = encoder;
	};
	tarsier.setDecoder = function(name, decoder) {
		_decoders[_sk(name)] = decoder;
	};
	// encode
	tarsier.encode = function(name, data) {
		var func = this.encoder(name);
		if (func) {
			return func(data);
		}
		alert("unsupported encoder: " + name);
		return data;
	};
	// decode
	tarsier.decode = function(name, data) {
		var func = this.decode(name);
		if (func) {
			return func(data);
		}
		alert("unsupported decoder: " + name);
		return data;
	};

	//--------------------------------------------------------------------------

	// class: String
	tarsier.String = function(string, charset) {
		this.charset = charset || "utf-16";
		this.data = string;
		return this;
	};

	// converting string from 'this.charset' to 'charset'
	tarsier.String.prototype.convertTo = function(charset) {
		return tarsier.convert(this.charset, charset, this.data);
	};

	// encode
	tarsier.String.prototype.encode = function(name, data) {
		data = data || this.data;
		var encode = tarsier.encoder(name);
		if (encode) {
			return encode(data);
		} else {
			alert("unsupported encoder: " + name);
			return data;
		}
	};
	// decode
	tarsier.String.prototype.decode = function(name, data) {
		data = data || this.data;
		var decode = tarsier.decoder(name);
		if (decode) {
			return decode(data);
		} else {
			alert("unsupported decoder: " + name);
			return data;
		}
	};

})(tarsier);
<|endoftext|>


<commit_before>'use strict';

var util = require('util');
var events = require('events');
var dbus = require('dbus-native');
var async = require('async');
var debug = require('debug')('bluez-mgr');

var exec = require('child_process').exec;

var Defs = require('./bluez-defs.js');
var Advertise = require('./advertise.js');
var Advertisement = Advertise.Advertisement;
var AdvertisementIface = Advertise.AdvertisementIface;

var ObjectManagerIface = {
    name: Defs.Dbus.BLUEZ_OBJ_MANAGER_INTERFACE,
    methods: {
      GetManagedObjects: ['', 'a{oa{sa{sv}}}']
    },
    signals: {
    },
    properties: {
    }
};

var PropIface = {
    name: Defs.Dbus.DBUS_PROP_IFACE,
    methods: {
      GetAll: ['s', 'a{sv}']
    },
    signals: {
      PropertiesChanged: ['sa{sv}as', 'interface', 'changed', 'invalidated']
    },
    properties: {
    }
};

var CharIface = {
    name: Defs.Dbus.GATT_CHRC_IFACE,
    methods: {
      ReadValue: ['', 'ay'],
      WriteValue: ['ay', ''],
      StartNotify: ['', ''],
      StopNotify: ['', '']
    },
    signals: {
    },
    properties: {
    }
};

var DescIface = {
    name: Defs.Dbus.GATT_DESC_IFACE,
    methods: {
      ReadValue: ['', 'ay']
    },
    signals: {
    },
    properties: {
    }
};

var ServiceIface = {
    name: Defs.Dbus.GATT_SERVICE_IFACE,
    methods: {
    },
    signals: {
    },
    properties: {
      UUID: 's',
      Primary: 'b'
    }
};

function parseProps(rawProps) {
    var parsed = {};
    rawProps.forEach(function(prop) {
        var propName = prop[0];
        //TODO prop[1][0] has the type info, do we need it?
        var propValue = prop[1][1][0];

        parsed[propName] = propValue;
    });
    return parsed;
}

function BluezManager(configOptions) {
    this.objMng = null;
    this.adapterPaths = [];
    this.devices = Object.create(null);
    this.config = configOptions || {};

    events.EventEmitter.call(this);
}

util.inherits(BluezManager, events.EventEmitter);

BluezManager.prototype._handleInterfaceAdded = function _handleInterfaceAdded(path, interfaces) {
    debug('InterfacesAdded on', path, interfaces);
};

BluezManager.prototype._handleInterfaceRemoved =
    function _handleInterfaceRemoved(path, interfaces) {
    //TODO handle removal of ble adapter!
    debug('InterfacesRemoved', path, interfaces);
};

BluezManager.prototype._getAdapterPath = function _getAdapterPath() {
    return this.adapterPaths[0];
};

BluezManager.prototype._addDevice = function _addDevice(devicePath, cb) {
    var self = this;
    cb = cb || function(){};
    this.dbusService.getInterface(devicePath, Defs.Dbus.DBUS_PROP_IFACE, function(err, obj) {
        if (err) {
          return cb(err);
        }
        self.devices[devicePath] = obj;
        obj.on('PropertiesChanged', function(path, rawProps) {
            var props = parseProps(rawProps);
            debug('Properties changed in device %j', props);

            //TODO can actually emit any prop change here. Needed?
            if ('Connected' in props) {
                self.emit('device-connect', devicePath, props.Connected);
            }
        });
    });
};

BluezManager.prototype._advertise = function _advertise(callback) {
    function legacyAdvertise(cb) {
        debug('Legacy Advertising');
        //TODO Bluez does not support advertising via Dbus api yet (not on kernels < 4.1 anyway)
        //So this is just a hack

        //Sets the advertising packet
        //2=length, 1=ad type flags,
        //5=GAP_ADTYPE_FLAGS_LIMITED(1) | GAP_ADTYPE_FLAGS_BREDR_NOT_SUPPORTED(4)
        //(No classic only ble)
        //TODO assumes hci0 is the adapter
        exec('hcitool -i hci0 cmd 0x08 0x0008 3 02 01 05' +
            '&& hciconfig hci0 leadv', function (error, stdout, stderr) {
            debug('hciconfiguration error', error, 'stdout', stdout, 'stderr', stderr);
            cb(error);
        });
    }

    var cb = callback || function(){};
    var self = this;

    if (this.config.legacyAdvertising) {
        legacyAdvertise(cb);
        self.on('device-connect', function(path, isConnected) {
            if (!isConnected) {
                legacyAdvertise(cb);
            }
        });
    } else {
        self.sysbus.exportInterface(
            self.advertisement, self.advertisement.getPath(), AdvertisementIface);
        self.sysbus.exportInterface(
            self.advertisement, self.advertisement.getPath(), PropIface);

        self.dbusService.getInterface(
            self._getAdapterPath(),
            Defs.Dbus.LE_ADVERTISING_MANAGER_IFACE,
            function (err, adManager) {

                adManager.RegisterAdvertisement(
                    self.advertisement.getPath(),
                    {},
                    function(err, data) {
                        cb(err, data);
                    });
            }
        );
    }
};

BluezManager.prototype._handleDeviceConn = function _handleDeviceConn(devicePath, isConnected) {
  if (!isConnected) {
      //TODO this is not the best approach now since we do not really know if the
      //disconnected device was a client to these services but bluez does not offer
      //a way to know that, i.e. device was a client of these services or it was a server.
      this.services.forEach(function(service) {
          service.onDisconnect();
      });
  }
};

BluezManager.prototype.init = function init(cb) {
    var self = this;

    this.sysbus = dbus.systemBus();
    this.dbusService = this.sysbus.getService(Defs.Dbus.BLUEZ_DBUS_SERVICE_NAME);

    this.sysbus.connection.on('error', function (err) {
        debug('Dbus error', err);
        throw err;
    });

    this.sysbus.connection.on('end', function () {
        debug('Dbus end');
    });

    self._crawl(function(err) {
        if (err) {
            return cb(err);
        }

        if (self.adapterPaths.length === 0) {
            return cb(new Error('No Adapter Found!'));
        }

        self.on('device-connect', self._handleDeviceConn.bind(self));

        cb(null);
    });
};

BluezManager.prototype.start = function start(options, cb) {
    var self = this;
    this.services = options.services || [];
    this.advertisement = options.advertisement ||
                            new Advertisement('advertisement', 'peripheral', {
                                    service_uuids: ['180D'],
                                    manufacturer_data: [0xffff, [0x00, 0x01, 0x02, 0x03, 0x04]],
                                    service_data: ['9999', [0x00, 0x01, 0x02, 0x03, 0x04]]});
    async.series([
        self.init.bind(self),
        self._advertise.bind(self),
        self.registerBleServices.bind(self, self.services)
    ], cb);
};

BluezManager.prototype.close = function close(cb) {
    var self = this;
    // It seems like services are unregistered automatically
    //so just unregistering the advertisement here
    self.dbusService.getInterface(
        self._getAdapterPath(),
        Defs.Dbus.LE_ADVERTISING_MANAGER_IFACE,
        function (err, adManager) {
            adManager.UnregisterAdvertisement(self.advertisement.getPath(), function(err) {
                cb(err);
            });
        });
};

BluezManager.prototype._crawl = function _crawl(cb) {
    var self = this;

    function crawlManagedObject(objPath, current) {
        var interfaceName = current[0];
        if (interfaceName === Defs.Dbus.BLUEZ_ADAPTER_INTERFACE) {
            self.adapterPaths.push(objPath);
        } else if (interfaceName === Defs.Dbus.BLUEZ_DEVICE_INTERFACE) {
            self._addDevice(objPath);
        }
    }

    this.dbusService.getInterface(
        Defs.Dbus.BLUEZ_ROOT_OBJ, Defs.Dbus.BLUEZ_OBJ_MANAGER_INTERFACE, function(err, obj) {
        if (err) {
            return cb(err);
        }

        self.objMng = obj;

        //Listeners for the signals.
        self.objMng.on('InterfacesAdded', self._handleInterfaceAdded.bind(self));
        self.objMng.on('InterfacesRemoved', self._handleInterfaceRemoved.bind(self));

        self.objMng.GetManagedObjects(function(err, objs) {
            if (err) {
                return cb(err);
            }

            // console.log("ManagedObjs %j", objs);

            for (var i = 0; i < objs.length; i++) {
                var currentObj = objs[i];
                var path = currentObj[0];
                var interfacesAndProps = currentObj[1];

                for (var j = 0; j < interfacesAndProps.length; j++) {
                    crawlManagedObject(path, interfacesAndProps[j]);
                }
            }
            cb();
        });
    });
};

BluezManager.prototype.createBleServiceObjects = function createBleServiceObjects(bleServices) {
    var self = this;
    bleServices.forEach(function(service){
        self.sysbus.exportInterface(service, service.getPath(), ObjectManagerIface);
        self.sysbus.exportInterface(service, service.getPath(), ServiceIface);

        service.characteristics.forEach(function(char){
            self.sysbus.exportInterface(char, char.getPath(service.getPath()), CharIface);
            //TODO not sure if this is really needed yet.
            self.sysbus.exportInterface(char, char.getPath(service.getPath()), PropIface);

            char.descriptors.forEach(function(desc){
                self.sysbus.exportInterface(
                    desc, desc.getPath(char.getPath(service.getPath())), DescIface);
            });
        });
    });
};

BluezManager.prototype.registerBleServices = function registerBleServices(bleServices, cb) {
    function registerService(gattManager, service, cb) {
        gattManager.RegisterService(service.getPath(), {}, function(err) {
            debug('RegisterService cb', err);
            return cb(err);
      });
    }

    var self = this;
    self.createBleServiceObjects(bleServices);

    this.dbusService.getInterface(
        self._getAdapterPath(), Defs.Dbus.BLUEZ_GATT_MANAGER_INTERFACE, function(err, gattManager) {
        if (err) {
            throw err;
        }

        async.each(bleServices, registerService.bind(self, gattManager), function(err) {
            if (err) {
                return cb(err);
            }
            //concat in place
            self.services.push.apply(self.services, bleServices);
            cb();

        });
    });
};

module.exports = {
    BluezManager: BluezManager
};
<commit_msg>Restucture init function so that it can be used separately<commit_after>'use strict';

var util = require('util');
var events = require('events');
var dbus = require('dbus-native');
var async = require('async');
var debug = require('debug')('bluez-mgr');

var exec = require('child_process').exec;

var Defs = require('./bluez-defs.js');
var Advertise = require('./advertise.js');
var Advertisement = Advertise.Advertisement;
var AdvertisementIface = Advertise.AdvertisementIface;

var ObjectManagerIface = {
    name: Defs.Dbus.BLUEZ_OBJ_MANAGER_INTERFACE,
    methods: {
      GetManagedObjects: ['', 'a{oa{sa{sv}}}']
    },
    signals: {
    },
    properties: {
    }
};

var PropIface = {
    name: Defs.Dbus.DBUS_PROP_IFACE,
    methods: {
      GetAll: ['s', 'a{sv}']
    },
    signals: {
      PropertiesChanged: ['sa{sv}as', 'interface', 'changed', 'invalidated']
    },
    properties: {
    }
};

var CharIface = {
    name: Defs.Dbus.GATT_CHRC_IFACE,
    methods: {
      ReadValue: ['', 'ay'],
      WriteValue: ['ay', ''],
      StartNotify: ['', ''],
      StopNotify: ['', '']
    },
    signals: {
    },
    properties: {
    }
};

var DescIface = {
    name: Defs.Dbus.GATT_DESC_IFACE,
    methods: {
      ReadValue: ['', 'ay']
    },
    signals: {
    },
    properties: {
    }
};

var ServiceIface = {
    name: Defs.Dbus.GATT_SERVICE_IFACE,
    methods: {
    },
    signals: {
    },
    properties: {
      UUID: 's',
      Primary: 'b'
    }
};

function parseProps(rawProps) {
    var parsed = {};
    rawProps.forEach(function(prop) {
        var propName = prop[0];
        //TODO prop[1][0] has the type info, do we need it?
        var propValue = prop[1][1][0];

        parsed[propName] = propValue;
    });
    return parsed;
}

function BluezManager(configOptions) {
    this.objMng = null;
    this.adapterPaths = [];
    this.devices = Object.create(null);
    this.config = configOptions || {};

    events.EventEmitter.call(this);
}

util.inherits(BluezManager, events.EventEmitter);

BluezManager.prototype._handleInterfaceAdded = function _handleInterfaceAdded(path, interfaces) {
    debug('InterfacesAdded on', path, interfaces);
};

BluezManager.prototype._handleInterfaceRemoved =
    function _handleInterfaceRemoved(path, interfaces) {
    //TODO handle removal of ble adapter!
    debug('InterfacesRemoved', path, interfaces);
};

BluezManager.prototype._getAdapterPath = function _getAdapterPath() {
    return this.adapterPaths[0];
};

BluezManager.prototype._addDevice = function _addDevice(devicePath, cb) {
    var self = this;
    cb = cb || function(){};
    this.dbusService.getInterface(devicePath, Defs.Dbus.DBUS_PROP_IFACE, function(err, obj) {
        if (err) {
          return cb(err);
        }
        self.devices[devicePath] = obj;
        obj.on('PropertiesChanged', function(path, rawProps) {
            var props = parseProps(rawProps);
            debug('Properties changed in device %j', props);

            //TODO can actually emit any prop change here. Needed?
            if ('Connected' in props) {
                self.emit('device-connect', devicePath, props.Connected);
            }
        });
    });
};

BluezManager.prototype._advertise = function _advertise(callback) {
    function legacyAdvertise(cb) {
        debug('Legacy Advertising');
        //TODO Bluez does not support advertising via Dbus api yet (not on kernels < 4.1 anyway)
        //So this is just a hack

        //Sets the advertising packet
        //2=length, 1=ad type flags,
        //5=GAP_ADTYPE_FLAGS_LIMITED(1) | GAP_ADTYPE_FLAGS_BREDR_NOT_SUPPORTED(4)
        //(No classic only ble)
        //TODO assumes hci0 is the adapter
        exec('hcitool -i hci0 cmd 0x08 0x0008 3 02 01 05' +
            '&& hciconfig hci0 leadv', function (error, stdout, stderr) {
            debug('hciconfiguration error', error, 'stdout', stdout, 'stderr', stderr);
            cb(error);
        });
    }

    var cb = callback || function(){};
    var self = this;

    if (this.config.legacyAdvertising) {
        legacyAdvertise(cb);
        self.on('device-connect', function(path, isConnected) {
            if (!isConnected) {
                legacyAdvertise(cb);
            }
        });
    } else {
        self.sysbus.exportInterface(
            self.advertisement, self.advertisement.getPath(), AdvertisementIface);
        self.sysbus.exportInterface(
            self.advertisement, self.advertisement.getPath(), PropIface);

        self.dbusService.getInterface(
            self._getAdapterPath(),
            Defs.Dbus.LE_ADVERTISING_MANAGER_IFACE,
            function (err, adManager) {

                adManager.RegisterAdvertisement(
                    self.advertisement.getPath(),
                    {},
                    function(err, data) {
                        cb(err, data);
                    });
            }
        );
    }
};

BluezManager.prototype._handleDeviceConn = function _handleDeviceConn(devicePath, isConnected) {
  if (!isConnected) {
      //TODO this is not the best approach now since we do not really know if the
      //disconnected device was a client to these services but bluez does not offer
      //a way to know that, i.e. device was a client of these services or it was a server.
      this.services.forEach(function(service) {
          service.onDisconnect();
      });
  }
};

BluezManager.prototype.init = function init(crawlHandler, cb) {
    var self = this;

    this.sysbus = dbus.systemBus();
    this.dbusService = this.sysbus.getService(Defs.Dbus.BLUEZ_DBUS_SERVICE_NAME);

    this.sysbus.connection.on('error', function (err) {
        debug('Dbus error', err);
        throw err;
    });

    this.sysbus.connection.on('end', function () {
        debug('Dbus end');
    });

    self._crawl(crawlHandler, function(err) {
        return cb(err);
    });
};

BluezManager.prototype._handleCrawledObject = function _handleCrawledObject(objPath, current) {
    var interfaceName = current[0];
    if (interfaceName === Defs.Dbus.BLUEZ_ADAPTER_INTERFACE) {
        this.adapterPaths.push(objPath);
    } else if (interfaceName === Defs.Dbus.BLUEZ_DEVICE_INTERFACE) {
        this._addDevice(objPath);
    }
};

BluezManager.prototype.start = function start(options, cb) {
    var self = this;
    this.services = options.services || [];
    this.advertisement = options.advertisement ||
                            new Advertisement('advertisement', 'peripheral', {
                                    service_uuids: ['180D'],
                                    manufacturer_data: [0xffff, [0x00, 0x01, 0x02, 0x03, 0x04]],
                                    service_data: ['9999', [0x00, 0x01, 0x02, 0x03, 0x04]]});
    async.series([
        self.init.bind(self, self._handleCrawledObject.bind(self)),
        function(cb) {
            if (self.adapterPaths.length === 0) {
                return cb(new Error('No Adapter Found!'));
            }
            return cb();
        },
        self._advertise.bind(self),
        self.registerBleServices.bind(self, self.services),
        function(cb) {
            //Listeners for the signals.
            self.on('device-connect', self._handleDeviceConn.bind(self));
            self.objMng.on('InterfacesAdded', self._handleInterfaceAdded.bind(self));
            self.objMng.on('InterfacesRemoved', self._handleInterfaceRemoved.bind(self));
            cb(null);
        }
    ], cb);

};

BluezManager.prototype.close = function close(cb) {
    var self = this;
    // It seems like services are unregistered automatically
    //so just unregistering the advertisement here
    self.dbusService.getInterface(
        self._getAdapterPath(),
        Defs.Dbus.LE_ADVERTISING_MANAGER_IFACE,
        function (err, adManager) {
            adManager.UnregisterAdvertisement(self.advertisement.getPath(), function(err) {
                cb(err);
            });
        });
};

BluezManager.prototype._crawl = function _crawl(crawlHandler, cb) {
    var self = this;

    this.dbusService.getInterface(
        Defs.Dbus.BLUEZ_ROOT_OBJ, Defs.Dbus.BLUEZ_OBJ_MANAGER_INTERFACE, function(err, obj) {
        if (err) {
            return cb(err);
        }

        self.objMng = obj;

        self.objMng.GetManagedObjects(function(err, objs) {
            if (err) {
                return cb(err);
            }

            for (var i = 0; i < objs.length; i++) {
                var currentObj = objs[i];
                var path = currentObj[0];
                var interfacesAndProps = currentObj[1];

                for (var j = 0; j < interfacesAndProps.length; j++) {
                    crawlHandler(path, interfacesAndProps[j]);
                }
            }
            cb();
        });
    });
};

BluezManager.prototype.createBleServiceObjects = function createBleServiceObjects(bleServices) {
    var self = this;
    bleServices.forEach(function(service){
        self.sysbus.exportInterface(service, service.getPath(), ObjectManagerIface);
        self.sysbus.exportInterface(service, service.getPath(), ServiceIface);

        service.characteristics.forEach(function(char){
            self.sysbus.exportInterface(char, char.getPath(service.getPath()), CharIface);
            //TODO not sure if this is really needed yet.
            self.sysbus.exportInterface(char, char.getPath(service.getPath()), PropIface);

            char.descriptors.forEach(function(desc){
                self.sysbus.exportInterface(
                    desc, desc.getPath(char.getPath(service.getPath())), DescIface);
            });
        });
    });
};

BluezManager.prototype.registerBleServices = function registerBleServices(bleServices, cb) {
    function registerService(gattManager, service, cb) {
        gattManager.RegisterService(service.getPath(), {}, function(err) {
            debug('RegisterService cb', err);
            return cb(err);
      });
    }

    var self = this;
    self.createBleServiceObjects(bleServices);

    this.dbusService.getInterface(
        self._getAdapterPath(), Defs.Dbus.BLUEZ_GATT_MANAGER_INTERFACE, function(err, gattManager) {
        if (err) {
            throw err;
        }

        async.each(bleServices, registerService.bind(self, gattManager), function(err) {
            if (err) {
                return cb(err);
            }
            //concat in place
            self.services.push.apply(self.services, bleServices);
            cb();

        });
    });
};

module.exports = {
    BluezManager: BluezManager
};
<|endoftext|>


<commit_before>'use babel';

import { BufferedProcess, File } from 'atom';
import tempy from 'tempy';

function toolEnv() {
  return Object.assign(
    {},
    process.env,
    {PATH: atom.config.get('casefile.toolPath')}
  );
}

export function openBookmark({file: filePath, line, markText: text, peg: gitPeg}) {
  atom.workspace.open(filePath, {initialLine: line - 1}).then((editor) => {
    // Look for *text* around the line the cursor is now on
    const rowHasText = (i) => {
      const lineText = editor.lineTextForBufferRow(i);
      return lineText && lineText.includes(text);
    };

    const findAndSelectTextInRow = (i) => {
      if (rowHasText(i - 1)) {
        editor.setCursorBufferPosition(
          [i - 1, editor.lineTextForBufferRow(i - 1).indexOf(text)]
        );
        return true;
      }
      return false;
    }

    const attemptMarkLocationWithoutTracking = () => {
      if (findAndSelectTextInRow(line)) {
        return;
      }
      for (let i = 1; i <= 10; ++i) {
        if (findAndSelectTextInRow(line + i) || findAndSelectTextInRow(line - i)) {
          return;
        }
      }
    }

    if (gitPeg) {
      computeCurrentLineRange(filePath, gitPeg).then(function({start, prime, end}) {
        if (findAndSelectTextInRow(prime)) {
          return;
        }
        const iLimit = Math.max(prime - start - 1, end - prime);
        for (let i = 1; i < iLimit; ++i) {
          if (start <= prime - i && findAndSelectTextInRow(prime - i)) {
            return;
          } else if (prime + i < end && findAndSelectTextInRow(prime + i)) {
            return;
          }
        }
      }).catch(function() {
        attemptMarkLocationWithoutTracking();
      });
      return;
    }

    attemptMarkLocationWithoutTracking();
  });
}

const hunkMapping = /^@@\s*-?(\d+)(?:,(\d+))?\s+\+?(\d+)(?:,(\d+))?/;

// Return a Promise for {commit, hunks}, where each of hunks is an object
// with {currentStart, currentEnd, baseStart, baseEnd}.  Start/End pairs are
// like C++ iterators, half-closed at Start.  "Current" refers to the working
// tree version of the file, where "base" refers to the committed version at
// the given "commit" or HEAD (if unspecified).
function computeGitPeggingInfo(filePath, {commit=null}={}) {
  const target = new File(filePath);

  const promiseOfCommit = commit ? Promise.resolve({commit}) : readGitHeadCommit(filePath);

  var promiseOfCurrentContentFile = Promise.resolve(filePath);
  const currentContentPane = atom.workspace.paneForURI(filePath);
  if (currentContentPane) {
    const editor = currentContentPane.itemForURI(filePath);
    if (editor && editor.isModified()) {
      const currentContentFile = tempy.file();
      promiseOfCurrentContentFile = new File(currentContentFile).write(editor.getText()).then(function() {
        return currentContentFile;
      });
    }
  }

  const promiseOfBaseContentFile = new Promise(function(resolve, reject) {
    const baseContentFile = tempy.file();
    var baseContent = "";
    new BufferedProcess({
      command: 'git',
      args: ['show', (commit || 'HEAD') + ':./' + target.getBaseName()],
      stdout: function(data) {
        baseContent = baseContent + data;
      },
      stderr: function(output) {
        console.log(output);
      },
      options: {
        cwd: target.getParent().getPath(),
        env: toolPath()
      },
      exit: function(code) {
        if (!code) {
          resolve(
            new File(baseContentFile)
            .write(baseContent)
            .then(function() {
              return baseContentFile;
            })
          );
        } else {
          reject("Unable to read base version of file");
        }
      }
    }).onWillThrowError((errObj) => {
      reject("Unable to run git");
      console.log(errObj.error);
      errObj.handle();
    })
  });

  return (
    Promise.all([
      promiseOfCommit,
      promiseOfBaseContentFile,
      promiseOfCurrentContentFile
    ]).then(function([commit, baseContentFile, currentContentFile]) {
      return new Promise(function (resolve, reject) {
        const hunks = [];
        new BufferedProcess({
          command: 'diff',
          args: ['-U0', baseContentFile, currentContentFile],
          stdout: function(data) {
            for (const line of data.split("\n").slice(0, -1)) {
              const parts = line.match(hunkMapping)
              if (parts) {
                const newHunk = {
                  baseStart: parseInt(parts[1]),
                  baseEnd: parseInt(parts[1]) + parseInt(parts[2] || "1"),
                  currentStart: parseInt(parts[3]),
                  currentEnd: parseInt(parts[3]) + parseInt(parts[4] || "1")
                };
                if (parts[2] == "0") {
                  newHunk.baseStart = newHunk.baseEnd = newHunk.baseStart + 1;
                }
                if (parts[4] == "0") {
                  newHunk.currentStart = newHunk.currentEnd = newHunk.currentStart + 1;
                }
                hunks.push(newHunk);
              }
            }
          },
          stderr: function(output) {
            console.log(output);
          },
          options: {
            env: toolPath()
          },
          exit: function(code) {
            if (code == 0 || code == 1) {
              resolve({commit, hunks});
            } else {
              reject("Unable to diff file");
            }
          }
        }).onWillThrowError((errObj) => {
          reject("Unable to run diff");
          console.log(errObj.error);
          errObj.handle();
        });
      });
    })
  );
}

export function readGitHeadCommit(filePath) {
  const target = new File(filePath);
  return new Promise(function (resolve, reject) {
    var commit = null;
    new BufferedProcess({
      command: 'git',
      args: ['rev-parse', 'HEAD'],
      stdout: function(data) {
        commit = data.trim();
      },
      stderr: function(output) {
        console.log(output);
      },
      options: {
        cwd: target.getParent().getPath(),
        env: toolPath()
      },
      exit: function(code) {
        if (!code) {
          resolve({commit});
        } else {
          reject("Unable to resolve current Git HEAD commit");
        }
      }
    }).onWillThrowError((errObj) => {
      reject("Unable to run git");
      console.log(errObj.error);
      errObj.handle();
    });
  });
}

// Return a Promise for {line} and possibly {commit}.  The "line" returned
// indexes the committed version of the file (at the given commit or HEAD if
// unspecified).  If currentLine lies within a modified hunk, it is mapped to
// the committed version by linear interpolation within the modified hunk.
export function computePegLine(filePath, currentLine, {commit=null}={}) {
  return computeGitPeggingInfo(filePath, {commit}).then(function({commit, hunks}) {
    var currentOffset = 0;
    for (let hunk of hunks) {
      if (currentLine < hunk.currentStart) {
        return {line: currentLine - currentOffset, commit};
      } else if (hunk.currentStart <= currentLine && currentLine < hunk.currentEnd) {
        return {
          line: Math.floor(
            (currentLine - hunk.currentStart) / (hunk.currentEnd - hunk.currentStart) * (hunk.baseEnd - hunk.baseStart)
          ) + hunk.baseStart,
          commit
        };
      }
      currentOffset = hunk.currentEnd - hunk.baseEnd;
    }
    return {line: currentLine - currentOffset, commit};
  }).catch(function() {
    return {line: currentLine};
  });
}

// Return a Promise for {start, prime, end}, where "start" and "end" are
// a half-closed interval of line numbers encompassing the realistic range of
// line numbers in the working copy that could correspond to the given line
// of the committed file.  "prime" is a "best guess" line number in
// [start, end) expected to correspond to the committed line based on linear
// interpolation within the modified hunk.
export function computeCurrentLineRange(filePath, {line, commit}) {
  if (!commit) {
    return Promise.resolve({start: line, prime: line, end: line + 1});
  }

  return computeGitPeggingInfo(filePath, {commit}).then(function({hunks}) {
    var currentOffset = 0;
    for (let hunk of hunks) {
      if (line < hunk.baseStart) {
        return {start: line + currentOffset, prime: line + currentOffset, end: line + currentOffset + 1};
      } else if (hunk.baseStart <= line && line < hunk.baseEnd) {
        return {
          start: hunk.currentStart,
          prime: hunk.currentStart + Math.floor(
            (line - hunk.baseStart) / (hunk.baseEnd - hunk.baseStart) * (hunk.currentEnd - hunk.currentStart)
          ),
          end: hunk.currentEnd
        };
      } else if (hunk.baseStart == line) {
        return {
          start: hunk.currentStart,
          prime: Math.floor((hunk.currentStart + hunk.currentEnd) / 2),
          end: hunk.currentEnd
        }
      }
      currentOffset = hunk.currentEnd - hunk.baseEnd;
    }
    return {start: line + currentOffset, prime: line + currentOffset, end: line + currentOffset + 1};
  }).catch(function() {
    return {start: line, prime: line, end: line + 1};
  });
}
<commit_msg>Fix bugs in bookmark commit computation<commit_after>'use babel';

import { BufferedProcess, File } from 'atom';
import tempy from 'tempy';

function toolEnv() {
  return Object.assign(
    {},
    process.env,
    {PATH: atom.config.get('casefile.toolPath')}
  );
}

export function openBookmark({file: filePath, line, markText: text, peg: gitPeg}) {
  atom.workspace.open(filePath, {initialLine: line - 1}).then((editor) => {
    // Look for *text* around the line the cursor is now on
    const rowHasText = (i) => {
      const lineText = editor.lineTextForBufferRow(i);
      return lineText && lineText.includes(text);
    };

    const findAndSelectTextInRow = (i) => {
      if (rowHasText(i - 1)) {
        editor.setCursorBufferPosition(
          [i - 1, editor.lineTextForBufferRow(i - 1).indexOf(text)]
        );
        return true;
      }
      return false;
    }

    const attemptMarkLocationWithoutTracking = () => {
      if (findAndSelectTextInRow(line)) {
        return;
      }
      for (let i = 1; i <= 10; ++i) {
        if (findAndSelectTextInRow(line + i) || findAndSelectTextInRow(line - i)) {
          return;
        }
      }
    }

    if (gitPeg) {
      computeCurrentLineRange(filePath, gitPeg).then(function({start, prime, end}) {
        if (findAndSelectTextInRow(prime)) {
          return;
        }
        const iLimit = Math.max(prime - start - 1, end - prime);
        for (let i = 1; i < iLimit; ++i) {
          if (start <= prime - i && findAndSelectTextInRow(prime - i)) {
            return;
          } else if (prime + i < end && findAndSelectTextInRow(prime + i)) {
            return;
          }
        }
      }).catch(function() {
        attemptMarkLocationWithoutTracking();
      });
      return;
    }

    attemptMarkLocationWithoutTracking();
  });
}

const hunkMapping = /^@@\s*-?(\d+)(?:,(\d+))?\s+\+?(\d+)(?:,(\d+))?/;

// Return a Promise for {commit, hunks}, where each of hunks is an object
// with {currentStart, currentEnd, baseStart, baseEnd}.  Start/End pairs are
// like C++ iterators, half-closed at Start.  "Current" refers to the working
// tree version of the file, where "base" refers to the committed version at
// the given "commit" or HEAD (if unspecified).
function computeGitPeggingInfo(filePath, {commit=null}={}) {
  const target = new File(filePath);

  const promiseOfCommit = commit ? Promise.resolve({commit}) : readGitHeadCommit(filePath);

  var promiseOfCurrentContentFile = Promise.resolve(filePath);
  const currentContentPane = atom.workspace.paneForURI(filePath);
  if (currentContentPane) {
    const editor = currentContentPane.itemForURI(filePath);
    if (editor && editor.isModified()) {
      const currentContentFile = tempy.file();
      promiseOfCurrentContentFile = new File(currentContentFile).write(editor.getText()).then(function() {
        return currentContentFile;
      });
    }
  }

  const promiseOfBaseContentFile = new Promise(function(resolve, reject) {
    const baseContentFile = tempy.file();
    var baseContent = "";
    new BufferedProcess({
      command: 'git',
      args: ['show', (commit || 'HEAD') + ':./' + target.getBaseName()],
      stdout: function(data) {
        baseContent = baseContent + data;
      },
      stderr: function(output) {
        console.log(output);
      },
      options: {
        cwd: target.getParent().getPath(),
        env: toolEnv()
      },
      exit: function(code) {
        if (!code) {
          resolve(
            new File(baseContentFile)
            .write(baseContent)
            .then(function() {
              return baseContentFile;
            })
          );
        } else {
          reject("Unable to read base version of file");
        }
      }
    }).onWillThrowError((errObj) => {
      reject("Unable to run git");
      console.log(errObj.error);
      errObj.handle();
    })
  });

  return (
    Promise.all([
      promiseOfCommit,
      promiseOfBaseContentFile,
      promiseOfCurrentContentFile
    ]).then(function([commit, baseContentFile, currentContentFile]) {
      return new Promise(function (resolve, reject) {
        const hunks = [];
        new BufferedProcess({
          command: 'diff',
          args: ['-U0', baseContentFile, currentContentFile],
          stdout: function(data) {
            for (const line of data.split("\n").slice(0, -1)) {
              const parts = line.match(hunkMapping)
              if (parts) {
                const newHunk = {
                  baseStart: parseInt(parts[1]),
                  baseEnd: parseInt(parts[1]) + parseInt(parts[2] || "1"),
                  currentStart: parseInt(parts[3]),
                  currentEnd: parseInt(parts[3]) + parseInt(parts[4] || "1")
                };
                if (parts[2] == "0") {
                  newHunk.baseStart = newHunk.baseEnd = newHunk.baseStart + 1;
                }
                if (parts[4] == "0") {
                  newHunk.currentStart = newHunk.currentEnd = newHunk.currentStart + 1;
                }
                hunks.push(newHunk);
              }
            }
          },
          stderr: function(output) {
            console.log(output);
          },
          options: {
            env: toolEnv()
          },
          exit: function(code) {
            if (code == 0 || code == 1) {
              resolve({commit, hunks});
            } else {
              reject("Unable to diff file");
            }
          }
        }).onWillThrowError((errObj) => {
          reject("Unable to run diff");
          console.log(errObj.error);
          errObj.handle();
        });
      });
    })
  );
}

export function readGitHeadCommit(filePath) {
  const target = new File(filePath);
  return new Promise(function (resolve, reject) {
    var commit = null;
    new BufferedProcess({
      command: 'git',
      args: ['rev-parse', 'HEAD'],
      stdout: function(data) {
        commit = data.trim();
      },
      stderr: function(output) {
        console.log(output);
      },
      options: {
        cwd: target.getParent().getPath(),
        env: toolEnv()
      },
      exit: function(code) {
        if (!code) {
          resolve(commit);
        } else {
          reject("Unable to resolve current Git HEAD commit");
        }
      }
    }).onWillThrowError((errObj) => {
      reject("Unable to run git");
      console.log(errObj.error);
      errObj.handle();
    });
  });
}

// Return a Promise for {line} and possibly {commit}.  The "line" returned
// indexes the committed version of the file (at the given commit or HEAD if
// unspecified).  If currentLine lies within a modified hunk, it is mapped to
// the committed version by linear interpolation within the modified hunk.
export function computePegLine(filePath, currentLine, {commit=null}={}) {
  return computeGitPeggingInfo(filePath, {commit}).then(function({commit, hunks}) {
    var currentOffset = 0;
    for (let hunk of hunks) {
      if (currentLine < hunk.currentStart) {
        return {line: currentLine - currentOffset, commit};
      } else if (hunk.currentStart <= currentLine && currentLine < hunk.currentEnd) {
        return {
          line: Math.floor(
            (currentLine - hunk.currentStart) / (hunk.currentEnd - hunk.currentStart) * (hunk.baseEnd - hunk.baseStart)
          ) + hunk.baseStart,
          commit
        };
      }
      currentOffset = hunk.currentEnd - hunk.baseEnd;
    }
    return {line: currentLine - currentOffset, commit};
  }).catch(function() {
    return {line: currentLine};
  });
}

// Return a Promise for {start, prime, end}, where "start" and "end" are
// a half-closed interval of line numbers encompassing the realistic range of
// line numbers in the working copy that could correspond to the given line
// of the committed file.  "prime" is a "best guess" line number in
// [start, end) expected to correspond to the committed line based on linear
// interpolation within the modified hunk.
export function computeCurrentLineRange(filePath, {line, commit}) {
  if (!commit) {
    return Promise.resolve({start: line, prime: line, end: line + 1});
  }

  return computeGitPeggingInfo(filePath, {commit}).then(function({hunks}) {
    var currentOffset = 0;
    for (let hunk of hunks) {
      if (line < hunk.baseStart) {
        return {start: line + currentOffset, prime: line + currentOffset, end: line + currentOffset + 1};
      } else if (hunk.baseStart <= line && line < hunk.baseEnd) {
        return {
          start: hunk.currentStart,
          prime: hunk.currentStart + Math.floor(
            (line - hunk.baseStart) / (hunk.baseEnd - hunk.baseStart) * (hunk.currentEnd - hunk.currentStart)
          ),
          end: hunk.currentEnd
        };
      } else if (hunk.baseStart == line) {
        return {
          start: hunk.currentStart,
          prime: Math.floor((hunk.currentStart + hunk.currentEnd) / 2),
          end: hunk.currentEnd
        }
      }
      currentOffset = hunk.currentEnd - hunk.baseEnd;
    }
    return {start: line + currentOffset, prime: line + currentOffset, end: line + currentOffset + 1};
  }).catch(function() {
    return {start: line, prime: line, end: line + 1};
  });
}
<|endoftext|>


<commit_before>
module.exports = exports = configure

/**
 * Module dependencies.
 */

var fs = require('graceful-fs')
  , path = require('path')
  , glob = require('glob')
  , log = require('npmlog')
  , osenv = require('osenv')
  , which = require('which')
  , semver = require('semver')
  , mkdirp = require('mkdirp')
  , exec = require('child_process').exec
  , spawn = require('child_process').spawn
  , win = process.platform == 'win32'
  , hasVCExpress = false
  , hasWin71SDK = false

exports.usage = 'Generates ' + (win ? 'MSVC project files' : 'a Makefile') + ' for the current module'

function configure (gyp, argv, callback) {

  var python = process.env.PYTHON || gyp.opts.python || 'python'
    , buildDir = path.resolve('build')
    , configPath
    , nodeDir

  if (win) {
    checkVCExpress(function () {
      if (hasVCExpress) {
        checkWin71SDK(function () {
          checkPython()
        })
      } else {
        checkPython()
      }
    })
  } else
    checkPython()

  // Make sure that Python is in the $PATH
  function checkPython () {
    log.verbose('check python', 'checking for Python executable "%s" in the PATH', python)
    which(python, function (err, execPath) {
      if (err) {
        if (win) {
          guessPython()
        } else {
          failNoPython()
        }
        return
      }
      log.verbose('`which` succeeded for `' + python + '`', execPath)
      checkPythonVersion()
    })
  }

  // Called on Windows when "python" isn't available in the current $PATH.
  // We're gonna glob C:\python2*
  function guessPython () {
    log.verbose('could not find "' + python + '". guessing location')
    var rootDir = process.env.SystemDrive || 'C:\\'
    if (rootDir[rootDir.length - 1] !== '\\') {
      rootDir += '\\'
    }
    var pythonPath = path.resolve(rootDir, 'Python27', 'python.exe')
    log.verbose('ensuring that file exists:', pythonPath)
    fs.stat(pythonPath, function (err, stat) {
      if (err) {
        if (err.code == 'ENOENT') {
          failNoPython()
        } else {
          callback(err)
        }
        return
      }
      python = pythonPath
      checkPythonVersion()
    })
  }

  function checkPythonVersion () {
    exec(python + ' --version', function (err, stdout, stderr) {
      if (err) {
        return callback(err)
      }
      log.verbose('check python version', '`%s --version` returned: %j', python, stderr)
      var version = stderr.trim().replace(/[^\d\.]+/g, '')
      var numDots = 0
      version.replace(/\./g, function () {
        numDots++
      })
      while (numDots < 2) {
        version += '.0'
        numDots++
      }
      log.verbose('check python version', 'using version %j to check', version)
      if (semver.gte(version, '2.5.0') && semver.lt(version, '3.0.0')) {
        getNodeDir()
      } else {
        failPythonVersion(version)
      }
    })
  }

  function failNoPython () {
    callback(new Error('Can\'t find Python executable "' + python
          + '", you can set the PYTHON env variable.'))
  }

  function failPythonVersion (badVersion) {
    callback(new Error('Python executable "' + python
          + '" is v' + badVersion + ', which is not supported by gyp.\n'
          + 'You can pass the --python switch to point to Python >= v2.5.0 & < 3.0.0.'))
  }

  function checkWin71SDK(cb) {
    spawn('reg', ['query', 'HKLM\\Software\\Microsoft\\Microsoft SDKs\\Windows\\v7.1', '/v', 'InstallationFolder'])
         .on('exit', function (code) {
           hasWin71SDK = (code === 0)
           cb()
         })
  }

  function checkVCExpress64(cb) {
    var cp = spawn('cmd', ['/C', '%WINDIR%\\SysWOW64\\reg', 'query', 'HKLM\\Software\\Microsoft\\VCExpress\\10.0\\Setup\\VC', '/v', 'ProductDir'])
    cp.on('exit', function (code) {
      hasVCExpress = (code === 0)
      cb()
    })
  }

  function checkVCExpress(cb) {
    spawn('reg', ['query', 'HKLM\\Software\\Microsoft\\VCExpress\\10.0\\Setup\\VC', '/v', 'ProductDir'])
         .on('exit', function (code) {
           if (code !== 0) {
             checkVCExpress64(cb)
           } else {
             cb()
           }
         })
  }

  function getNodeDir () {

    // 'python' should be set by now
    process.env.PYTHON = python

    if (gyp.opts.nodedir) {
      // --nodedir was specified. use that for the dev files
      nodeDir = gyp.opts.nodedir.replace(/^~/, osenv.home())

      log.verbose('get node dir', 'compiling against specified --nodedir dev files: %s', nodeDir)
      createBuildDir()

    } else {
      // if no --nodedir specified, ensure node dependencies are installed
      var version
      var versionStr

      if (gyp.opts.target) {
        // if --target was given, then determine a target version to compile for
        versionStr = gyp.opts.target
        log.verbose('get node dir', 'compiling against --target node version: %s', versionStr)
      } else {
        // if no --target was specified then use the current host node version
        versionStr = process.version
        log.verbose('get node dir', 'no --target version specified, falling back to host node version: %s', versionStr)
      }

      // make sure we have a valid version
      version = semver.parse(versionStr)
      if (!version) {
        return callback(new Error('Invalid version number: ' + versionStr))
      }

      // ensure that the target node version's dev files are installed
      gyp.opts.ensure = true
      gyp.commands.install([ versionStr ], function (err, version) {
        if (err) return callback(err)
        log.verbose('get node dir', 'target node version installed:', version)
        nodeDir = path.resolve(gyp.devDir, version)
        createBuildDir()
      })
    }
  }

  function createBuildDir () {
    log.verbose('build dir', 'attempting to create "build" dir: %s', buildDir)
    mkdirp(buildDir, function (err, isNew) {
      if (err) return callback(err)
      log.verbose('build dir', '"build" dir needed to be created?', isNew)
      createConfigFile()
    })
  }

  function createConfigFile (err) {
    if (err) return callback(err)

    var configFilename = 'config.gypi'
    configPath = path.resolve(buildDir, configFilename)

    log.verbose(configFilename, 'creating config file')

    var config = process.config || {}
      , defaults = config.target_defaults
      , variables = config.variables

    if (!defaults) {
      defaults = config.target_defaults = {}
    }
    if (!variables) {
      variables = config.variables = {}
    }
    if (!defaults.cflags) {
      defaults.cflags = []
    }
    if (!defaults.defines) {
      defaults.defines = []
    }
    if (!defaults.include_dirs) {
      defaults.include_dirs = []
    }
    if (!defaults.libraries) {
      defaults.libraries = []
    }

    // set the default_configuration prop
    if ('debug' in gyp.opts) {
      defaults.default_configuration = gyp.opts.debug ? 'Debug' : 'Release'
    }
    if (!defaults.default_configuration) {
      defaults.default_configuration = 'Release'
    }

    // set the target_arch variable
    variables.target_arch = gyp.opts.arch || process.arch || 'ia32'

    // set the toolset for 64-bit VCExpress users
    if (win && variables.target_arch === 'x64' && hasVCExpress && hasWin71SDK) {
      defaults.msbuild_toolset = 'Windows7.1SDK'
    }

    // set the node development directory
    variables.nodedir = nodeDir

    // don't copy dev libraries with nodedir option
    variables.copy_dev_lib = !gyp.opts.nodedir

    // loop through the rest of the opts and add the unknown ones as variables.
    // this allows for module-specific configure flags like:
    //
    //   $ node-gyp configure --shared-libxml2
    Object.keys(gyp.opts).forEach(function (opt) {
      if (opt === 'argv') return
      if (opt in gyp.configDefs) return
      variables[opt.replace(/-/g, '_')] = gyp.opts[opt]
    })

    // ensures that any boolean values from `process.config` get stringified
    function boolsToString (k, v) {
      if (typeof v === 'boolean')
        return String(v)
      return v
    }

    log.silly(configFilename, config)

    // now write out the config.gypi file to the build/ dir
    var prefix = '# Do not edit. File was generated by node-gyp\'s "configure" step'
      , json = JSON.stringify(config, boolsToString, 2)
    log.verbose(configFilename, 'writing out config file: %s', configPath)
    fs.writeFile(configPath, [prefix, json, ''].join('\n'), runGypAddon)
  }

  function runGypAddon (err) {
    if (err) return callback(err)

    // location of the `gyp_addon` python script for the target nodedir
    var gyp_addon = path.resolve(nodeDir, 'tools', 'gyp_addon')

    if (!~argv.indexOf('-f') && !~argv.indexOf('--format')) {
      if (win) {
        log.verbose('gyp_addon', 'gyp format was not specified; forcing "msvs"')
        // force the 'make' target for non-Windows
        argv.push('-f', 'msvs')
      } else {
        log.verbose('gyp_addon', 'gyp format was not specified; forcing "make"')
        // force the 'make' target for non-Windows
        argv.push('-f', 'make')
      }
    }

    function hasMsvsVersion () {
      return argv.some(function (arg) {
        return arg.indexOf('msvs_version') === 0
      })
    }

    if (win && !hasMsvsVersion()) {
      if ('msvs_version' in gyp.opts) {
        argv.push('-G', 'msvs_version=' + gyp.opts.msvs_version)
      } else {
        argv.push('-G', 'msvs_version=2010')
      }
    }

    // include the "config.gypi" file that was generated
    argv.unshift('-I' + configPath)

    // enforce use of the "binding.gyp" file
    argv.unshift('binding.gyp')

    // execute `gyp_addon` from the current target nodedir
    argv.unshift(gyp_addon)

    var cp = gyp.spawn(python, argv)
    cp.on('exit', onCpExit)
  }

  /**
   * Called when the `gyp_addon` child process exits.
   */

  function onCpExit (code, signal) {
    if (code !== 0) {
      callback(new Error('`gyp_addon` failed with exit code: ' + code))
    } else {
      // we're done
      callback()
    }
  }

}
<commit_msg>configure: a little tidying up<commit_after>
module.exports = exports = configure

/**
 * Module dependencies.
 */

var fs = require('graceful-fs')
  , path = require('path')
  , glob = require('glob')
  , log = require('npmlog')
  , osenv = require('osenv')
  , which = require('which')
  , semver = require('semver')
  , mkdirp = require('mkdirp')
  , cp = require('child_process')
  , exec = cp.exec
  , spawn = cp.spawn
  , win = process.platform == 'win32'

exports.usage = 'Generates ' + (win ? 'MSVC project files' : 'a Makefile') + ' for the current module'

function configure (gyp, argv, callback) {

  var python = process.env.PYTHON || gyp.opts.python || 'python'
    , buildDir = path.resolve('build')
    , hasVCExpress = false
    , hasWin71SDK = false
    , configPath
    , nodeDir

  if (win) {
    checkVCExpress(function () {
      if (hasVCExpress) {
        checkWin71SDK(function () {
          checkPython()
        })
      } else {
        checkPython()
      }
    })
  } else
    checkPython()

  // Make sure that Python is in the $PATH
  function checkPython () {
    log.verbose('check python', 'checking for Python executable "%s" in the PATH', python)
    which(python, function (err, execPath) {
      if (err) {
        if (win) {
          guessPython()
        } else {
          failNoPython()
        }
        return
      }
      log.verbose('`which` succeeded for `' + python + '`', execPath)
      checkPythonVersion()
    })
  }

  // Called on Windows when "python" isn't available in the current $PATH.
  // We're gonna glob C:\python2*
  function guessPython () {
    log.verbose('could not find "' + python + '". guessing location')
    var rootDir = process.env.SystemDrive || 'C:\\'
    if (rootDir[rootDir.length - 1] !== '\\') {
      rootDir += '\\'
    }
    var pythonPath = path.resolve(rootDir, 'Python27', 'python.exe')
    log.verbose('ensuring that file exists:', pythonPath)
    fs.stat(pythonPath, function (err, stat) {
      if (err) {
        if (err.code == 'ENOENT') {
          failNoPython()
        } else {
          callback(err)
        }
        return
      }
      python = pythonPath
      checkPythonVersion()
    })
  }

  function checkPythonVersion () {
    exec(python + ' --version', function (err, stdout, stderr) {
      if (err) {
        return callback(err)
      }
      log.verbose('check python version', '`%s --version` returned: %j', python, stderr)
      var version = stderr.trim().replace(/[^\d\.]+/g, '')
      var numDots = 0
      version.replace(/\./g, function () {
        numDots++
      })
      while (numDots < 2) {
        version += '.0'
        numDots++
      }
      log.verbose('check python version', 'using version %j to check', version)
      if (semver.gte(version, '2.5.0') && semver.lt(version, '3.0.0')) {
        getNodeDir()
      } else {
        failPythonVersion(version)
      }
    })
  }

  function failNoPython () {
    callback(new Error('Can\'t find Python executable "' + python
          + '", you can set the PYTHON env variable.'))
  }

  function failPythonVersion (badVersion) {
    callback(new Error('Python executable "' + python
          + '" is v' + badVersion + ', which is not supported by gyp.\n'
          + 'You can pass the --python switch to point to Python >= v2.5.0 & < 3.0.0.'))
  }

  function checkWin71SDK(cb) {
    spawn('reg', ['query', 'HKLM\\Software\\Microsoft\\Microsoft SDKs\\Windows\\v7.1', '/v', 'InstallationFolder'])
         .on('exit', function (code) {
           hasWin71SDK = (code === 0)
           cb()
         })
  }

  function checkVCExpress64(cb) {
    var cp = spawn('cmd', ['/C', '%WINDIR%\\SysWOW64\\reg', 'query', 'HKLM\\Software\\Microsoft\\VCExpress\\10.0\\Setup\\VC', '/v', 'ProductDir'])
    cp.on('exit', function (code) {
      hasVCExpress = (code === 0)
      cb()
    })
  }

  function checkVCExpress(cb) {
    spawn('reg', ['query', 'HKLM\\Software\\Microsoft\\VCExpress\\10.0\\Setup\\VC', '/v', 'ProductDir'])
         .on('exit', function (code) {
           if (code !== 0) {
             checkVCExpress64(cb)
           } else {
             cb()
           }
         })
  }

  function getNodeDir () {

    // 'python' should be set by now
    process.env.PYTHON = python

    if (gyp.opts.nodedir) {
      // --nodedir was specified. use that for the dev files
      nodeDir = gyp.opts.nodedir.replace(/^~/, osenv.home())

      log.verbose('get node dir', 'compiling against specified --nodedir dev files: %s', nodeDir)
      createBuildDir()

    } else {
      // if no --nodedir specified, ensure node dependencies are installed
      var version
      var versionStr

      if (gyp.opts.target) {
        // if --target was given, then determine a target version to compile for
        versionStr = gyp.opts.target
        log.verbose('get node dir', 'compiling against --target node version: %s', versionStr)
      } else {
        // if no --target was specified then use the current host node version
        versionStr = process.version
        log.verbose('get node dir', 'no --target version specified, falling back to host node version: %s', versionStr)
      }

      // make sure we have a valid version
      version = semver.parse(versionStr)
      if (!version) {
        return callback(new Error('Invalid version number: ' + versionStr))
      }

      // ensure that the target node version's dev files are installed
      gyp.opts.ensure = true
      gyp.commands.install([ versionStr ], function (err, version) {
        if (err) return callback(err)
        log.verbose('get node dir', 'target node version installed:', version)
        nodeDir = path.resolve(gyp.devDir, version)
        createBuildDir()
      })
    }
  }

  function createBuildDir () {
    log.verbose('build dir', 'attempting to create "build" dir: %s', buildDir)
    mkdirp(buildDir, function (err, isNew) {
      if (err) return callback(err)
      log.verbose('build dir', '"build" dir needed to be created?', isNew)
      createConfigFile()
    })
  }

  function createConfigFile (err) {
    if (err) return callback(err)

    var configFilename = 'config.gypi'
    configPath = path.resolve(buildDir, configFilename)

    log.verbose(configFilename, 'creating config file')

    var config = process.config || {}
      , defaults = config.target_defaults
      , variables = config.variables

    if (!defaults) {
      defaults = config.target_defaults = {}
    }
    if (!variables) {
      variables = config.variables = {}
    }
    if (!defaults.cflags) {
      defaults.cflags = []
    }
    if (!defaults.defines) {
      defaults.defines = []
    }
    if (!defaults.include_dirs) {
      defaults.include_dirs = []
    }
    if (!defaults.libraries) {
      defaults.libraries = []
    }

    // set the default_configuration prop
    if ('debug' in gyp.opts) {
      defaults.default_configuration = gyp.opts.debug ? 'Debug' : 'Release'
    }
    if (!defaults.default_configuration) {
      defaults.default_configuration = 'Release'
    }

    // set the target_arch variable
    variables.target_arch = gyp.opts.arch || process.arch || 'ia32'

    // set the toolset for 64-bit VCExpress users
    if (win && variables.target_arch === 'x64' && hasVCExpress && hasWin71SDK) {
      defaults.msbuild_toolset = 'Windows7.1SDK'
    }

    // set the node development directory
    variables.nodedir = nodeDir

    // don't copy dev libraries with nodedir option
    variables.copy_dev_lib = !gyp.opts.nodedir

    // loop through the rest of the opts and add the unknown ones as variables.
    // this allows for module-specific configure flags like:
    //
    //   $ node-gyp configure --shared-libxml2
    Object.keys(gyp.opts).forEach(function (opt) {
      if (opt === 'argv') return
      if (opt in gyp.configDefs) return
      variables[opt.replace(/-/g, '_')] = gyp.opts[opt]
    })

    // ensures that any boolean values from `process.config` get stringified
    function boolsToString (k, v) {
      if (typeof v === 'boolean')
        return String(v)
      return v
    }

    log.silly(configFilename, config)

    // now write out the config.gypi file to the build/ dir
    var prefix = '# Do not edit. File was generated by node-gyp\'s "configure" step'
      , json = JSON.stringify(config, boolsToString, 2)
    log.verbose(configFilename, 'writing out config file: %s', configPath)
    fs.writeFile(configPath, [prefix, json, ''].join('\n'), runGypAddon)
  }

  function runGypAddon (err) {
    if (err) return callback(err)

    // location of the `gyp_addon` python script for the target nodedir
    var gyp_addon = path.resolve(nodeDir, 'tools', 'gyp_addon')

    if (!~argv.indexOf('-f') && !~argv.indexOf('--format')) {
      if (win) {
        log.verbose('gyp_addon', 'gyp format was not specified; forcing "msvs"')
        // force the 'make' target for non-Windows
        argv.push('-f', 'msvs')
      } else {
        log.verbose('gyp_addon', 'gyp format was not specified; forcing "make"')
        // force the 'make' target for non-Windows
        argv.push('-f', 'make')
      }
    }

    function hasMsvsVersion () {
      return argv.some(function (arg) {
        return arg.indexOf('msvs_version') === 0
      })
    }

    if (win && !hasMsvsVersion()) {
      if ('msvs_version' in gyp.opts) {
        argv.push('-G', 'msvs_version=' + gyp.opts.msvs_version)
      } else {
        argv.push('-G', 'msvs_version=2010')
      }
    }

    // include the "config.gypi" file that was generated
    argv.unshift('-I' + configPath)

    // enforce use of the "binding.gyp" file
    argv.unshift('binding.gyp')

    // execute `gyp_addon` from the current target nodedir
    argv.unshift(gyp_addon)

    var cp = gyp.spawn(python, argv)
    cp.on('exit', onCpExit)
  }

  /**
   * Called when the `gyp_addon` child process exits.
   */

  function onCpExit (code, signal) {
    if (code !== 0) {
      callback(new Error('`gyp_addon` failed with exit code: ' + code))
    } else {
      // we're done
      callback()
    }
  }

}
<|endoftext|>


<commit_before>var rp = require('./request-promise'),
    config = require('../config'),
    _ = require('underscore'),
    Q = require('q'),
    formatter = require('./utils/formatter');

function Dashboard (slug) {
  this.options = {
    json: true,
    slug: slug
  };
}

Dashboard.prototype.getConfig = function () {
  var options = _.extend(this.options, {
    url: config.stagecraft + 'public/dashboards?slug=' + this.options.slug
  });

  return rp(options);
};

Dashboard.prototype.getDashboardMetrics = function () {
  var moduleList = [];
  var supportedModules = ['kpi', 'single_timeseries'];
  return this.getConfig()
    .then(_.bind(function (dashboard) {
      this.dashboard = dashboard;
      _.each(dashboard.modules, function (module) {
        if (_.contains(supportedModules, module['module-type'])) {
          moduleList.push(this.getModule(module));
        }
      }, this);

      return Q.allSettled(moduleList);
    }, this))
      .then(_.bind(function (results) {
        var dashboardAndMetrics = _.extend({}, this.dashboard);
        dashboardAndMetrics.modules = [];

        _.each(results, function (result) {
          if (result.state === 'fulfilled') {
            dashboardAndMetrics.modules.push(result.value);
          }
        }, this);

        return dashboardAndMetrics;
      }, this));
};

Dashboard.prototype.getModule = function (module) {
  var dataSource = module['data-source'];
  var options = _.extend(this.options, {
    url: config.backdrop + 'data/' + dataSource['data-group'] + '/' + dataSource['data-type'],
    qs: _.extend(dataSource['query-params'], {
      flatten: true
    })
  });

  return rp(options)
    .then(function (data) {
      module.data = data.data;
      module.axes = module.axes || getModuleAxes(module);
      module = formatKeys(module);
      module.tabularData = tabularData(module);
      return module;
    });
};

function formatKeys (module) {
  var dataList = module.data;
  var formating = module.format;
  var valueAttr = module['value-attribute'];

  for (var x = 0; x < dataList.length; x++) {
    var dataItem = dataList[x];
    var currentValue = dataItem[valueAttr];
    var previousItem = dataList[x + 1] || undefined;
    var previousValue = previousItem ? previousItem[valueAttr] : undefined;
    var isNumberOrCurrency = module.format &&
      (module.format.type === 'number' || module.format.type === 'currency');

    // formatted_change_from_previous
    if (previousValue && isNumberOrCurrency) {
      var change = formatter.format((currentValue - previousValue) / previousValue,
          {
            type: 'percent',
            dps: 2,
            pad: true,
            showSigns: true
          }
      );
      var trend;

      if (currentValue > previousValue) {
        trend = 'increase';
      } else if (currentValue < previousValue) {
        trend = 'decrease';
      } else {
        trend = 'no-change';
      }

      dataItem.formatted_change_from_previous = {
        change: change,
        trend: trend
      };
    }

    //formatted_value
    if (currentValue) {
      dataItem.formatted_value = formatter.format(currentValue, formating);
    } else if (currentValue === null) {
      dataItem.formatted_value = 'no data';
    }

    //formatted_start_at
    if (dataItem['_timestamp']) {
      dataItem.formatted_start_at = formatter.format(dataItem['_timestamp'], 'date');
    }

    //formatted_end_at
    if (dataItem['end_at']) {
      dataItem.formatted_end_at = formatter.format(dataItem['end_at'], 'date');
    }

    //formatted_date_range
    if (dataItem['_timestamp'] && dataItem['end_at']) {
      var range = [dataItem['_timestamp'], dataItem['end_at']];
      dataItem.formatted_date_range = formatter.format(range, 'date');
    }
  }

  return module;
}

function tabularData (module) {
  var data = module.data;
  var axes = module.axes;

  var cols = [];
  var xCol = [axes.x.label];

  xCol = loopAndReturnFromKey(data, xCol, axes.x.key);
  cols.push(xCol);

  _.each(axes.y, function (yAxis) {
    var yCol = [yAxis.label];

    yCol = loopAndReturnFromKey(data, yCol, yAxis.key);

    cols.push(yCol);
  });

  function loopAndReturnFromKey (data, axis, key) {
    _.each(data, function (dataEntry) {
      axis.push(dataEntry[key]);
    });

    return axis;
  }

  return cols;
}

function getModuleAxes (module) {
  var type = module['module-type'];

  if (type === 'kpi') {
    return {
      'x': {
        'label': 'Quarter',
        'key': '_quarter_start_at',
        'format': 'date'
      },
      'y': [
        {
          'label': module.title,
          'key': module['value-attribute'],
          'format': module.format.type
        }
      ]
    };
  }

}

module.exports = Dashboard;
<commit_msg>If the y axis isNumberorCurrency then process a delta.<commit_after>var rp = require('./request-promise'),
    config = require('../config'),
    _ = require('underscore'),
    Q = require('q'),
    formatter = require('./utils/formatter');

function Dashboard (slug) {
  this.options = {
    json: true,
    slug: slug
  };
}

Dashboard.prototype.getConfig = function () {
  var options = _.extend(this.options, {
    url: config.stagecraft + 'public/dashboards?slug=' + this.options.slug
  });

  return rp(options);
};

Dashboard.prototype.getDashboardMetrics = function () {
  var moduleList = [];
  var supportedModules = ['kpi', 'single_timeseries'];
  return this.getConfig()
    .then(_.bind(function (dashboard) {
      this.dashboard = dashboard;
      _.each(dashboard.modules, function (module) {
        if (_.contains(supportedModules, module['module-type'])) {
          moduleList.push(this.getModule(module));
        }
      }, this);

      return Q.allSettled(moduleList);
    }, this))
      .then(_.bind(function (results) {
        var dashboardAndMetrics = _.extend({}, this.dashboard);
        dashboardAndMetrics.modules = [];

        _.each(results, function (result) {
          if (result.state === 'fulfilled') {
            dashboardAndMetrics.modules.push(result.value);
          }
        }, this);

        return dashboardAndMetrics;
      }, this));
};

Dashboard.prototype.getModule = function (module) {
  var dataSource = module['data-source'];
  var options = _.extend(this.options, {
    url: config.backdrop + 'data/' + dataSource['data-group'] + '/' + dataSource['data-type'],
    qs: _.extend(dataSource['query-params'], {
      flatten: true
    })
  });

  return rp(options)
    .then(function (data) {
      module.data = data.data;
      module.axes = module.axes || getModuleAxes(module);
      module = formatKeys(module);
      module.tabularData = tabularData(module);
      return module;
    });
};

function formatKeys (module) {
  var dataList = module.data;
  var formating = module.format;
  var valueAttr = module['value-attribute'];
  var yAxes = module.axes.y;
  var isNumberOrCurrency = _.some(yAxes, function (y) {
    return y.format  === 'number' || y.format === 'currency';
  });

  for (var x = 0; x < dataList.length; x++) {
    var dataItem = dataList[x];
    var currentValue = dataItem[valueAttr];
    var previousItem = dataList[x + 1] || undefined;
    var previousValue = previousItem ? previousItem[valueAttr] : undefined;

    // formatted_change_from_previous
    if (previousValue && isNumberOrCurrency) {
      var change = formatter.format((currentValue - previousValue) / previousValue,
          {
            type: 'percent',
            dps: 2,
            pad: true,
            showSigns: true
          }
      );
      var trend;

      if (currentValue > previousValue) {
        trend = 'increase';
      } else if (currentValue < previousValue) {
        trend = 'decrease';
      } else {
        trend = 'no-change';
      }

      dataItem.formatted_change_from_previous = {
        change: change,
        trend: trend
      };
    }

    //formatted_value
    if (currentValue) {
      dataItem.formatted_value = formatter.format(currentValue, formating);
    } else if (currentValue === null) {
      dataItem.formatted_value = 'no data';
    }

    //formatted_start_at
    if (dataItem['_timestamp']) {
      dataItem.formatted_start_at = formatter.format(dataItem['_timestamp'], 'date');
    }

    //formatted_end_at
    if (dataItem['end_at']) {
      dataItem.formatted_end_at = formatter.format(dataItem['end_at'], 'date');
    }

    //formatted_date_range
    if (dataItem['_timestamp'] && dataItem['end_at']) {
      var range = [dataItem['_timestamp'], dataItem['end_at']];
      dataItem.formatted_date_range = formatter.format(range, 'date');
    }
  }

  return module;
}

function tabularData (module) {
  var data = module.data;
  var axes = module.axes;

  var cols = [];
  var xCol = [axes.x.label];

  xCol = loopAndReturnFromKey(data, xCol, axes.x.key);
  cols.push(xCol);

  _.each(axes.y, function (yAxis) {
    var yCol = [yAxis.label];

    yCol = loopAndReturnFromKey(data, yCol, yAxis.key);

    cols.push(yCol);
  });

  function loopAndReturnFromKey (data, axis, key) {
    _.each(data, function (dataEntry) {
      axis.push(dataEntry[key]);
    });

    return axis;
  }

  return cols;
}

function getModuleAxes (module) {
  var type = module['module-type'];

  if (type === 'kpi') {
    return {
      'x': {
        'label': 'Quarter',
        'key': '_quarter_start_at',
        'format': 'date'
      },
      'y': [
        {
          'label': module.title,
          'key': module['value-attribute'],
          'format': module.format.type
        }
      ]
    };
  }

}

module.exports = Dashboard;
<|endoftext|>


<commit_before>var request = require('request')

var digio_api = function (token) {
  var API_URL = 'https://api.digitalocean.com/v2/'

  var digio_headers = {
    'Authorization': 'Bearer ' + token,
    'Content-Type': 'application/json'
  }

  var tools = {
    _get: function (action, callback) {
      request({
        url: API_URL + action,
        headers: digio_headers
      },
      function (err, res, body) {
        if (err) return callback(err)
        if (res.statusCode >= 400) return callback(JSON.parse(body), body)

        callback(null, body || {})
      })
    },

    _post: function (action, body, callback) {
      request.post({
        url: API_URL + action,
        headers: digio_headers,
        body: JSON.stringify(body)
      },
      function (err, res, body) {
        if (err) return callback(err)
        if (res.statusCode >= 400) return callback(JSON.parse(body), body)

        callback(null, body || {})
      })
    },

    _delete: function (action, callback) {
      request.del({
        url: API_URL + action,
        headers: digio_headers
      },
      function (err, res, body) {
        if (err) return callback(err)
        if (res.statusCode >= 400) return callback(JSON.parse(body), body)

        callback(null, body || {})
      })
    },

    _put: function (action, body, callback) {
      request.put({
        url: API_URL + action,
        headers: digio_headers,
        body: JSON.stringify(body)
      },
      function (err, res, body) {
        if (err) return callback(err)
        if (res.statusCode >= 400) return callback(JSON.parse(body), body)

        callback(null, body || {})
      })
    }
  }

  return {
    droplets: require('./modules/droplets')(tools),
    domains: require('./modules/domains')(tools),
    domain_records: require('./modules/domain-records')(tools),
    regions: require('./modules/regions')(tools),
    sizes: require('./modules/sizes')(tools),
    keys: require('./modules/keys')(tools)
  }
}

module.exports = digio_api
<commit_msg>Register images module to API<commit_after>var request = require('request')

var digio_api = function (token) {
  var API_URL = 'https://api.digitalocean.com/v2/'

  var digio_headers = {
    'Authorization': 'Bearer ' + token,
    'Content-Type': 'application/json'
  }

  var tools = {
    _get: function (action, callback) {
      request({
        url: API_URL + action,
        headers: digio_headers
      },
      function (err, res, body) {
        if (err) return callback(err)
        if (res.statusCode >= 400) return callback(JSON.parse(body), body)

        callback(null, body || {})
      })
    },

    _post: function (action, body, callback) {
      request.post({
        url: API_URL + action,
        headers: digio_headers,
        body: JSON.stringify(body)
      },
      function (err, res, body) {
        if (err) return callback(err)
        if (res.statusCode >= 400) return callback(JSON.parse(body), body)

        callback(null, body || {})
      })
    },

    _delete: function (action, callback) {
      request.del({
        url: API_URL + action,
        headers: digio_headers
      },
      function (err, res, body) {
        if (err) return callback(err)
        if (res.statusCode >= 400) return callback(JSON.parse(body), body)

        callback(null, body || {})
      })
    },

    _put: function (action, body, callback) {
      request.put({
        url: API_URL + action,
        headers: digio_headers,
        body: JSON.stringify(body)
      },
      function (err, res, body) {
        if (err) return callback(err)
        if (res.statusCode >= 400) return callback(JSON.parse(body), body)

        callback(null, body || {})
      })
    }
  }

  return {
    droplets: require('./modules/droplets')(tools),
    domains: require('./modules/domains')(tools),
    domain_records: require('./modules/domain-records')(tools),
    regions: require('./modules/regions')(tools),
    sizes: require('./modules/sizes')(tools),
    keys: require('./modules/keys')(tools),
    images: require('./modules/images')(tools)
  }
}

module.exports = digio_api
<|endoftext|>


<commit_before>/*
 * Spreed Speak Freely.
 * Copyright (C) 2013-2014 struktur AG
 *
 * This file is part of Spreed Speak Freely.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */
define([
    'jquery',
    'underscore',
    'mediastream/connector',
    'mediastream/api',
    'mediastream/webrtc',
    'mediastream/tokens'

], function($, _, Connector, Api, WebRTC, tokens) {

    return ["$route", "$location", "$window", "visibility", "alertify", "$http", "safeApply", "$timeout", function($route, $location, $window, visibility, alertify, $http, safeApply, $timeout) {

        var globalcontext = $("#globalcontext").text();
        var context = JSON.parse(globalcontext);
        var url = (context.Ssl ? "wss" : "ws") + "://" + context.Host + (context.Cfg.B || "/") + "ws";
        var version = context.Cfg.Version || "unknown";
        console.log("Service version: "+version);
        console.log("Ws URL: "+ url);

        var connector = new Connector(version);
        var api = new Api(connector);
        var webrtc = new WebRTC(api);

        var td = null;
        $window.testDisconnect = function() {
            if (td) {
                $window.clearInterval(td);
                td = null;
                console.info("Stopped disconnector.");
                return;
            }
            td = $window.setInterval(function() {
                console.info("Test disconnect!");
                connector.conn.close();
            }, 10000);
            console.info("Started disconnector.");
        };

        var mediaStream = {
            version: version,
            url: url,
            config: context.Cfg,
            webrtc: webrtc,
            connector: connector,
            api: api,
            tokens: tokens,
            url: {
                room: function(id) {
                    id = $window.encodeURIComponent(id);
                    return $window.location.protocol+'//'+$window.location.host+context.Cfg.B+id;
                },
                api: function(path) {
                    return (context.Cfg.B || "/") + "api/v1/" + path;
                }
            },
            initialize: function($rootScope, translation) {

                var cont = false;
                var ready = false;

                $rootScope.version = version;
                $rootScope.roomid = null;
                $rootScope.roomlink = null;
                $rootScope.roomstatus = false;

                connector.e.on("closed error", _.bind(function(event, options) {
                    var opts = $.extend({}, options);
                    if (!opts.soft) {
                        // Do not hang up when this is a soft event.
                        webrtc.doHangup();
                    }
                }, this));

                var connect = function() {
                    if (ready && cont) {
                        // Inject connector function into scope, so that controllers can pick it up.
                        safeApply($rootScope, function(scope) {
                            scope.connect = function() {
                                connector.connect(url);
                            };
                        });
                    }
                };

                $window.changeRoom = function(room) {
                    $rootScope.$apply(function(scope) {
                        $location.path("/"+room).replace();
                    });
                };

                // Room selector.
                $rootScope.$on("$locationChangeSuccess", function(event) {
                    //console.log("location change", $route, $rootScope.roomid);
                    var defaultRoom, room;
                    room = defaultRoom = $rootScope.roomid || "";
                    if ($route.current) {
                        room = $route.current.params.room;
                    } else {
                        room = "";
                    }
                    if (!ready && room !== defaultRoom && !room) {
                        // First start.
                        $location.path("/"+defaultRoom).replace();
                        return
                    }
                    console.info("Selected room is:", [room]);
                    if (!ready || !cont) {
                        ready = true;
                        connector.roomid = room;
                        connect();
                    } else {
                        connector.room(room);
                    }
                    $rootScope.roomid = room;
                    $rootScope.roomlink = room ? mediaStream.url.room(room) : null;
                });

                // Cache events, to avoid ui flicker during quick room changes.
                var roomStatusCache = $rootScope.roomStatus;
                var roomCache = null;
                var roomCache2 = null;
                $rootScope.$on("roomStatus", function(event, status) {
                    roomStatusCache = status ? true : false;
                    roomCache = status ? $rootScope.roomid : null;
                    $timeout(function() {
                        if ($rootScope.roomstatus !== roomStatusCache) {
                            $rootScope.roomstatus = roomStatusCache;
                            console.log("set roomstsatus", roomStatusCache);
                        }
                        if (roomCache !== roomCache2) {
                            $rootScope.$broadcast("room", roomCache);
                            roomCache2 = roomCache;
                        }
                    }, 100);
                });

                visibility.afterPrerendering(function() {

                    // Hide loader when we are visible.
                    var loader = $("#loader");
                    loader.addClass("done");
                    _.delay(function() {
                        loader.remove();
                    },1000);

                    if (context.Cfg.Tokens) {
                        var storedCode = localStorage.getItem("mediastream-access-code");
                        var prompt = function() {
                            alertify.dialog.prompt(translation._("Access code required"), function(code) {
                                if (!code) {
                                    prompt();
                                } else {
                                    check(code);
                                    return;
                                }
                            }, prompt);
                        };
                        var url = mediaStream.url.api("tokens");
                        var check = function(code) {
                            $http({
                                method: "POST",
                                url: url,
                                data: $.param({
                                    a: code
                                }),
                                headers: {'Content-Type': 'application/x-www-form-urlencoded'}
                            }).
                            success(function(data, status) {
                                if (data.token !== "" && data.success) {
                                    localStorage.setItem("mediastream-access-code", code);
                                    cont = true;
                                    connect();
                                } else {
                                    alertify.dialog.error(translation._("Access denied"), translation._("Please provide a valid access code."), function() {
                                        prompt();
                                    });
                                }
                            }).
                            error(function() {
                                alertify.dialog.error(translation._("Error"), translation._("Failed to verify access code. Check your Internet connection and try again."), function() {
                                    prompt();
                                });
                            });
                        };
                        if (storedCode) {
                            check(storedCode);
                        } else {
                            prompt();
                        }
                    } else {
                        cont = true;
                        connect();
                    }

                });

            }
        };

        return mediaStream;

    }];

});
<commit_msg>Removed debug.<commit_after>/*
 * Spreed Speak Freely.
 * Copyright (C) 2013-2014 struktur AG
 *
 * This file is part of Spreed Speak Freely.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */
define([
    'jquery',
    'underscore',
    'mediastream/connector',
    'mediastream/api',
    'mediastream/webrtc',
    'mediastream/tokens'

], function($, _, Connector, Api, WebRTC, tokens) {

    return ["$route", "$location", "$window", "visibility", "alertify", "$http", "safeApply", "$timeout", function($route, $location, $window, visibility, alertify, $http, safeApply, $timeout) {

        var globalcontext = $("#globalcontext").text();
        var context = JSON.parse(globalcontext);
        var url = (context.Ssl ? "wss" : "ws") + "://" + context.Host + (context.Cfg.B || "/") + "ws";
        var version = context.Cfg.Version || "unknown";
        console.log("Service version: "+version);
        console.log("Ws URL: "+ url);

        var connector = new Connector(version);
        var api = new Api(connector);
        var webrtc = new WebRTC(api);

        var td = null;
        $window.testDisconnect = function() {
            if (td) {
                $window.clearInterval(td);
                td = null;
                console.info("Stopped disconnector.");
                return;
            }
            td = $window.setInterval(function() {
                console.info("Test disconnect!");
                connector.conn.close();
            }, 10000);
            console.info("Started disconnector.");
        };

        var mediaStream = {
            version: version,
            url: url,
            config: context.Cfg,
            webrtc: webrtc,
            connector: connector,
            api: api,
            tokens: tokens,
            url: {
                room: function(id) {
                    id = $window.encodeURIComponent(id);
                    return $window.location.protocol+'//'+$window.location.host+context.Cfg.B+id;
                },
                api: function(path) {
                    return (context.Cfg.B || "/") + "api/v1/" + path;
                }
            },
            initialize: function($rootScope, translation) {

                var cont = false;
                var ready = false;

                $rootScope.version = version;
                $rootScope.roomid = null;
                $rootScope.roomlink = null;
                $rootScope.roomstatus = false;

                connector.e.on("closed error", _.bind(function(event, options) {
                    var opts = $.extend({}, options);
                    if (!opts.soft) {
                        // Do not hang up when this is a soft event.
                        webrtc.doHangup();
                    }
                }, this));

                var connect = function() {
                    if (ready && cont) {
                        // Inject connector function into scope, so that controllers can pick it up.
                        safeApply($rootScope, function(scope) {
                            scope.connect = function() {
                                connector.connect(url);
                            };
                        });
                    }
                };

                $window.changeRoom = function(room) {
                    $rootScope.$apply(function(scope) {
                        $location.path("/"+room).replace();
                    });
                };

                // Room selector.
                $rootScope.$on("$locationChangeSuccess", function(event) {
                    //console.log("location change", $route, $rootScope.roomid);
                    var defaultRoom, room;
                    room = defaultRoom = $rootScope.roomid || "";
                    if ($route.current) {
                        room = $route.current.params.room;
                    } else {
                        room = "";
                    }
                    if (!ready && room !== defaultRoom && !room) {
                        // First start.
                        $location.path("/"+defaultRoom).replace();
                        return
                    }
                    console.info("Selected room is:", [room]);
                    if (!ready || !cont) {
                        ready = true;
                        connector.roomid = room;
                        connect();
                    } else {
                        connector.room(room);
                    }
                    $rootScope.roomid = room;
                    $rootScope.roomlink = room ? mediaStream.url.room(room) : null;
                });

                // Cache events, to avoid ui flicker during quick room changes.
                var roomStatusCache = $rootScope.roomStatus;
                var roomCache = null;
                var roomCache2 = null;
                $rootScope.$on("roomStatus", function(event, status) {
                    roomStatusCache = status ? true : false;
                    roomCache = status ? $rootScope.roomid : null;
                    $timeout(function() {
                        if ($rootScope.roomstatus !== roomStatusCache) {
                            $rootScope.roomstatus = roomStatusCache;
                        }
                        if (roomCache !== roomCache2) {
                            $rootScope.$broadcast("room", roomCache);
                            roomCache2 = roomCache;
                        }
                    }, 100);
                });

                visibility.afterPrerendering(function() {

                    // Hide loader when we are visible.
                    var loader = $("#loader");
                    loader.addClass("done");
                    _.delay(function() {
                        loader.remove();
                    },1000);

                    if (context.Cfg.Tokens) {
                        var storedCode = localStorage.getItem("mediastream-access-code");
                        var prompt = function() {
                            alertify.dialog.prompt(translation._("Access code required"), function(code) {
                                if (!code) {
                                    prompt();
                                } else {
                                    check(code);
                                    return;
                                }
                            }, prompt);
                        };
                        var url = mediaStream.url.api("tokens");
                        var check = function(code) {
                            $http({
                                method: "POST",
                                url: url,
                                data: $.param({
                                    a: code
                                }),
                                headers: {'Content-Type': 'application/x-www-form-urlencoded'}
                            }).
                            success(function(data, status) {
                                if (data.token !== "" && data.success) {
                                    localStorage.setItem("mediastream-access-code", code);
                                    cont = true;
                                    connect();
                                } else {
                                    alertify.dialog.error(translation._("Access denied"), translation._("Please provide a valid access code."), function() {
                                        prompt();
                                    });
                                }
                            }).
                            error(function() {
                                alertify.dialog.error(translation._("Error"), translation._("Failed to verify access code. Check your Internet connection and try again."), function() {
                                    prompt();
                                });
                            });
                        };
                        if (storedCode) {
                            check(storedCode);
                        } else {
                            prompt();
                        }
                    } else {
                        cont = true;
                        connect();
                    }

                });

            }
        };

        return mediaStream;

    }];

});
<|endoftext|>